{
    
      "2026-01-11-3d-game-starter-c99-raylib5-opengl3": {
        "title": "3D Game Starter – C99 OpenGL3 Raylib5 CMake (2500 FPS!)",
        "author": "",
        "category": "",
        "tags": "gamedev, c, opengl, raylib, cmake",
        "content": "2024’s small template to start your raylib game. Featuring 3D, C 2017, Raylib 5.0, OpenGL 3 and a modular architecture.Content  Dependencies  Screenshots  Features  Install  Usage  Assets  Release  ResourcesDependencies  C++ 2020 / C 2017  RayLib 5.0  OpenGL 3.30  CMake v3.28.3  Visual Studio 2022 MVSScreenshotsNote: Captured on mid-tier PC from 2020 (GPU: RTX-2060 with 6 GB VRAM, CPU: Intel i5-9600K, RAM: 32 GB).Features  Targets:          Win64 (Windows)      Linux      SteamDeck (Windows/Linux)      HTML5 (WebAssembly)      Discord (WebAssembly)        Graphics          Render: PostProcessing Bloom, AA MSAA, Texture Filtering      Camera: ThirdPerson, Follow      Lighting: World Lighting, Player Lighting, Player Shadows      Meshes: Meshes, Textures, Shaders, Materials,   [ ] Texture tiling      Sky: Color, Cubemap, Fog        World          Physics  [ ] hitbox  [ ] gravity      Simulation: Tick Systems        Scripting          Console        Animation          Character        Input          UI: lauch screen, settings menu      Input: Keyboard, Arrows, Gamepad      Control: [x] Tank control, [ ] Third Person        Other          launching screen      Repository layout:├── assets│   └── images│   └── ...├── docs├── infra├── lib│   ├── raylib-5.0_win64_msvc16│   ├── winmm-10-win64├── platform│   ├── engine│   └── game├── standalone│   ├── desktop_win64└── tools    └── blender    └── ciInstallWindowsCMake:  Download the v3.28.3 release of CMake at http://www.cmake.org/download/.  Pick Windows (Windows x64 Installer).  Run the installer  When asked for, select Add CMake to the system PATH for all users.  Run software installation…Visual Studio:  Download the Community version of Visual Studio 2022 release of Visual Studio at https://visualstudio.microsoft.com/downloads/  Run the installer…  Run software Visual Studio Installer  When asked for, click on modify under Visual Studio 2002  Select Desktop development with C++ (contains MVC package)  Click on modifyPowerShell:cmake -S \".\" -B \"build\" -G \"Visual Studio 17 2022\"UsageCLI (pure CMake)  Pros: basic, no Editor, CI friendly.  Cons: manual actions intensive..\\tools\\ci\\install.bat.\\tools\\ci\\dev.bat# OR.\\tools\\ci\\release.batVisualStudio 2022 (IDE)  Pros: better integration, 1 step compile+debug.  Cons: very laggy UI, bad search tools..\\tools\\ci\\install.batVSCode  Pros: better code editor, lightweight.  Cons: 2 steps compile+debug.\\tools\\ci\\install.bat.\\tools\\ci\\watch.batRun (press Ctrl+F5, or Menu &gt; “Run” &gt; “Run without Debugging”)Debug (press F5, or Menu &gt; “Run” &gt; “Start Debugging”)AssetsPipelineInstallation:  Download io_scene_m3d.py  Start Blender  Go to menu, “Edit” &gt; “Preferences…” &gt; “Add-ons” tab &gt; “Install…” button  Browse and double click on the downloaded file  On the “Add-ons” tab, search for “m3d”  Click on “Enable Add-on.”  Now in the menu, “File” &gt; “Export” &gt; “Model 3D (.m3d)” (and eventually “File” &gt; “Import” &gt; “Model 3D (.m3d)”) should appearGet 3D Models:  Start WebBrowser…  https://www.mixamo.com  Click Characters  search “X bot”  Click Download  Check Format: fbx, pose: t-pose  Click Download  Start Blender…  Go to menu, File &gt; New &gt; General …Delete Cube  Go to menu, File &gt; Import &gt; FBX &gt; “X bot.fbx”  Click on the “Texture Paint” tab &gt; click “new” &gt; type “X_bot_diffuse”  On right side panel &gt; click “material” &gt; “base color” &gt; “image texture” &gt; select “X_bot_diffuse”  Go to menu, File &gt; Export &gt; M3D &gt; scale: 2.0 &gt; “X_bot.m3d” &gt; ExportGet 3D Animations:  Start WebBrowser…  https://www.mixamo.com  Click Animations  search “Slow Run”  check “In Place” box  Click Download  Check Format: fbx, Skin: with skin  Click Download  Start Blender…  Go to menu, File &gt; New &gt; General …Delete Cube  Go to menu, File &gt; Import &gt; FBX &gt; “Slow Run.fbx”  Click on the “Animation” tab &gt; click “editor type icon” &gt; “non linear animation” (new channel editor)  click “push down action” (new channel)  Go to menu, File &gt; Export &gt; M3D &gt; scale: 2.0 &gt; “Slow Run.m3d” &gt; ExportFAQWhy Models are sometime unlit ?Cause: Blender export changes materials indexes (start with 0 or 1) and lighting shader needs to be applied to real material.  *.obj, *.iqm formats: use material[0]  *.m3d, *.glb formats: use material[1]What about performance ?Condition: GPU: RTX-2060, CPU: i5-9600K, RAM: 32 GB  Raylib (GL3) “High”: ~2500 FPS (AA 4x, Postpro Bloom)  Raylib (GL3) “Low”: ~3000 FPS  Unreal (DX12) “Low”: ~150 FPS (Settings=Low)Project HistoryRelease  Source Code (monorepo):          20260111-c99-raylib5-gl3-3dgame-starter-1.0.0-source-code        Executable (Win64):          20260111-c99-raylib5-gl3-3dgame-starter-1.0.0-desktop_win64.zip        Repository (GitHub):          c99-raylib5-gl3-3dgame-starter (GitHub)      Resources  C          ModernCppStarter        CMake          CMake with include and source paths - basic setup      CMake add_library      Specify the default startup project in a Visual Studio solution.      How To Automatically Build CMake        Monorepo          How to structure a monorepo      A monorepo template that actually works        VS Code          Configure C/C++ debugging        Raylib          raylib vs SDL - A libraries comparison      raylib-game-template      Examples GitHub      Examples Demos (HTML5)                  shaders_postprocessing          shaders_texture_tiling          shaders_basic_lighting          shaders_fog          text_draw_3d          textures_image_processing                    how to properly setup raylib app to talk to glsl shaders      WASM                  Working for Web (HTML5)          Creating Discord Activities with raylib                    Shadow                  c99-raylib-shadowmap                      Quality          cppcheck        Model3D Format          Welcome to Model 3D!      Model 3D Blender Integration      io_scene_m3d.py      IQM Export        C Libs          cJSON parser      ReferencesThere are several games made with raylib to highlight:  Hare136: https://play.google.com/store/apps/details?id=games.haremonic.slider  SideStep Legends: https://store.steampowered.com/app/2077590/Sidestep_Legends/  Pure Logic: https://store.steampowered.com/app/1861500/Pure_Logic/There are also many small games (and tools) made with raylib on itchio: https://itch.io/c/380928/made-with-raylib",
        "url": "/2026/01/11/3d-game-starter-c99-raylib5-opengl3"
      },
    
      "2022-03-01-cars2048-open-source-release": {
        "title": "My Mobile Game Cars-2048 Is Open-Source Now!",
        "author": "",
        "category": "",
        "tags": "gamedev, unity3d, git",
        "content": "Hi everyone,This is the complete source code for my game Cars2048 (Android, 2017, Unity3D)Check it out here :      Unity project on GitHub        Photoshop and Blender assets on GitHub  The primary intent of this release is for entertainment and educational purposes.Have fun !StoreGooglePlay/Android : Cars 2048 - Puzzle GameScreenshots",
        "url": "/2022/03/01/cars2048-open-source-release"
      },
    
      "2022-02-20-my-blog-is-turning-10-years-old-today": {
        "title": "My blog is turning 10 years old today!",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Today (20 February 2022) is a very meaningful and historic day for me as it marks the 10th anniversary of my blog here. A decade has gone since I browse through the web looking for a platform for blogging and then decided to join WordPress after Blogger.What I’ve Learned ?This blog helped me a lot in my job. Motivate myself to learn on my own, then sharing knowledge with others.What’s Next ?More products and less blogging!Last wordLast but not least, Happy 10th Birthday to my blog once again!Thank you all.",
        "url": "/2022/02/20/my-blog-is-turning-10-years-old-today"
      },
    
      "2021-02-18-test-driven-development-tdd-in-java-helloworld-examples": {
        "title": "How-to JUnit: Test Driven Development / TDD In Java (Step by step with Helloworld Examples)",
        "author": "",
        "category": "",
        "tags": "java, junit, spring, tdd, test",
        "content": "Test-driven development is not about testing. Test-driven development is about development (and design), specifically improving the quality and design of code. The resulting unit tests are just an extremely useful by-product.TDD life-cycleBefore explaining best practices, it is important to understand the TDD life-cycle.  Write the test  Run the test (there is no implementation code, test does not pass)  Write just enough implementation code to make the test pass  Run all tests (tests pass)  Refactor  RepeatResultHelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit5Parent;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)public class HelloWorld6FinalTest extends JUnit5Parent {    @Test    void print_Hello_World_by_default() {        String expected = \"Hello, World!!\";        HelloWorld6Final.main(null);        Assertions.assertEquals(expected, getOutput());    }    @DisplayName(\"print Hello with parameter (expected, parameter)\")    @ParameterizedTest    @CsvSource({            \"'Hello, Damien!', Damien\",            \"'Hello, Jane!', Jane\",            \"'Hello, John!', John\",    })    void print_Hello_with_parameter(String expected, String parameter) {        String[] args = {parameter};        HelloWorld6Final.main(args);        Assertions.assertEquals(expected, getOutput());    }    @DisplayName(\"exception bad format (description, expected, parameter)\")    @ParameterizedTest    @CsvSource({            \"Param is empty,  bad arg (ex: Damien), ''  \",            \"Param is blanck, bad arg (ex: Damien), ' ' \",            \"Param is null,   bad arg (ex: Damien), null\"    })    void exception_bad_format(String description, String expected, String parameter) {        String[] args = {parameter.equals(\"null\") ? null : parameter};        Exception e = Assertions.assertThrows(IllegalArgumentException.class, () -&gt; {            HelloWorld6Final.main(args);        });        Assertions.assertEquals(expected, e.getMessage());    }}SpecificationsThis tutorial will implement the following specifications.  Print “Hello, World!”  Print “Hello, !\", where  is a parameter  If parameter is not present, Print “Hello, World!”  If parameter is not null or empty, then exception “bad arg (ex: Damien)”StepsOrder is important, next step is also solution to previous step.(in Git Projet, Just follow classes named HelloWorld*Test order)  Start by developing Print \"Hello, World!\"          HelloWorldTest#print_Hello_World Complete the test      HelloWorldTest#print_Hello_World Run the test (test does not pass)      HelloWorld Write just enough implementation code to make the test pass        Repeat with Print \"Hello, &lt;MY NAME&gt;!\", where &lt;MY NAME&gt; is a parameter          HelloWorldTest#print_Hello_with_parameter Complete the test      HelloWorldTest#print_Hello_with_parameter Run the test (test does not pass)      HelloWorld Write just enough implementation code to make the test pass      HelloWorldTest#* Run all tests (tests pass)        Repeat with If parameter is not present, Print \"Hello, World!\"          HelloWorldTest#print_Hello_World_by_default Complete the test      HelloWorldTest#print_Hello_World_by_default Run the test (test does not pass)      HelloWorld Write just enough implementation code to make the test pass      HelloWorldTest#* Run all tests (tests pass)        Refactor          HelloWorldTest Migrate to JUnit5      HelloWorld Use Ternary operator for inline condition        Repeat with If parameter is not null or empty, then exception \"bad arg (ex: Damien)\"          HelloWorldTest#exception_bad_format Complete the test      HelloWorldTest#exception_bad_format Run the test (test does not pass)      HelloWorld Write just enough implementation code to make the test pass      HelloWorldTest#* Run all tests (tests pass)      Step 0 - Initial commitHelloWorld.javapackage com.damienfremont.blog;public class HelloWorld {    public static void main(String[] args) {        // TODO: NEXT: Print \"Hello, World!\"    }}Step 1Start by developing Print \"Hello, World!\"HelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit4Parent;import org.junit.Test;public class HelloWorldTest extends JUnit4Parent {    @Test    public void print_Hello_World() {        throw new IllegalStateException(\"Not yet implemented!\");        // TODO: NEXT OUTPUT: super.getOutput()    }}Run the test (test does not pass)Complete the testHelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit4Parent;import org.junit.Assert;import org.junit.Test;public class HelloWorld1Test extends JUnit4Parent {    @Test    public void print_Hello_World() {        String expected = \"Hello, World!\";        HelloWorld1.main(null);        Assert.assertEquals(expected, getOutput());    }}Run the test (test does not pass)Write just enough implementation code to make the test passHelloWorld.javapackage com.damienfremont.blog;public class HelloWorld1 {    public static void main(String[] args) {        String text = \"Hello, World!\";        System.out.println(text);    }}Step 2Repeat with Print \"Hello, &lt;MY NAME&gt;!\", where &lt;MY NAME&gt; is a parameterHelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit4Parent;import org.junit.Assert;import org.junit.Test;public class HelloWorld2Test extends JUnit4Parent {    @Test    public void print_Hello_World() {        String expected = \"Hello, World!\";        HelloWorld2.main(null);        Assert.assertEquals(expected, getOutput());    }    @Test    public void print_Hello_with_parameter() {        throw new IllegalStateException(\"Not yet implemented!\");        // TODO: NEXT: Print \"Hello, &lt;MY NAME&gt;!\", where &lt;MY NAME&gt; is a parameter    }}Complete the testHelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit4Parent;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import java.util.Arrays;import java.util.Collection;@RunWith(Parameterized.class)public class HelloWorld2Test extends JUnit4Parent {    @Parameterized.Parameters    public static Collection&lt;Object[]&gt; data() {        return Arrays.asList(new Object[][]{                {\"Hello, World!\", \"World\"},                {\"Hello, Damien!\", \"Damien\"},                {\"Hello, Jane!\", \"Jane\"},                {\"Hello, John!\", \"John\"},        });    }    private final String expected;    private final String first;    public HelloWorld2Test(String expected, String first) {        this.first = first;        this.expected = expected;    }    @Test    public void print_Hello_with_parameter() {        String[] args = {first};        HelloWorld2.main(args);        Assert.assertEquals(expected, getOutput());    }}Run the test (test does not pass)Write just enough implementation code to make the test passHelloWorld.javapackage com.damienfremont.blog;public class HelloWorld2 {    public static void main(String[] args) {        String text = args[0];        System.out.println(String.format(\"Hello, %s!\", text));    }}Step 3Repeat with If parameter is not present, Print \"Hello, World!\"HelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit4Parent;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import java.util.Arrays;import java.util.Collection;@RunWith(Parameterized.class)public class HelloWorld3Test extends JUnit4Parent {    @Parameterized.Parameters    public static Collection&lt;Object[]&gt; data() {        return Arrays.asList(new Object[][]{                {\"Hello, World!\", \"World\"},                {\"Hello, Damien!\", \"Damien\"},                {\"Hello, Jane!\", \"Jane\"},                {\"Hello, John!\", \"John\"},        });    }    private final String expected;    private final String first;    public HelloWorld3Test(String expected, String first) {        this.first = first;        this.expected = expected;    }    @Test    public void print_Hello_with_parameter() {        String[] args = {first};        HelloWorld3.main(args);        Assert.assertEquals(expected, getOutput());    }    @Test    public void print_Hello_World_by_default() {        throw new IllegalStateException(\"Not yet implemented!\");        // TODO: NEXT: If parameter is not present, Print \"Hello, World!\"    }}Complete the testHelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit4Parent;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import java.util.Arrays;import java.util.Collection;@RunWith(Parameterized.class)public class HelloWorld3Test extends JUnit4Parent {    @Parameterized.Parameters    public static Collection&lt;Object[]&gt; data() {        return Arrays.asList(new Object[][]{                {\"Hello, World!\", \"World\"},                {\"Hello, Damien!\", \"Damien\"},                {\"Hello, Jane!\", \"Jane\"},                {\"Hello, John!\", \"John\"},        });    }    private final String expected;    private final String first;    public HelloWorld3Test(String expected, String first) {        this.first = first;        this.expected = expected;    }    @Test    public void print_Hello_with_parameter() {        String[] args = {first};        HelloWorld3.main(args);        Assert.assertEquals(expected, getOutput());    }    @Test    public void print_Hello_World_by_default() {        String expected = \"Hello, World!!\";        HelloWorld4.main(null);        Assert.assertEquals(expected, getOutput());    }}Run the test (test does not pass)Write just enough implementation code to make the test passHelloWorld.javapackage com.damienfremont.blog;public class HelloWorld3 {    public static void main(String[] args) {        // TODO: NEXT: If parameter is not present, Print \"Hello, World!\"        String text = args[0];        System.out.println(String.format(\"Hello, %s!\", text));    }}Step 4Refactor from JUnit4 to JUnit5HelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit5Parent;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)public class HelloWorld5Test extends JUnit5Parent {   @Test   void print_Hello_World_by_default() {      String expected = \"Hello, World!!\";      HelloWorld5.main(null);      Assertions.assertEquals(expected, getOutput());   }   @DisplayName(\"print Hello with parameter (expected, parameter)\")   @ParameterizedTest   @CsvSource({           \"'Hello, Damien!', Damien\",           \"'Hello, Jane!', Jane\",           \"'Hello, John!', John\",   })   void print_Hello_with_parameter(String expected, String parameter) {      String[] args = {parameter};      HelloWorld5.main(args);      Assertions.assertEquals(expected, getOutput());   }}HelloWorld.javapackage com.damienfremont.blog;public class HelloWorld5 {    public static void main(String[] args) {        // TODO: NEXT: `If parameter is not null or empty, then exception \"bad arg (ex: Damien)\"`        String text = hasNoArgs(args) ? \"World!\" : args[0];        System.out.println(String.format(\"Hello, %s!\", text));    }    private static boolean hasNoArgs(String[] args) {        return args == null || (args != null &amp;&amp; args.length == 0);    }}Run all tests (tests pass)Step 5Repeat with If parameter is not null or empty, then exception \"bad arg (ex: Damien)\"HelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit5Parent;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)public class HelloWorld5Test extends JUnit5Parent {   @Test   void print_Hello_World_by_default() {      String expected = \"Hello, World!!\";      HelloWorld5.main(null);      Assertions.assertEquals(expected, getOutput());   }   @DisplayName(\"print Hello with parameter (expected, parameter)\")   @ParameterizedTest   @CsvSource({           \"'Hello, Damien!', Damien\",           \"'Hello, Jane!', Jane\",           \"'Hello, John!', John\",   })   void print_Hello_with_parameter(String expected, String parameter) {      String[] args = {parameter};      HelloWorld5.main(args);      Assertions.assertEquals(expected, getOutput());   }   @Test   void exception_bad_format() {      // TODO: NEXT: `If parameter is not null or empty, then exception \"bad arg (ex: Damien)\"`      throw new IllegalStateException(\"Not yet implemented!\");   }}Complete the testHelloWorldTest.javapackage com.damienfremont.blog;import com.damienfremont.blog.utils.JUnit5Parent;import org.junit.jupiter.api.*;import org.junit.jupiter.params.ParameterizedTest;import org.junit.jupiter.params.provider.CsvSource;@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)public class HelloWorld6FinalTest extends JUnit5Parent {    @Test    void print_Hello_World_by_default() {        String expected = \"Hello, World!!\";        HelloWorld6Final.main(null);        Assertions.assertEquals(expected, getOutput());    }    @DisplayName(\"print Hello with parameter (expected, parameter)\")    @ParameterizedTest    @CsvSource({            \"'Hello, Damien!', Damien\",            \"'Hello, Jane!', Jane\",            \"'Hello, John!', John\",    })    void print_Hello_with_parameter(String expected, String parameter) {        String[] args = {parameter};        HelloWorld6Final.main(args);        Assertions.assertEquals(expected, getOutput());    }    @DisplayName(\"exception bad format (description, expected, parameter)\")    @ParameterizedTest    @CsvSource({            \"Param is empty,  bad arg (ex: Damien), ''  \",            \"Param is blanck, bad arg (ex: Damien), ' ' \",            \"Param is null,   bad arg (ex: Damien), null\"    })    void exception_bad_format(String description, String expected, String parameter) {        String[] args = {parameter.equals(\"null\") ? null : parameter};        Exception e = Assertions.assertThrows(IllegalArgumentException.class, () -&gt; {            HelloWorld6Final.main(args);        });        Assertions.assertEquals(expected, e.getMessage());    }}Run the test (test does not pass)HelloWorld.javapackage com.damienfremont.blog;public class HelloWorld6Final {    public static void main(String[] args) {        String name = getName(args);        String text = String.format(\"Hello, %s!\", name);        System.out.println(text);    }    private static String getName(String[] args) {        if (hasNoArgs(args)) {            return \"World!\";        }        if(isNullOrEmpty(args[0])) {            throw new IllegalArgumentException(\"bad arg (ex: Damien)\");        }        return args[0];    }    private static boolean isNullOrEmpty(String arg) {        return arg == null || arg.trim().isEmpty();    }    private static boolean hasNoArgs(String[] args) {        return args == null || (args != null &amp;&amp; args.length == 0);    }}Run all tests (tests pass)And it’s finished !!!ConclusionTest-driven development is not about testing.Test-driven development is about development (and design), specifically improving the quality and design of code. The resulting unit tests are just an extremely useful by-product.Post  https://damienfremont.com/2021/02/18/test-driven-development-tdd-in-java-helloworld-examples/Source  https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20210201-test-tdd-java-helloworld-examplesReferences  https://javacodehouse.com/blog/test-driven-development-tutorial/#what-is-tdd  https://technologyconversations.com/2014/09/30/test-driven-development-tdd/  https://technologyconversations.com/2013/12/24/test-driven-development-tdd-best-practices-using-java-examples-2/",
        "url": "/2021/02/18/test-driven-development-tdd-in-java-helloworld-examples"
      },
    
      "2020-07-05-software-architecture-train-wagons-be-agile-and-prioritize-your-stack": {
        "title": "Software Architecture – “Train wagons” – Be agile and prioritize your stack",
        "author": "",
        "category": "",
        "tags": "agile, design",
        "content": "You can view an application as a train, and components as wagons. It’s possible to let go some of them if needed, like features for a project backlog. But here, instead of saving now on time or cost (implementation), you mostly save on future cost (maintenance).Content:  “Train Wagons” Metaphor  Example – Classic Full-stack Javascript Project  Step 1 – Prioritize Stack  Step 2 – Identify non-essential or non-LTS parts  Step 3 – Repeat until best-value is achievedThe “Train Wagons” MetaphorYou can view tasks in a list, as wagons attached to a train. First wagon is the most important (a must have), last wagon is the least important (nice to have).…and when you can’t make it to the end in the required budget or time, you could let go some wagons from the tail (actual benefice).It’s also possible to view an application stack, or software architecture, in the same way. The train is the application, parts of it are wagons and you can let go some wagons. But here, instead of saving on time, you save on maintenance cost (future benefice).Example – Classic Full-stack Javascript ProjectHere is a simple example, a Single Page App (SPA) using classic stack from 2019: a server running NodeJS, PostgreSQL, and also a browser like Firefox executing ReactJS, Bootstrap.It’s obvious that’s not enough to build your project. You also need third-part library to build on top of your main components, like ExpressJS for NodeJS, and tools or even a new language, like TypeScript for JavaScript.Step 1 – Prioritize StackNot all components are equals. You need to identify which depends on which (A -&gt; B -&gt; C ..to show that A is the main component, and B and C some add-ons to it)The classic way is to group them by software layers, then do the dependency graph. Usually with full-stack applications, you’ll find 2 layers (back-end server, database), up to sometimes 4 layers (+proxy, +front-end).In this diagram, there are two layers: front-end (browser) and back-end (server). It’s obvious that the front-end is kinda bloated, specifically with add-ons!Step 2 – Identify non-essential or non-LTS partsThere are multiple category for identifying non-essential parts, depending on your goals and constraints (team size, budget). Ex: boilerplate is a problem for every team, but too many tools not so much if your team is large or your environment complex.Too many tools:  SaSS, you are not FaceBook ..maybe just CSS with some overrides on Bootstrap?Overkill delivery: Docker for standard application ..maybe just Git pull or Zip transfer?Heavy boilerplate: small library, only using some functions, that you could write and maintained yourself!Constant refactoring: library without Long Term Support (LTS) or community (ex: 1 developer)Over-testing: why doing unit testing (Mocha) on front-end ? when you already do UI testing with full coverage (Selenium, Protractor)Step 3 – Repeat until best-value is achievedYou need to know when to stop.Client side: maybe your users don’t need it (simple website or business application)Tests: maybe your tests are bad (low coverage, disabled, unmaintained) or your source code is bullet-proof (generated code, simple), or site downtime is OK (non-critical app).ConclusionYou need to answer these questions: Are all components essentials ? and not just here for the hype ? Do I need a perfect clean project ? What is the future cost of each non-essential components ?Project Source  https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20200705-design-train-wagons-be-agile-and-prioritize-your-stackResources  Wikipedia          Software_architecture      MoSCoW_method      ",
        "url": "/2020/07/05/software-architecture-train-wagons-be-agile-and-prioritize-your-stack"
      },
    
      "2019-06-20-how-to-photoshop-script-translate-text-then-save-png-for-each-language": {
        "title": "How to Photoshop Script: Translate Text Then Save PNG for Each Language",
        "author": "",
        "category": "",
        "tags": "assets, javascript, photoshop, tools",
        "content": "Photoshop script to translate text layers based on language JSON files, then export project to PNG images for each language. Save a lot of time!Usage: generate screenshots files for your app (ex: Googleplay, etc).One project is converted to X languages screenshots. With the seconde script, you can also convert each group layer as a separate files (for multi-screenshots project).Getting started (one screenshot by project)  Open test photoshop file ./test/project-to-screenshot.psd  Execute text-project-translate.bat  Get your results from your Documents folderNOTE: Edit output value in text-project-translate.jsx with you want to change the target folderNOTE: Edit project-to-screenshot-fr.json or project-to-screenshot-en.json content to change translation text.NOTE: Edit same keys in Photoshop projet AND *.json files.NOTE: Use ‘Unicode’ type for universal support (asian and russian fonts).Example – Test with 1 Screenshot (project)text-project-translate.bat\"C:\\Program Files (x86)\\Photoshop\\Photoshop.exe\" c:\\Users\\damien\\git\\photoshop-script-text-translator\\text-project-translate.jsxtext-project-translate.jsx/** * Photoshop script to translate text layers based on lang * JSON file, then export project to PNG images for each * language. * * Usage: generate screenshots files for your app (ex: * Googleplay, etc). * * @param langs array of languages, linked to translation * files named like '-.json' * @param langFallback language to use when json file does * not exist. * @param (input) Current Photoshop project * @param (output) Current Photoshop project */ var langs = [\"en\", \"ja\", \"ko\", \"zh-TW\", \"de\", \"fr\", \"pt\", \"es\", \"it\", \"ru\", \"hi\"];var langFallback = \"en\";// get the path of currently opened photoshop documentvar output = app.activeDocument.path;var input = app.activeDocument.path; /* UTILS *************************************************** */ // Because Photoshop doesn'tfunction JSON_parse(fileContent) {    /// Extend script doesn't support JSON. Are you fucking kidding?    // obj = JSON.parse(file_to_read .read());    // Worry not. We got potentially harmful, yet useful, `eval` function.    var jsonFile = eval(\"(\" + fileContent + \")\");    return jsonFile;} function FILE_toString(fileToRead) {    if (fileToRead === false) {        alert(\"File read error:\" + jsonFilePath);    }    fileToRead.open('r');    var fileContent = fileToRead.read();    fileToRead.close();    return fileContent;} function loadLangFile(langKey) { } /* EXECUTION *************************************************** */ //Get the currently opened Photoshop documentvar doc = app.activeDocument; // get filename without extensionvar filename = doc.name;filename = filename.slice(0, filename.lastIndexOf(\".\")); //just add this line to the construction.       // execute for eqch languagesfor (var t = 0; t &amp;lt; langs.length; t++) {    var currentLang = langs[t];    var fileContent;     // Use absolute path for the JSON file.    var langFilePath = input + &amp;quot;/&amp;quot; + filename + &amp;quot;-&amp;quot; + currentLang + &amp;quot;.json&amp;quot;;    var fileToRead = File(langFilePath);    fileContent = FILE_toString(fileToRead);     // Use default language if file not found!    if (fileContent === &amp;quot;&amp;quot;) {        var langFilePath2 = input + &amp;quot;/&amp;quot; + filename + &amp;quot;-&amp;quot; + langFallback + &amp;quot;.json&amp;quot;;        var fileToRead2 = File(langFilePath2);        fileContent = FILE_toString(fileToRead2);    }     var messages = JSON_parse(fileContent);     // Translate each text layers and sub layers    for (var i = 0; i &lt;span id=\"mce_SELREST_start\" style=\"overflow:hidden;line-height:0;\"&gt;&lt;/span&gt;&amp;lt; doc.layers.length; i++) {        var currLayer = doc.layers[i];         // check layer is visible        if (currLayer.visible === false) {            break;        }         // check layer is text        if (currLayer.kind != LayerKind.TEXT) {            break;        }         // get translation        var translation = messages[currLayer.name];         // check translation founded        if (!translation) {            break;        }         // set new text        currLayer.textItem.contents = translation;    }     // save    var file = new File(output + &amp;quot;/&amp;quot; + filename + &amp;quot;-&amp;quot; + currentLang + &amp;quot;.png&amp;quot;);    var saveOptions = new PNGSaveOptions();    doc.saveAs(file, saveOptions, true, Extension.LOWERCASE);}Getting started (multiple screenshot layers by project)  Open test photoshop file ./test/layers-to-screenshots.psd  Execute text-layers-translate.bat  Get your results from your Documents folderExample – Test with 2 Screenshot (group)text-group-translate.bat\"C:\\Program Files (x86)\\Photoshop\\Photoshop.exe\" c:\\Users\\damien\\git\\photoshop-script-text-translator\\text-groups-translate.jsxtext-groups-translate.jsx/** * Photoshop script to translate text layers based on lang * JSON file, then export project to PNG images for each * language. * * Usage: generate screenshots files for your app (ex: * Googleplay, etc). * * @param langs array of languages, linked to translation * files named like '-.json' * @param langFallback language to use when json file does * not exist. * @param (input) Current Photoshop project * @param (output) Current Photoshop project */ var langs = [\"en\", \"ja\", \"ko\", \"zh-TW\", \"de\", \"fr\", \"pt\", \"es\", \"it\", \"ru\", \"hi\"];var langFallback = \"en\";// get the path of currently opened photoshop documentvar inputPath = app.activeDocument.path;var outputPath = app.activeDocument.path; /* UTILS *************************************************** */ // Because Photoshop doesn'tfunction JSON_parse(fileContent) {    /// Extend script doesn't support JSON. Are you fucking kidding?    // obj = JSON.parse(file_to_read .read());    // Worry not. We got potentially harmful, yet useful, `eval` function.    var jsonFile = eval(\"(\" + fileContent + \")\");    return jsonFile;} function FILE_toString(fileToRead) {    if (fileToRead === false) {        alert(\"File read error:\" + jsonFilePath);    }    fileToRead.open('r');    var fileContent = fileToRead.read();    fileToRead.close();    return fileContent;} /* EXECUTION *************************************************** */ //Get the currently opened Photoshop documentvar doc = app.activeDocument; // get filename without extensionvar filename = doc.name;filename = filename.slice(0, filename.lastIndexOf(\".\")); //just add this line to the construction.       // execute for each groupfor (var y = 0; y &amp;lt; doc.layers.length; y++) {    var currentGroup = doc.layers[y];     // check layer is visible    if (currentGroup.kind != undefined) {        break;    }     // Pass sub layers to core script    var groupLayers = currentGroup.layers;    // hide others groups    for (var t = 0; t &amp;lt; doc.layers.length; t++)        doc.layers[t].visible = false;    currentGroup.visible = true;     // execute for each languages    for (var t = 0; t &amp;lt; langs.length; t++) {        var currentLang = langs[t];        var fileContent;         // Use absolute path for the JSON file.        var langFilePath = inputPath + &amp;quot;/&amp;quot; + filename + &amp;quot;-&amp;quot; + currentLang + &amp;quot;.json&amp;quot;;        var fileToRead = File(langFilePath);        fileContent = FILE_toString(fileToRead);         // Use default language if file not found!        if (fileContent === &amp;quot;&amp;quot;) {            var langFilePath2 = inputPath + &amp;quot;/&amp;quot; + filename + &amp;quot;-&amp;quot; + langFallback + &amp;quot;.json&amp;quot;;            var fileToRead2 = File(langFilePath2);            fileContent = FILE_toString(fileToRead2);        }         var messages = JSON_parse(fileContent);         // Translate each text layers and sub layers        for (var i = 0; i &lt;span id=\"mce_SELREST_start\" style=\"overflow:hidden;line-height:0;\"&gt;&amp;#65279;&lt;/span&gt;&amp;lt; groupLayers.length; i++) {            var currLayer = groupLayers[i];             // check layer is visible            if (currLayer.visible === false) {                break;            }             // check layer is text            if (currLayer.kind != LayerKind.TEXT) {                break;            }             // get translation            var translation = messages[currLayer.name];             // check translation founded            if (!translation) {                break;            }             // set new text            currLayer.textItem.contents = translation;        }         // save        // TODO: create outputPath        var file = new File(outputPath + &amp;quot;/&amp;quot; + filename + &amp;quot;-&amp;quot; + currentLang + &amp;quot;-&amp;quot; + (y + 1) + &amp;quot;.png&amp;quot;);        var saveOptions = new PNGSaveOptions();        doc.saveAs(file, saveOptions, true, Extension.LOWERCASE);    }}Example – External Projecttext-group-translate.bat\"C:\\Program Files (x86)\\Photoshop\\Photoshop.exe\" c:\\Users\\damien\\git\\photoshop-script-text-translator\\text-groups-translate.jsxReferences  Photoshop read json file  Photoshop get layer typeSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20190620-photoshop-script-translate-text-then-export",
        "url": "/2019/06/20/how-to-photoshop-script-translate-text-then-save-png-for-each-language"
      },
    
      "2019-05-25-photoshop-script-export-layers-to-png": {
        "title": "How to Photoshop Script: Export Layers to PNG Files",
        "author": "",
        "category": "",
        "tags": "assets, javascript, photoshop, tools",
        "content": "When you don’t want to do repetitive tasks in Photoshop… This script exports root layers from your current project to separate PNG files.Usage: exporting sketchs to character animation, mock-up, code, etc.Scriptslayers-exporter.bat\"C:\\Program Files (x86)\\Photoshop\\Photoshop.exe\" %cd%\\layers-exporter.jsx`layers-exporter.jsxvar output = $.getenv(\"USERPROFILE\") + \"/Documents/\"; //Get the currently opened Photoshop documentvar doc = app.activeDocument; //Show each layer each time and save a snapshotfor (var i = 0; i &lt; doc.layers.length; i++) {   //Hide all the layers  for (var j = 0; j &lt; doc.layers.length; j++) {    doc.layers[j].visible = false;  }   // show layer  var layerIndex = i;  doc.layers[layerIndex].visible = true;  var layerName = doc.layers[layerIndex].name;  var filename = doc.name;  filename = filename.slice(0, filename.lastIndexOf(\".\")); //just add this line to the construction.   // save  var file = new File(output + filename + \"_\" + layerName + \".png\");  var saveOptions = new PNGSaveOptions();  doc.saveAs(file, saveOptions, true, Extension.LOWERCASE);}Usage  save these two scipts at the same location on your machine  Open a photoshop file with layers  Execute layers-exporter.bat, from command line or by clicking on it  Get your results from your Documents folderNOTE: edit output value in layers-exporter.jsx if you want to change the target folderNOTE: only ‘root’ layers or groups will generate files, you don’t have to worry about a million files from your project tree.ExampleSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20190525-photoshop-script-export-layers-to-png",
        "url": "/2019/05/25/photoshop-script-export-layers-to-png"
      },
    
      "2019-05-04-unity3d-reducing-apk-size-for-mobile": {
        "title": "Unity3d Reducing Apk Size For Mobile",
        "author": "",
        "category": "",
        "tags": "gamedev, android, unity3d",
        "content": "Keeping the file size of the built app to a minimum is important, especially for mobile devices or for app stores that impose a size limit.Note: this article was made using Unity 2019.1Edit (2020): use App Bundle now. Your app will be splitted in small parts for download, it’s one package for all hardware plateformes …and Google will force you into it next year anyway.Content  Don’t expect too much from Unity  Remove useless assets, models, script etc  Remove the parts of the engine you aren’t using  Use small size textures/images and compression  If you have audio, Convert songs to ogg  Enable IL2CPP native compilation  Build two separate APK1. Don’t expect too much from UnityHalf of that size is taken up by the Unity engine. You won’t be able to get it much smaller and later version of Unity are bigger !!!But no matter what you do, I doubt you’ll get a completed game smaller than ~20mb. It’s just a downside of using a game engine that has lots of features you don’t use.Example: in 7-Zip &gt; Open your APK file, wait, sort by Size …’lib’ use 10 mo, ‘assets\\bin\\Data\\Managed’ 6 mo (compressed) …so that’s 16 mo for the engine in your APK, (uncompressed to compressed size is not linear, bad with lib, good with assets)2. Remove useless assets, models, script etcIt’s common sense, but it’s easy to forget some large picture or sound files in your project.Remove any stuff you don’t need, such as scenes that are in your build but not used.Example: in WinDirStat &gt; menu:File &gt; Open Folder &gt; choose your unity3d project &gt; Ok, Wait, Navigate to Assets folder, Check your files …maybe there are some you don’t use or need.Example: in Unity3D &gt; menu: Window &gt; General &gt; Console), click the small drop-down panel in the top right, and select Open Editor Log …you’ll see only your files in uncompressed size, so it won’t be true in your APK !!! (uncompressed to compressed size is not linear, bad with DLL, good with picture file)3. Remove the parts of the engine you aren’t usingRemove the parts of the engine you arent using instead of including all of it. Like Physics, x86 Architecture, .NET 4.x.Unity supports two .NET API compatibility levels.: .NET 4.x and .NET Standard 2.0. The .NET Standard 2.0 restricts you to a smaller subset of the .NET API, which can help keep size down.Change the build to just ARM you don’t need x86. Also check out the stripping level.Example: in Unity3D &gt; Menu &gt; Build Settings &gt; (new window) &gt; Player Settings &gt; (new window) &gt; Player &gt; Settings &gt; ARMv7:true, x86:false, API Compatibility Level: NET Standard 2.04. Use small size textures/images and compressionTry reducing the sizes of your assets. Use compression on images (and reduce their resolution), reduce the bitrate of any audio, especially music.You can reduce the colour depth of images that don’t need transparency.Example: in Photoshop &gt; Menu &gt; File &gt; Save for web &gt; PNG 8, Image Size …File size is reduce from 600 ko to 40 ko !!!5. If you have audio, Convert songs to oggUse a tool to convert sound files to .ogg format.Example: http://www.the-converter.net/fr/audio &gt; ogg, 16 KHz, 32 kb/s, mono6. Enable IL2CPP native compilationInstall NDK and choose IL2CPPExample: in Unity3D &gt; Menu &gt; Build Settings &gt; (new window) &gt; Player Settings &gt; (new window) &gt; Player &gt; Settings &gt; ‘Scripting Backend’:’IL2CPP’7. Build two separate APKGoogleplay will impose ARM64. In the meantime, you’ll need to build for ARMv7 and ARM64. It’s only possible with IL2CPP activated.But ARM64, like x86, adds about 5 MO to your APK file.Example: in Unity3D &gt; Menu &gt; Build Settings &gt; (new window) &gt; Player Settings &gt; (new window) &gt; Player &gt; Settings &gt; ‘Split APK by Archi’:trueResourcesReducing the file size of your buildHow to reduce apk size?How to reduce the size of an APK file in Unity?How can we reduce apk file size in unity i made a game like flappy bird it is over 32 mb how to reduce the size .Performance tips for Unity 2d mobile",
        "url": "/2019/05/04/unity3d-reducing-apk-size-for-mobile"
      },
    
      "2018-11-24-gamedev-trello-for-project-management": {
        "title": "Gamedev Trello For Project Management",
        "author": "",
        "category": "",
        "tags": "gamedev, agile, tools",
        "content": "Do you find project management stressful? Do you struggle to keep your tasks, team members, and goals organized? Here’s how to manage your project with a simple and free tool like Trello. Whether on desktop or mobile.Staying on top of these things can be frustrating—but with the right tool, the entire process can become streamlined, efficient, and easier for everyone. The right tool will turn you into a project management master, able to get updates, reprioritize tasks, and communicate with your team on the fly.What’s the tool that will give you these project management superpowers? Trello.There are a lot of project management tools out there. But Trello stands out from the crowd with its simplicity. It provides a straightforward system for organizing and monitoring projects at a glance. It’s so simple, in fact, that you might be tempted to pass it up in favor of something that requires a week-long training course.But Trello’s simplicity is its greatest strength. Let’s take a look at how it can turn you into an organizational ace.Contents  Create a Trello account  Create a Trello Team  Create a Trello Board          Lists: categorizing your activities      Labels: categorizing your cards        Add some tasks to Board          Flow example        Install the mobile app          Share it with team members      The final board:Create a Trello accountGo to Trello’s signup and use the ‘Sign up with Google’.https://trello.com/signupCreate a Trello TeamEach one can be used by a whole company, a separate team within it, a non-work related group such as your family or friends, or just yourself. A Team unit can even represent a single complex project that has numerous sub-units.Create a new team by clicking the “+” button at the left hand side of your Trello header. Add a name, picture and people to your team, then saveCreate a Trello BoardWithin the Teams you create or join, the Board is the main working unit. It looks and feels like a whiteboard where you manage your work with sticky notes. Write new ones, move them around, and archive old ones.Boards can be used in myriad ways. They can be dedicated to the whole workflow of a particular team or separate activities within it. Alternatively, they can focus on a single project or event.From the team’s Boards tab, click “Create new board” in the Trello header directly to the left of your name, and select “Create Board.”  Set a name for your board, choose a background and a Team.  Create your first list ‘About this board’  Create your first card in it ‘What can you expect from this board?’  Add a picture to the card with ‘attachment’, then complete decription  And some other cards like ‘Release Target: 2018’ and ‘Tips for using this Board’Lists: categorizing your activitiesThe next thing in the Trello workflow is Lists. They’re the classifiers of your activities within a Board.There are numerous ways to go about using Lists. If you stick to the classical Kanban approach of Trello, your lists would hold your to-dos, in-progress tasks, and things you’ve finished. Each list can represent any way of grouping tasks that makes sense for your work. This can be their subject area, priority level, responsible person, or other classifying criteria.Use the following:  Idea  Set for Development  In Progress  DoneTipslater you can add more lists,  for each release: coping Done’s content to Shipped for v1, Shipped for v2, etcLabels: categorizing your cardsTrello labels can be used for tracking which types activities your team is spending time on.To set labels in Trello, Just open the menu and click on “Labels”. There you can give names to the default labels or create new ones – as many as you like!Use the following:  Need attention (something need to be rework before work)  Must have (core elements to your project, like gameplay)  Nice to have (optionnal elements to your project, like lootbox, skins)  Whishlist proposal (An idea that you maybe want in the Set for development list)  Hot! (it’s a bug, an issue or it’s urgent)TipsYou can also add and remove labels pressing “l” to bring up a pop-over menu of labels. Toggle an individual label by pressing numbers between 1 and 9. Individual label shortcuts are mapped below.You can use ASCII art to make icons for your labels:  /!\\ [x] [_] &lt;?&gt; ♥ …Add some tasks to BoardCards: where work gets doneThe smallest unit of work in Trello is the card. Cards are super flexible and allow you to include descriptions, attachments, subtasks or checklists, due dates and times, assignees, and labels. A card typically represents a single task in your workflow.You can upload images and files from your device, or from Google Drive, Dropbox, Box, or OneDrive. And with a simple click-and-drag, cards can be moved from one list to another.  Some cards are simple: use a name and description  Some cards are heavy: use a checklist  Some tasks have deadline: use a due date  then put a label if a type is neededTipsYou can add multiple card in a one-shot action if the text in it have multiple lines.Flow exampleStart  Create basic tasks for your project (tools install, helloworld project, brainstorming)  Do it!  Only when done, create a lot of tasks (idea1, idea 2, idea 3)  Priorize it, add a ‘whishlist’ label if neededIterate  Move 3-5 of your top ‘idea’ cards to ‘set for dev’  Do it! Experiment with it !  When Done, repeatEnd  When you hit your target for v1, copy it to a new list ‘shipped for v1’ for archive purpose (Done is now empty)  Release your game  Then restart a new versionTipsAlways finish a card before working on the next.Always start your card with a verb if it’s a task.Check checklists’ boxes to follow Card advancement.Install the mobile appThe app is available on desktop web browser or on your mobile app : use it at anytime whenever you have an idea (transport, bed, work, etc).https://trello.com/platformsShare it with team membersYou can invite others to your boards and teams by sharing a special link with them.Referenceshttps://trello.com/b/TTAVI7Ny/ue4-roadmaphttps://blog.trello.com/how-to-scrum-and-trello-for-teams-at-workhttps://help.trello.com/article/705-creating-a-new-teamhttps://help.trello.com/article/717-adding-people-to-a-board",
        "url": "/2018/11/24/gamedev-trello-for-project-management"
      },
    
      "2018-10-22-devfest-nantes-2018-retours": {
        "title": "Devfest Nantes 2018 Retours",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Nous avons pu participer pour la première fois à la conférence DevFest à Nantes le 18 octobre 2018. Dans cet article à deux mains, nous vous proposons quelques morceaux choisis sur cette expérience et ses talks/conférences.Pour rappel, DevFest est un événement présent dans plusieurs pays et villes, et très orienté technique.  -&gt; Le siteJEUDI 18 OCTOBRE - 1ER JOURLes moments forts: la keynote, les talks, les codelabs et quelques speakers de renom (ex: les GDE ‘Google Developer Expert’, David Gageot, etc).8h30 - AccueilDu monde! Du monde! Content d’être venu tôt pour être bien placé durant la conférence.Bon point pour l’organisation: le badge est aussi un planning des talks ET un plan du site. C’est beaucoup plus pratique que d’autres conférences (le palais des congrès c’est grands! et il n’y a plus besoin d’application mobile, car vous avez l’essentiel autour du cou).  -&gt; Aperçu des stands  -&gt; Sans oublier SQLI !!!9h00 - Keynote d’ouvertureUne grosse vidéo d’intro sur le thème de la conquête spatiale, suivi d’un talk.Nous avons eu la chance d’avoir un speaker expérimenté pour ce premier talk: Christian HEILMANN (lead developer at Microsoft Germany). Rien de ‘disruptif’, mais quelques piqures de rappel: les développeurs doivent se comporter en professionnels (ex: attention à la ‘hype’, se faire à l’idée qu’une application est là pour 10 ans, la dette technique doit être gérée, et nous devons construire en partant de l’existant plutôt que de réinventer constamment la même chose).  -&gt; L’intro de la keynote  -&gt; Le twitter du speakerQuelques ‘talks’ et ‘codelab’ pour la suite (présentation et travaux pratiques).11h00 - The next big thing in (client side) templatingUn talk sur le futur des templating en web (faire des vues pour nos sites et applications).Le speaker de chez Google a retracé l’histoire du templating à travers les âges du web:  ‘concat’: Au début il y avait juste des chaines de caractères assemblées …pas très maintenable, mais simple.  ‘template’: ensuite il y eu le MVC, et donc son ‘V’ pour Vue séparée du code et sa traduction en template …un peu lourd, mais durable.  ‘react’: puis vint le JSX et de nouveau le mélange entre Vue et Code …beaucoup trop lié à la librairie de facebook, mais performant.Le futur semble aller vers le style de ReactJS, mais basé sur les standards du web, les WebComponents du W3C, et donc sur ce que propose le navigateur.  ‘polymer’: librairie de Google qui permet dès aujourd’hui de coder comme pour demain. Pour résumer, en faisant du ReactJS, à la sauce ES6, donc du JavaScript, en utilisant les class ES6 et le templating ES6 à la place du JSX de ReactJS.Bilan? natif, performant, léger (&lt;1kb), futur-proof car fournit par le navigateur, meilleur pratiques de dev, pas de librairie tier.  -&gt; La présentation sur le templating ES6  -&gt; Le twitter du speakerReprise à 14h après un bon repas!14h00 - Typographie et accessibilitéUn talk à mi-chemin entre UX et Accessibilité, et un bon rappel sur la définition d’un handicap (comment rendre accessible son site ou applications, et pourquoi).Rappel: Handicap ou limite ne correspondent pas forcément à une personne handicapée, au sens légal du terme. Beaucoup de troubles, d’invalidités ou de blessures temporaires entrent dans cette définition (rappel: 80% des handicaps ne se voient pas).Derrière l’effort à fournir, en plus de la valeur légale, il y la valeur morale de pousser une solution UX vers RGAA.Les enjeux: l’accessibilité numérique est un droit depuis quelques années. Il y a deux normes WCAG (W3C), RGAA (France) pour l’implémenter. Ces deux normes sont des méthodologies, non des outils. Elles ne fournissent pas de solutions, mais des critères pour vous aider à valider votre site. En France nous avons RGAA avec trois niveaux. Soit ‘A’: accessible, ‘AA’: confort (minimum légal), ‘AAA’ facultatif: handicap mental ou cognitif.Concernant la typographie, il y a deux points d’attention:  VISU: visuelle, malvoyant, couleurs, contrastes  DYS: dyslexie, lecture, gestes, chiffres, mémoireLes préconisations: reposer sur ce que fait la plateforme (navigateur) plutôt que votre code (JavaScript et widgets), afin de ne pas tout ‘casser’ quand l’utilisateur à un zoom, une navigation ou un écran différent. Utiliser la taille de police pour hiérarchiser le contenu. Toujours définir les tailles en unité ‘em’ (unité relative), que ce soit pour les polices, les interlignes ou les inter-paragraphes. La largeur de police en ‘ch’. Les polices ‘web-safe’ classiques (‘verdana’, ‘arial’, ‘tahoma’, ‘trebuchet’). Voir même laisser l’utilisateur personnaliser son expérience, via les polices, le contraste, le thème. Des outils automatisés existent pour détecter les erreurs flagrantes.  -&gt; La présentation sur la Typographie et accessibilité  -&gt; Le twitter du speaker15h00 - L’infrastructure as code avec TerraformUn talk sur la nouvelle orientation de Terraform, qui passe de gestion d’infrastructure vers la gestion de ‘providers’ fournissant des APIs (Graphana, Cubernetis, base de données, outils), et donc une solution d’Infrastructure-As-Code.Il propose une compatibilité accrue par rapport à ses concurrents: beaucoup de ‘providers’ pour Terraform sont maintenus par le produits tiers eux-mêmes (ex: produits Google). Et introduit son propre vocabulaire: topologie (‘topology’) des ressources (‘provider)’ qui ont des états (‘state’). En se basant autour d’un langage maison (malheureusement), le HCL, mais facile à lire et à générer par les outils (Ansible, utilise le YML, un langage standardisé lui).Ses points forts:  provider-specific: Le code écrit est spécifique aux ressources. ex: un programme écrit pour un cloud Google ne fonctionnera pas sur un cloud Amazon.  cloud-agnostic: Le workflow autour est générique. ex: la gestion de l’infra (‘topoly’) d’une infra sera la même que cela soit sur un cloud Amazon ou Google.TerraForm introduit de la gestion d’état dans Infrastructure-As-Code (contrairement à Ansible, qui ne gère que des script/code et des ressources). L’avantage est sur la modification de l’infrastructure. Par exemple: si une personne modifie manuellement une ressource (une VM), Terraform le détectera et jouera la partie de code concernant cette partie de l’infra, et seulement elle. Il profite également de modules via HTTP ou GitHub ou S3.Conclusion: par rapport à Ansible, il y a plus de complexité introduite (via le code et la gestion d’états), mais maintenable et réactive (moins monolithique). Ansible est plus simple et rappel le python pour les Ops, mais il est difficile de rendre la solution modulaire. Terraform à essayer donc, mais quelques questions sur l’avenir du produit, notamment sa compatibilité à long terme avec les clouds et l’évolution de son langage.  -&gt; Le twitter du speaker16h00 - A la découverte des algorithmes génétiquesUn codelab cette fois (travaux pratiques sur deux heures) autour des algorithmes génétiques.Une expérience un peu rude, car limitée dans le temps sur un sujet qui m’était inconnu: Il fallait résoudre un problème, très rapidement présenté, en étant par équipe, le tout en compétition, en seulement une heure, en installant son poste! Heureusement, après 20min d’égarement, nous avons compris quel était le sujet, et tout est rentré dans l’ordre.Ce que j’en ai ressorti: quand il est question de machine-learning, nous y associons souvent les réseaux de neurones et des jeux de données massifs pour l’apprentissage. Ici le but est le même: la machine doit apprendre seule, mais plutôt que de renforcer des réseaux de neurones, nous allons soumettre des solutions aléatoires à la ‘sélection’ naturelle (comprendre: les moins bonnes solutions disparaissent), puis y ajouter une touche d’aléatoire (‘mutation’) pour éviter les impasses, jusqu’à obtenir un candidat adapté au problème (‘fit’).En somme, du Darwinisme (algorithmes génétiques), plutôt que de l’apprentissage spécialisé (réseau de neurones).Bilan: petit plaisir coupable, mon équipe (en violet ci-dessous) s’en est bien sortie, malgré un algo trop aléatoire …la nature fait bien les choses (le but était de produire une voiture qui roulait, testé dans un simulateur web).  -&gt; Le starter du codelab sur algorithmes génétiques  -&gt; Le twitter du speaker  -&gt; Un peu de littérature pour comprendreEt enfin quelques ‘quickies’ pour finir (talks courts et moins poussés).BILANUne conférence sympa, du choix entre les sujets (web, IoT, mobile, etc), pour tous les niveaux et dans tous les formats (talk, codelab). Mais, des salles un peu surchargées et quelques soucis pour la retransmission des talks dans les salles annexes.  -&gt; Retrouver tout les moments forts sur le twitter du DevFest NantesPRESENTATIONJustine POEZEVARAjpoezevara@sqli.comDamien FREMONTExpert technique SQLIEn mission au Ministère des Affaires Etrangères, Nanteshttps://twitter.com/Damien_Fremontdfremont@sqli.com",
        "url": "/2018/10/22/devfest-nantes-2018-retours"
      },
    
      "2018-05-27-gamedev-tools-to-share-your-work": {
        "title": "Gamedev Tools To Share Your Work",
        "author": "",
        "category": "",
        "tags": "gamedev, tools",
        "content": "What tools and techniques do you use to record and share your work? Along with any tips, tutorials, costs, downloads, or social media concerns you might deal with? (Using only free tools)When developing video games or any visual application, we often find ourselves needing skills or tools that we didn’t first consider. And because it can be so easy to get wrapped up in what WE can see (our code, our assets, our game design), we’ll often ignore what others can see, (footage, screen captures, gifs). Which can be quite harmful if you’re trying to drum up support for your latest project. Because saying that you’re working on a game is good, but showing that you are is always better.Content  GadwinPrintScreen for screenshot with cursor  ScreenToGif for animated GIF  FlashIntegro for video (short or edited)  LibreOffice-Presentation for marketing stuff  ….then Buffer to schedule and share all this content on Twitter, Facebokk &amp; Instagram, with tags like #MobileGame #IndieGame #GameDev #Puzzle #Game #Screenshot #Android #GooglePlayGadwinPrintScreen for screenshot with cursorDownload it at https://www.gadwin.com/printscreen/You need to configure it with :  Preferences &gt; Show widget : off  Image &gt; Capture Mouse cursor: on, Cursor file : on  Post capture actions &gt; Save Capture to file : on, Copy to clipboardThen use it zone-capture mode with :  press Ctrl+Impr  select capture-zone  press Enter to confirm selection  …repeat or get your file in User/Pictures/MyScreenshotsScreenToGif for animated GIFYou need to use it zone-capture mode by :  download it at http://www.screentogif.com/  start ScreenToGif app          click Record &gt; select zone &gt; click record or F7      …do your demo      click stop or F8        …wait for editor to start          Image &gt; Resize &gt; select a smaller resolution height like ‘720p or 480p’ -&gt; Apply      select non-relevant beginning frames &gt; click Supprt &gt; confirm      select non-relevant ending frames &gt; click Supprt &gt; confirm      test it with Playback &gt; Play      File &gt; Save as &gt; Save      FlashIntegro for video (short or edited)You need to use it zone-capture mode, editing mode, then compression :  download it at http://www.videosoftdev.com/  start VSDC Screen Recorder          click Start      select capture zone &gt; click record button or F5      …do your demo      click stop or Maj+F5      quit app        start VSDC Video Editor          import video      delete before part                  move cursor to the real video start (after trash frames)          click split          delete start chunk                    delete end part                  move cursor to the real video end (before trash frames)          click split          delete end chunk                    move middle chunk to timeline start      preview the final result      export menu                  click youtube          click export          click continue on popup          …wait for it          get file from User/Videos folder                    LibreOffice-Presentation for marketing stuffYou must install LibreOffice, then make a simple presentation:  start Libre Office Impress  create presentation &gt; empty template  Insert &gt; Images          select in explorer      resize it        select image group          Aligne &gt; horizontaly spacing      Align &gt; top        Insert text with bold, size  Edit background color  Export to *.png without transparencyBuffer to schedule and share all this contentYou must link socials account, write a post, then scheduling it:  Configure Buffer          create Buffer account at https://buffer.com/app/      authorize 1-3 social accounts (Twitter, Facebook, LinkedIn)        Edit a post          Click on ‘What do you want to share?’      write a title, description, link, tags      add image        Schedule social network          Click ‘Customize for each network’      Click ‘Add to queue’        …wait tomorrow for post, or click ‘share now’ConclusionYou can easily capture and share your work for pretty much to nothing (screenshots, videos, presentations to Twitter of Facebook).",
        "url": "/2018/05/27/gamedev-tools-to-share-your-work"
      },
    
      "2017-12-07-js-node-express-rest-api": {
        "title": "Js Node Express Rest Api",
        "author": "",
        "category": "",
        "tags": "expressjs, javascript, nodejs",
        "content": "Express has support for REST API. This example is inspired by SpringBoot’s Data/REST generated API, with auto-doc. Here’s how.Steps  Source  Install  Start  TestSource  userListRoutes.js: contains route associated with impl (controllers), and simple doc at the API root route.  userListModel.js: actual service/resource implementation, call data layer (service/repository/dao)  userListModel.js:  repository + datas (mock here)userListRoutes.js'use strict';var express = require('express'),  userList = require('./userListController'); var api = express.Router(); // DOCvar infos = function (req, res) {  var json = {    _links: {      users: {        href: \"http://localhost:3000/api/users\"      }    }  };  res.send(json);};api.get('/', infos); // APIapi.get('/users', userList.list_all_users);api.post('/users', userList.create_a_user);api.get('/users/:userId', userList.read_a_user);api.put('/users/:userId', userList.update_a_user);api.delete('/users/:userId', userList.delete_a_user); module.exports = api;userListController.js'use strict';var Users = require('./userListModel'); // READ ALLexports.list_all_users = function (req, res) {  Users.find({}, function (err, user) {    if (err)      res.status(500).send(err);    res.json(user);  });}; // CREATEexports.create_a_user = function (req, res) {  Users.save(req.body, function (err, user) {    if (err)      res.status(400).send(err);    res.json(user);  });}; // READ (ONE)exports.read_a_user = function (req, res) {  Users.findById(req.params.userId, function (err, user) {    if (err)      res.status(400).send(err);    res.json(user);  });}; // UPDATEexports.update_a_user = function (req, res) {  Users.save(req.body, function (err, user) {    if (err)      res.status(400).send(err);    res.json(user);  });}; // DELETEexports.delete_a_user = function (req, res) {  Users.remove(req.params.userId, function (err, user) {    if (err)      res.status(400).send(err);    res.json({ message: 'User successfully deleted' });  });};userListModel.js'use strict'; // DUMMY DATA / MOCKvar userData = {  \"total\": 3,  \"users\": [    {      \"id\": \"1\",      \"username\": \"user1\",      \"role\": \"ADMIN\",      \"status\": \"ACTIVE\"    },    {      \"id\": \"2\",      \"username\": \"user2\",      \"role\": \"USER\",      \"status\": \"ACTIVE\"    },    {      \"id\": \"3\",      \"username\": \"user3\",      \"role\": \"USER\",      \"status\": \"DISABLED\"    }  ]}; // READ ALLexports.find = function (req, callback) {  var error = null;  var response = userData;  callback(error, response);}; // READ (ONE)exports.findById = function (userId, callback) {  var error = null;  var response = null;  var actualUser = userData.users.find(x =&gt; x.id === userId);  if (!actualUser)    error = { \"message\": \"user not found\" };  else    response = actualUser;  callback(error, response);}; // DELETEexports.remove = function (userId, callback) {  var error = null;  var actualUser = userData.users.find(x =&gt; x.id === userId);  if (!actualUser) {    error = { \"message\": \"user not found\" };  } else {    var response = actualUser;    var i = userData.users.indexOf(actualUser);    userData.users.splice(i, 1);    userData.total = userData.users.length;  };  callback(error, response);}; // CREATE OR UPDATEexports.save = function (user, callback) {  var error = null;  var response;  var userId = user.id;  if (!userId) {    var newUser = user;    var generatedId = Math.floor(Math.random() * 6) + 1;    newUser.id = generatedId;    userData.users.push(newUser);    userData.total = userData.users.length;    response = newUser;  } else {    var actualUser = userData.users.find(x =&gt; x.id === userId);    if (!actualUser)      error = { \"message\": \"user not found\" };    else {      actualUser.username = user.username;      actualUser.role = user.role;      actualUser.status = user.status;      response = actualUser;    }  }  callback(error, response);};server.jsvar express = require('express'),    app = express(),    port = process.env.PORT || 3000,    bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({ extended: true }));app.use(bodyParser.json()); // APIapp.use('/api', require('./api/userListRoutes')); // DOCapp.get('/', function (req, res) {    res.send('Hello from root route. (please use /api)');}); app.listen(port); console.log('user list RESTful API server started on: ' + port);package.json{    \"author\": \"Damien FREMONT\",    \"name\": \"js-node-express-rest-api\",    \"version\": \"2017.12.07\",    \"main\": \"index.js\",    \"scripts\": {        \"start\": \"nodemon server.js\"    },    \"devDependencies\": {        \"nodemon\": \"1.12.4\"    },    \"dependencies\": {        \"body-parser\": \"1.18.2\",        \"express\": \"4.16.2\"    }}InstallStart VSC -&gt; View -&gt; Terminal -&gt; “npm install”StartTerminal -&gt; “npm start”TestStart FireFox / Chrome -&gt; type “localhost:3000” -&gt; “localhost:3000/api” -&gt; “localhost:3000/users” -&gt; GET “localhost:3000/users”  -&gt; POST -&gt; etc…Referenceshttps://spring.io/guides/gs/accessing-data-rest/https://spring.io/guides/gs/accessing-data-rest/https://github.com/expressjs/express/tree/master/exampleshttps://github.com/expressjs/express/tree/master/examplesSource on Githubhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171207-js-node-express-rest-apihttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171207-js-node-express-rest-apiPost on Wordpresshttps://damienfremont.com/2017/12/07/howto-js-node-express-rest-api/",
        "url": "/2017/12/07/js-node-express-rest-api"
      },
    
      "2017-12-06-howto-js-node-debug-visual-studio-code": {
        "title": "Howto Js Node Debug Visual Studio Code",
        "author": "",
        "category": "",
        "tags": "expressjs, javascript, nodejs, tools",
        "content": "Visual Studio Code has support for JavaScript and out-of-the-box Node.js debugging. Here’s how.Steps  open project  install  start  stop  debug mode start  debug code  debug mode stopOpen projectStart VSC -&gt; File -&gt; Open Folder -&gt; Select FolderInstallView -&gt; Integrated Terminal -&gt; “npm install”StartIntegrated Terminal -&gt; “npm start”Start Chrome -&gt; type “localhost:3000”StopIntegrated Terminal -&gt; Ctrl+C  -&gt; “Y”+ReturnDebug Mode StartDebug Icon -&gt; Settings -&gt; NodeJS -&gt; launch.json -&gt; Save -&gt; Debug Start Iconlaunch.json{    \"version\": \"0.2.0\",    \"configurations\": [        {            \"type\": \"node\",            \"request\": \"launch\",            \"name\": \"Launch Program\",            \"program\": \"${workspaceFolder}/server.js\"        }    ]}Debug CodeExplorer Icon -&gt; server.js -&gt; add breakpoitn by double-clicking on line 7Open Browser -&gt; refresh (F5)Open VSC -&gt; Hover on source vars &amp; params -&gt; press Debug Continue Icon (F5)Debug Mode StopDebug Stop IconSource on GitHubhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171206-js-node-debug-visualstudiocodehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171206-js-node-debug-visualstudiocodeReferenceshttps://code.visualstudio.com/docs/nodejs/nodejs-tutorialhttps://code.visualstudio.com/docs/nodejs/nodejs-tutorialOriginhttps://damienfremont.com/2017/12/06/howto-js-node-debug-visual-studio-code/",
        "url": "/2017/12/06/howto-js-node-debug-visual-studio-code"
      },
    
      "2017-11-24-howto-eclipse-fix-autoimport-for-list-map": {
        "title": "Howto Eclipse Fix Autoimport For List Map",
        "author": "",
        "category": "",
        "tags": "java, quicktip, tools",
        "content": "When you let your Eclipse IDE auto-organize your List/Map imports, it struggles with it and break …it’s a loss of productivity on every single file ! (ex: duplicate classes like List: java.awt.List, java.util.List and Map)The Problem‘Source -&gt; Organize imports ‘ is not working for List or Map, an ask for user resolution (you), for each file ! But in Java, we only need java.util.List and java.util.Map. And these classes are massively used in Java projects.Steps  import Eclipse preference  or  set Eclipse preferenceImport Eclipse preferenceFile -&gt; Import -&gt; Preferences -&gt; Browse -&gt; (choose file ‘eclipse-pref-autoimport.epf’) -&gt; Finish (…then check it : Window -&gt; Preferences -&gt; Java -&gt; Appearance -&gt; Type Filters )Eclipse Preference File ContentDownload here :https://raw.githubusercontent.com/DamienFremont/blog/master/20171124-eclipse-ide-fix-autoimport-config/eclipse-pref-autoimport.epfhttps://raw.githubusercontent.com/DamienFremont/blog/master/20171124-eclipse-ide-fix-autoimport-config/eclipse-pref-autoimport.epfeclipse-pref-autoimport.epf#Fri Nov 24 13:10:54 CET 2017/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.typefilter.enabled=antlr.collections.*;COM.*;com.ibm.*;com.sun.*;java.awt.*;org.hibernate.mapping.List;org.omg.*;sun.*;@org.eclipse.jdt.ui=3.13.50.v20170929-1653file_export_version=3.0Stepscheck itSet Eclipse preferenceWindow -&gt; Preferences -&gt; Java -&gt; Appearance -&gt; Type Filters -&gt; Add (N times, like ‘java.awt.*’, ‘antlr’)Eclipse Preference Filtersantlr.collection.*COM.*com.ibm.*com.sun.*java.awt.*org.hibernate.mapping.Listorg.omg.*sun.*StepsReferenceshttp://stackoverflow.com/questions/2073913/eclipse-exclude-specific-packages-when-autocompleting-a-class-namehttp://stackoverflow.com/questions/2073913/eclipse-exclude-specific-packages-when-autocompleting-a-class-nameOn GitHubhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171124-eclipse-ide-fix-autoimport-confighttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171124-eclipse-ide-fix-autoimport-configOriginhttps://damienfremont.com/2017/11/24/howto-eclipse-fix-autoimport-for-list-map/",
        "url": "/2017/11/24/howto-eclipse-fix-autoimport-for-list-map"
      },
    
      "2017-11-23-rest-api-maturity-levels-from-0-to-5": {
        "title": "RESTful API Maturity Levels - From 0 To 5",
        "author": "",
        "category": "",
        "tags": "design, rest",
        "content": "This article is about RESTful maturity. It’s not a definition of levels of REST itself, but a simple approach with examples with HTTP, Spring.Content  What’s an API ?  What’s REST?  Steps toward REST  REST API Level 0  REST API Level 1  REST API Level 2  REST API Level 3  REST API Level 4  REST API Level 5What’s an API ?“defined methods of communication between various software components”WikipediaWikipediaWhat’s REST?WebAPIREST or RESTful is not a standard, but a WebAPI  Client-Server Architecture  Stateless  Cacheability  Layered System  Uniform Interface“By using a stateless protocol and standard operations, REST systems aim for fast performance, reliability, and the ability to grow, by re-using components that can be managed and updated without affecting the system as a whole, even while it is running.”WikipediaWikipediaSteps toward RESThttps://martinfowler.com/articles/richardsonMaturityModel.htmlFirst levels are now industry standards conventions, the lasts levels are more business oriented.See more at https://martinfowler.com/articles/richardsonMaturityModel.htmlREST API Level 0Using HTTP 1.1 protocol !  Client-Server : request-response protocol  Uniform : web standard  Layered System : HTTP hide underlying technology (database, cache, file, etc)CREATE : POST /api/userREAD :   POST /api/userUPDATE : POST /api/userDELETE : POST /api/userExample : SOAP over HTTPRequestResponsehttps://www.tutorialspoint.com/soap/soap_examples.htmhttps://www.tutorialspoint.com/soap/soap_examples.htm##REST API Level 11 Resource = 1 URI (like /api/users/…).  Stateless : only 1 URI, so no state in path (no /user/creation, just /users)  Uniform: URI is universal, URI don’t changeCREATE : POST /api/users/createREAD   : GET /api/users, GET /api/user/readUPDATE : POST /api/users/updateDELETE : POST /api/users/deleteSEARCH : GET or POST /api/users?sort=nameDetails  static path : no /user and  /users and /user-new …just /users  redirection : no /users and /users/ …just /users  case insensitive :  no /User/RoleGroup …just /user/role-group  format/parameters: no /users/xml/sort-by-name …just /user?format=xml&amp;sort=nameExample : Same HTTP action for two different actions!Update RequestPOST /api/users HTTP/1.1Host api.host.com ...Delete RequestPOST /api/users-delete HTTP/1.1Host api.host.com ...##REST API Level 2Actions inside URI (like /api/users {GET, PUT, POST, DEL}) !  Uniform: using HTTP method for CRUD methods  Cacheability : cache on READ, Idempotence on ActionsCREATE : PUT /api/usersREAD   : GET /api/users/42UPDATE : POST /api/users/42DELETE : DEL /api/users/42SEARCH : GET /api/users?sort=nameDetails  no action in URL : no /users/delete or /users-delete …just DEL /users  list/array : no unique response object …just a list of IDs, then client will get datas (if not in cache) by calling resource/IDs  Cache: resources ID in response instead of data  Idempotence : actions can be applied multiple times without changing the result (ex: delete user/42 multiple time will only delete 1 row in database)Example : GitHub Single Object (Uniforme)RequestGET /users/DamienFremont HTTP/1.1Host api.github.comResponse (then cached for next usages)HTTP/1.1 200 OK {  \"login\": \"DamienFremont\",  \"id\": 123456,  \"url\": \"https://api.github.com/users/DamienFremont\",  // ...}Example : GitHub Collection (Cacheability)RequestGET /users/DamienFremont/followers HTTP/1.1Host api.github.comResponseHTTP/1.1 200 OK [ \"https://api.github.com/users/jeanmichel72\", \"https://api.github.com/users/alien42\",  // ...]instead of this (not cacheable because some parts could change over time. ex: user update)HTTP/1.1 200 OK [ { \"login\": \"jeanmichel72\", \"id\": 123456, ...}, { \"login\": \"alien42\", \"id\": 123456, ...}, // ...##REST API Level 3RESTful or HATEOAS (Hypermedia As Engine of Application State) !  Uniform : Self-descriptiveCREATE : PUT /api/users/createREAD : GET /api/users/42UPDATE : POST /api/users/42DELETE : DEL /api/users/42SEARCH : GET /api/users?sort=nameSelf-descriptive Response Body:HTTP/1.1 200 OK{  \"_embedded\" : {    \"users\" : [ {      \"username\" : \"admin\", ...      \"_links\" : {        \"self\" : { \"href\" : \"http://localhost:8080/api/users/1\" },        \"user\" : { \"href\" : \"http://localhost:8080/api/users/1\" }      }    }, {      ...    } ]  },  \"_links\" : { \"self\" : { \"href\" : \"http://localhost:8080/api/users{?page,size,sort}\", },  \"search\" : { \"href\" : \"http://localhost:8080/api/users/search\" } },  \"page\" : {    \"size\" : 20,    \"totalElements\" : 27,    \"totalPages\" : 2,    \"number\" : 0  }}Details  Self-descriptive : API index summarizes all the resources  No question nor  interpretation required about navigability, URI, URL, format  No need for documentationExample : Spring Self-descriptive Generated APISpring API Request&lt;span                data-mce-type=\"bookmark\"                id=\"mce_SELREST_start\"              data-mce-style=\"overflow:hidden;line-height:0\"              style=\"overflow:hidden;line-height:0\"           &gt;﻿&lt;/span&gt;GET /api/ HTTP/1.1Host localhost:8080Spring API ResponseHTTP/1.1 200 OK {  \"_links\" : {    \"users\" : {      \"href\" : \"http://localhost:8080/api/users{?page,size,sort}\",      \"templated\" : true    }  }}##REST API Level 4API Versionning !  Uniform : Self-descriptiveCREATE : PUT /api/users/createREAD : GET /api/users/42UPDATE : POST /api/users/42DELETE : DEL /api/users/42SEARCH : GET /api/users?sort=name...Self-descriptive Response body :{  \"_links\" : {    \"users\" : {      \"href\" : \"http://localhost:8080/api/users{?page,size,sort}\"    }  }}...Version Request URI:GET /api/v2/user.json HTTP/1.1Host api.host.comDetails:  2 solutions  Path-based approch, in which the client defines the version in URL: http://localhost:9001/api/v1/userhttp://localhost:9001/api/v2/user  Content-Type header, in which the client defines the version in Accept header: http://localhost:9001/api/v1/user with Accept: application/vnd.app-1.0+json OR application/vnd.app-2.0+jsonNote: Since i am working a lot with rest documentation tools, i prefer to use the first approach.Example : Implementation with Springimport io.swagger.annotations.*;import org.springframework.stereotype.*;import org.springframework.web.bind.annotation.*; @Controller@Api(value = \"user\", description = \"Operations about users\")public class UserController {     @ResponseBody    @RequestMapping(method = RequestMethod.GET, value = \"/api/v1/user\")    @ApiOperation(value = \"Returns user\", notes = \"Returns the user\", tags = &lt;span               data-mce-type=\"bookmark\"                id=\"mce_SELREST_start\"              data-mce-style=\"overflow:hidden;line-height:0\"              style=\"overflow:hidden;line-height:0\"           &gt;&lt;/span&gt;{\"GET\", \"User\"})    public String getUserV1() {         return \"User V1\";    }     @ResponseBody    @RequestMapping(method = RequestMethod.GET, value = \"/api/v2/user\")    @ApiOperation(value = \"Returns user\", notes = \"Returns the user\", tags = {\"GET\", \"User\"})    public String getUserV2() {         return \"User V2\";    } }Or you can duplicate/redirect to the old V1 classes.##REST API Level 5Add behaviors to API responses !CREATE : PUT /api/users/create READ : GET /api/users/42 UPDATE : POST /api/users/42 DELETE : DEL /api/users/42 SEARCH : GET /api/users?sort=name ...Self-descriptive Response body : {   \"_links\" : {     \"users\" : {       \"href\" : \"http://localhost:8080/api/users{?page,size,sort}\" } } } ...Version Request URI: GET /api/v2/user.json HTTP/1.1 Host api.host.com...Behavior in Response body HTTP/1.1 201 OK {   \"_links\" : {     \"self\" : { \"href\" : \"http://localhost:8080/api/users/1\" }}Details  user/app can discover API by using it  next actions are directly provided to client, so no need to store all static URL in client source code, and after a CREATE you can directly use the resource with the newly provided READ URLExample : User CREATE return READ/UPDATE/DELETE behavioursSpring API RequestPUT /api/user HTTP/1.1Host localhost:8080 {  \"firstname\" : \"Damien\",  \"lastname\" : \"FREMONT\"}Spring API Response, with URL and newly created IDHTTP/1.1 201 OK {  \"_links\" : {    \"self\" : { \"href\" : \"http://localhost:8080/api/users/1\" },    \"user\" : { \"href\" : \"http://localhost:8080/api/users/1\" },  }}##ConclusionREST API self-descriptive can be enhanced with tools; like Swagger for autodocumentation and Spring for implementation.SwaggerSpring REST Data generated API is a good example of RESTful, with uniform URI, discoverability via JSON response meta-data.Spring Implementationimport org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository; @Repositorypublic interface UserRepository extends JpaRepository&amp;amp;lt;User, Long&amp;amp;gt; {   User findByUsername(String username);}Spring API RequestGET /api/ HTTP/1.1Host localhost:8080Spring API ResponseHTTP/1.1 200 OK {  \"_links\" : {    \"profiles\" : {      \"href\" : \"http://localhost:8080/api/profiles{?page,size,sort}\",      \"templated\" : true    },    \"users\" : {      \"href\" : \"http://localhost:8080/api/users{?page,size,sort}\",      \"templated\" : true    }  }}Spring API RequestGET /api/users HTTP/1.1Host localhost:8080Spring API ResponseHTTP/1.1 200 OK{  \"_embedded\" : {    \"users\" : [ {      \"dateCreated\" : null,      \"lastUpdated\" : null,      \"username\" : \"admin\",      \"enabled\" : true,      \"accountNonExpired\" : true,      \"credentialsNonExpired\" : true,      \"accountNonLocked\" : true,      \"roles\" : [ ...],      \"_links\" : {        \"self\" : {          \"href\" : \"http://localhost:8080/api/users/1\"        },        \"user\" : {          \"href\" : \"http://localhost:8080/api/users/1\"        }      }    }, {      ...    } ]  },  \"_links\" : {    \"self\" : {      \"href\" : \"http://localhost:8080/api/users{?page,size,sort}\",      \"templated\" : true    },    \"profile\" : {      \"href\" : \"http://localhost:8080/api/profile/users\"    },    \"search\" : {      \"href\" : \"http://localhost:8080/api/users/search\"    }  },  \"page\" : {    \"size\" : 20,    \"totalElements\" : 27,    \"totalPages\" : 2,    \"number\" : 0  }}Referenceshttps://en.wikipedia.org/wiki/Application_programming_interfacehttps://en.wikipedia.org/wiki/Application_programming_interfacehttps://fr.wikipedia.org/wiki/Representational_state_transferhttps://fr.wikipedia.org/wiki/Representational_state_transferhttp://www.baeldung.com/rest-versioninghttp://www.baeldung.com/rest-versioninghttps://stackoverflow.com/questions/20198275/how-to-manage-rest-api-versioning-with-springhttps://stackoverflow.com/questions/20198275/how-to-manage-rest-api-versioning-with-springhttps://martinfowler.com/articles/richardsonMaturityModel.htmlhttps://martinfowler.com/articles/richardsonMaturityModel.htmlhttps://www.infoq.com/fr/presentations/bow-virginie-bardales-rest-world?utm_source=presentations_about_best-of-web&amp;utm_medium=link&amp;utm_campaign=best-of-webhttps://www.infoq.com/fr/presentations/bow-virginie-bardales-rest-world?utm_source=presentations_about_best-of-web&amp;utm_medium=link&amp;utm_campaign=best-of-webOn GitHubhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171123-rest-api-maturity-levels-from-0-to-5https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171123-rest-api-maturity-levels-from-0-to-5Originhttps://damienfremont.com/2017/11/23/rest-api-maturity-levels-from-0-to-5/",
        "url": "/2017/11/23/rest-api-maturity-levels-from-0-to-5"
      },
    
      "2017-11-19-howto-springboot-datasource": {
        "title": "Howto Springboot Datasource",
        "author": "",
        "category": "",
        "tags": "hibernate, java, spring",
        "content": "To configure your own DataSource for SpringBoot, with fully automatic initialization, semi-auto or static configuration. With various properties or a JNDI.Steps  DataSources Examples AutoConfig Semi AutoConfig Static  Common Test &amp; Entity1. DataSource AutoConfig (SpringBoot)Source CodeApplication.javapackage com.damienfremont.blog; import org.springframework.boot.*;import org.springframework.boot.autoconfigure.*; @SpringBootApplication@EnableAutoConfigurationpublic class Application {   public static void main(String[] args) {    SpringApplication.run(Application.class, args);  }}application.properties# ===================================================================# COMMON SPRING BOOT PROPERTIES# ===================================================================# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html # ----------------------------------------# DATA PROPERTIES# ---------------------------------------- # DATASOURCE (DataSourceAutoConfiguration &amp; DataSourceProperties)#spring.datasource.jndi-name=XXXspring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriverspring.datasource.url=jdbc:hsqldb:file:db/testdbspring.datasource.username=saspring.datasource.password=saConfig Key Value Referencesspring.datasource.continue-on-error=false # Do not stop if an error occurs while initializing the database.spring.datasource.data= # Data (DML) script resource references.spring.datasource.data-username= # User of the database to execute DML scripts (if different).spring.datasource.data-password= # Password of the database to execute DML scripts (if different).spring.datasource.dbcp2.*= # Commons DBCP2 specific settingsspring.datasource.driver-class-name= # Fully qualified name of the JDBC driver. Auto-detected based on the URL by default.spring.datasource.generate-unique-name=false # Generate a random datasource name.spring.datasource.hikari.*= # Hikari specific settingsspring.datasource.initialize=true # Populate the database using 'data.sql'.spring.datasource.jmx-enabled=false # Enable JMX support (if provided by the underlying pool).spring.datasource.jndi-name= # JNDI location of the datasource. Class, url, username &amp; password are ignored when set.spring.datasource.name=testdb # Name of the datasource.spring.datasource.password= # Login password of the database.spring.datasource.platform=all # Platform to use in the DDL or DML scripts (e.g. schema-${platform}.sql or data-${platform}.sql).spring.datasource.schema= # Schema (DDL) script resource references.spring.datasource.schema-username= # User of the database to execute DDL scripts (if different).spring.datasource.schema-password= # Password of the database to execute DDL scripts (if different).spring.datasource.separator=; # Statement separator in SQL initialization scripts.spring.datasource.sql-script-encoding= # SQL scripts encoding.spring.datasource.tomcat.*= # Tomcat datasource specific settingsspring.datasource.type= # Fully qualified name of the connection pool implementation to use. By default, it is auto-detected from the classpath.spring.datasource.url= # JDBC url of the database.spring.datasource.username= # Login user of the database.spring.datasource.xa.data-source-class-name= # XA datasource fully qualified name.spring.datasource.xa.properties= # Properties to pass to the XA data sourhttps://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.htmlsource: https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html2. DataSource Semi-AutoConfig (SpringBoot)Source CodeApplication.javapackage com.damienfremont.blog; import org.springframework.boot.*;import org.springframework.boot.autoconfigure.*; @SpringBootApplication( //    scanBasePackageClasses = { DataSourceConfig.class })@EnableAutoConfigurationpublic class Application {   public static void main(String[] args) {    SpringApplication.run(Application.class, args);  }}DataSourceConfig.javapackage com.damienfremont.blog; import java.sql.*;import javax.sql.*; import org.springframework.context.annotation.*;import org.springframework.boot.autoconfigure.jdbc.*;import org.springframework.boot.context.properties.*;import org.springframework.jdbc.core.*; @Configurationpublic class DataSourceConfig {   private final static String DRIVER_CLASSNAME = \"org.hsqldb.jdbc.JDBCDriver\";   @Bean  public JdbcTemplate jdbcTemplate(DataSource dataSource) {    return new JdbcTemplate(dataSource);  }   // AUTO FILL MISSING PROPERTIES BY SPRINGBOOT (USR, PASS, URL, ...)  @Bean  @ConfigurationProperties(prefix = \"datasource\")  public DataSource dataSourceProperties() throws SQLException {    return DataSourceBuilder.create() //        .driverClassName(DRIVER_CLASSNAME) //        .build();  }}application.properties# ===================================================================# COMMON SPRING BOOT PROPERTIES# ===================================================================# https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html # ----------------------------------------# DATA PROPERTIES# ---------------------------------------- # DATASOURCE (DataSourceAutoConfiguration &amp; DataSourceProperties)datasource.url=jdbc:hsqldb:file:db/testdbdatasource.username=sadatasource.password=sa&lt;span              data-mce-type=\"bookmark\"                id=\"mce_SELREST_start\"              data-mce-style=\"overflow:hidden;line-height:0\"              style=\"overflow:hidden;line-height:0\"           &gt;&lt;/span&gt;3. DataSource Static Config (SpringBoot)Source CodeApplication.javapackage com.damienfremont.blog; import org.springframework.boot.*;import org.springframework.boot.autoconfigure.*; @SpringBootApplication( //    scanBasePackageClasses = { DataSourceConfig.class })public class Application {   public static void main(String[] args) {    SpringApplication.run(Application.class, args);  }}DataSourceConfig.javapackage com.damienfremont.blog; import java.sql.*;import javax.naming.*;import javax.sql.DataSource; import org.springframework.context.annotation.*;import org.springframework.boot.autoconfigure.jdbc.*;import org.springframework.beans.factory.annotation.*;import org.springframework.jdbc.core.*; @Configurationpublic class DataSourceConfig {      // PROPERTIES  @Value(\"${datasource.jndiname:DS}\")   private String jndi;  @Value(\"${datasource.driverClassName}\")   private String driverClassName;  @Value(\"${datasource.url}\")   private String url;  @Value(\"${datasource.username}\")   private String username;  @Value(\"${datasource.password}\")   private String password;   @Bean  public DataSource dataSource() throws Exception {    DataSource ds;    try {      ds = dataSourceJNDI();    } catch (NamingException e) {      ds = dataSourceProperties();    }    return ds;  }      @Bean  public JdbcTemplate jdbcTemplate(DataSource dataSource) {    return new JdbcTemplate(dataSource);  }      DataSource dataSourceProperties() throws SQLException {    return DataSourceBuilder.create() //        .driverClassName(driverClassName) //        .url(url) //        .username(username) //        .password(password) //        .build();  }   DataSource dataSourceJNDI() throws NamingException {    return (DataSource) new InitialContext() //        .lookup(jndi);  }    }application.properties# ----------------------------------------# DATA PROPERTIES# ---------------------------------------- # DATASOURCE (DataSourceAutoConfiguration &amp; DataSourceProperties)#datasource.jndiname=DSdatasource.driverClassName=org.hsqldb.jdbc.JDBCDriverdatasource.url=jdbc:hsqldb:file:db/testdbdatasource.username=sadatasource.password=sa5. Data Source Test (JUnit+HSQLDB)The same test can be used on all the previous DataSource implementations.Source CodeDataSourceTest.javapackage com.damienfremont.blog; import static org.junit.Assert.*;import org.junit.*;import org.junit.runner.*; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class)@SpringBootTest(classes = Application.class)public class DataSourceTest {   @Autowired  private GenericEntityRepository data;   @Test  public void test() {    GenericEntity newEntity = new GenericEntity(\"test\");     GenericEntity savedEntity = data.save(newEntity);    GenericEntity foundEntity = data.findOne(savedEntity.getId());     assertNotNull(foundEntity);    assertEquals(newEntity.getValue(), savedEntity.getValue());    assertEquals(newEntity.getValue(), foundEntity.getValue());  }}GenericEntity.javapackage com.damienfremont.blog; import javax.persistence.*; @Entitypublic class GenericEntity {   // PROPERTIE(S)  @Id @GeneratedValue(strategy = GenerationType.AUTO)  private Long id;  private String value;   // CONSTRUCTOR(S)  public GenericEntity() { }  public GenericEntity(String value) { this.value = value; }   // ACCESSOR(S)  public Long getId() { return id; }  public void setId(Long id) { this.id = id; }  public String getValue() { return value; }  public void setValue(String value) { this.value = value; }}GenericEntityRepository.javapackage com.damienfremont.blog; import org.springframework.data.jpa.repository.*; public interface GenericEntityRepository //  extends JpaRepository&lt;GenericEntity, Long&gt; {}pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"   xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;parent&gt;    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;    &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;    &lt;version&gt;1.5.8.RELEASE&lt;/version&gt;  &lt;/parent&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;springboot-datasource-1-autoconfig&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;   &lt;packaging&gt;jar&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;8&lt;/java.version&gt;  &lt;/properties&gt;  &lt;dependencies&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;      &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;    &lt;/dependency&gt;     &lt;!-- DATA --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;      &lt;artifactId&gt;commons-dbcp2&lt;/artifactId&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.springframework&lt;/groupId&gt;      &lt;artifactId&gt;spring-jdbc&lt;/artifactId&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.springframework.data&lt;/groupId&gt;      &lt;artifactId&gt;spring-data-jpa&lt;/artifactId&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.hibernate&lt;/groupId&gt;      &lt;artifactId&gt;hibernate-entitymanager&lt;/artifactId&gt;    &lt;/dependency&gt;     &lt;!-- DATA DRIVER --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.hsqldb&lt;/groupId&gt;      &lt;artifactId&gt;hsqldb&lt;/artifactId&gt;    &lt;/dependency&gt;     &lt;!-- TEST --&gt;    &lt;dependency&gt;      &lt;groupId&gt;junit&lt;/groupId&gt;      &lt;artifactId&gt;junit&lt;/artifactId&gt;      &lt;scope&gt;test&lt;/scope&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;      &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;      &lt;scope&gt;test&lt;/scope&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Source Codehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171119-springboot-datasourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171119-springboot-datasourceReferenceshttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-configure-a-datasourcehttps://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-configure-a-datasourcehttps://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.htmlhttps://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.htmlhttp://www.baeldung.com/spring-boot-custom-auto-configurationhttp://www.baeldung.com/spring-boot-custom-auto-configurationhttps://spring.io/blog/2014/03/07/deploying-spring-boot-applicationshttps://spring.io/blog/2014/03/07/deploying-spring-boot-applicationshttp://www.baeldung.com/spring-testing-separate-data-sourcehttp://www.baeldung.com/spring-testing-separate-data-sourcehttps://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.htmlhttps://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.htmlOriginhttps://damienfremont.com/2017/11/19/howto-springboot-datasource/",
        "url": "/2017/11/19/howto-springboot-datasource"
      },
    
      "2017-11-11-maslows-hierarchy-of-needs-for-software-developers": {
        "title": "Maslows Hierarchy Of Needs For Software Developers (Not Food!)",
        "author": "",
        "category": "",
        "tags": "agile, quicktip",
        "content": "A remake of the Maslow’s pyramid, but for software developers.Content  Original pyramid  Developer pyramidOriginal PyramidDeveloper Pyramid1. Physiological Needs  Env: a comfortable environment, with good chair and coffee!  Tools: a quiet computer with a good screen, mouse and keyboard.  Process: light processes, iterative instead of waterfall  Code: avoid technical debt, and no deprecated frameworks2. Safety Needs  Meaning: your work makes sense, product will be used  Wage: the remuneration reflects the work  Career: it is possible to progress3. Social Belonging  Vision: project vision is clear  Community: belong to a community, not solo developer  Manager: manager who actually gets down to work4. Esteem  Recognition: be recognized as an asset  Learning: work add experience to developer’s profile  Contributor: developer adds value to community5. Self-actualization  Responsibility: to receive responsibility, be in charge  Creativity: have the freedom to create your solutionsReferenceshttps://en.wikipedia.org/wiki/Maslow%27s_hierarchy_of_needshttps://en.wikipedia.org/wiki/Maslow%27s_hierarchy_of_needshttp://www.softfluent.fr/blog/societe/2015/07/22/Comment-motiver-les-developpeurshttp://www.softfluent.fr/blog/societe/2015/07/22/Comment-motiver-les-developpeursSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171111-dev-maslow-pyramidhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171111-dev-maslow-pyramidOriginhttps://damienfremont.com/2017/11/11/maslows-hierarchy-of-needs-for-software-developers/",
        "url": "/2017/11/11/maslows-hierarchy-of-needs-for-software-developers"
      },
    
      "2017-11-10-agile-manifesto-reminder": {
        "title": "Agile Manifesto Reminder",
        "author": "",
        "category": "",
        "tags": "agile, quicktip",
        "content": "Here is a quick reminder of the Agile Manifesto’s content from 2001, followed by some examples with code, doc, charts, and tasks (classic VS agile way).Content  Manifesto  ExamplesManifestoManifesto for Agile Software Development (2001)We are uncovering better ways of developingsoftware by doing it and helping others do it.Through this work we have come to value:- Individuals and interactions over processes and tools- Working software over comprehensive documentation- Customer collaboration over contract negotiation- Responding to change over following a planThat is, while there is value in the items onthe right, we value the items on the left more.Twelve Principles of Agile SoftwareYou can read more at “Twelve Principles of Agile Software“.CommentSome people think that Agile means “no documentation”, “no obligation to the client”, “no planning”.It’s false.As the authors said, “we value the items on the left more“, more doesn’t mean only/not-the-others.ExamplesYou can see Agile like this:1. Individuals and interactions over processes and toolsExample with task management:Instead of using a dedicated software like JIRA at start, with accounts, hosting, user training, etc.You can just use post-it on a wall, let people move it themselves. Then change this process/tool later on if needed, as the project grow.2. Working software over comprehensive documentationExample with Java code:Instead of doing this classic POJO./** * The object containing the value. */public class ClassicClass {     /**     * The value     */    private String value;     /**     * Getter for value.     * @return the value     */    public String getValue() {        return value;    }     /**     * Setter for value.     * @param value the value to set     */    public void setValue(String value) {        this.value = value;    } }You can use the same amount of time doing this:/** * Value Object. * The value is mandatory, and read-only. */public class AgileClass {     private String value;     public String getValue() {        return value;    }     public AgileClass(String requiredValue) {        if(requiredValue== null | requiredValue.isEmpty())            thorw new IllegalArgumentException(\"value must not be empty!\");        this.value = requiredValue;    }}It has stronger code (null check, not setter), auto-documented (requiredValue name), with only relevant documentation (class header)3. Customer collaboration over contract negotiationExample with features:Instead of doing all features requested by your client without hesitation.1. Authent2. Profile3. Profile Notification4. Display Business model 16. Display Business model 2You can : Ask him which are the keyfeatures and start only with it, then show him how much each of them cost, and let him decide if some of them are really mandatory for him (it’s not always the most expensive feature that adds the most value)1. Display Business model 1-1 (8 pts)2. Display Business model 2 (5 pts)3. Authent (5 pts)4. Display Business model 1-2 (13 pts)5. Profile (3 pts)(6. Profile Notification (8 pts))4. Responding to change over following a planExample with project delay change:Instead of just reevaluating tasks randomly.You can evaluate the project feasibility over time (using the burndown chart). Then remove/transform/add features or stop the project before it’s too late.Referencehttp://agilemanifesto.org/http://agilemanifesto.org/https://en.wikipedia.org/wiki/Agile_software_development#The_Agile_Manifestohttps://en.wikipedia.org/wiki/Agile_software_development#The_Agile_Manifestohttps://en.wikipedia.org/wiki/Burn_down_charthttps://en.wikipedia.org/wiki/Burn_down_chartSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171110-agile-manifesto-reminderhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20171110-agile-manifesto-reminderOriginhttps://damienfremont.com/2017/11/10/agile-manifesto-reminder/",
        "url": "/2017/11/10/agile-manifesto-reminder"
      },
    
      "2017-09-27-indiegame-free-resources-and-materials": {
        "title": "Indiegame Free Resources And Materials",
        "author": "",
        "category": "",
        "tags": "gamedev, unity3d, assets",
        "content": "Here are some search engines and archive websites to get free, Unity3d-ready, resources.  Universe/Charcaters  Icons  Pictures  3D Models  Sound  Music  SoftwaresUniverse/CharactersGet free characters and stories from public domain (yes it’s old stuff, like more than 100 years ago) …don’t forget to check the list at the bottom of the page.http://tvtropes.org/pmwiki/pmwiki.php/Main/PublicDomainCharacterhttp://tvtropes.org/pmwiki/pmwiki.php/Main/PublicDomainCharacterIconsUse the white ones to be able to change their color in Unity3D.http://www.iconsdb.com/white-icons/http://www.iconsdb.com/white-icons/Pictureshttps://www.pexels.com/public-domain-images/https://www.pexels.com/public-domain-images/3D Modelshttps://archive3d.net/https://archive3d.net/Soundshttps://freesound.org/browse/tags/sound-effects/https://freesound.org/browse/tags/sound-effects/MusicUse only “Commercial Use”.http://freemusicarchive.org/search/http://freemusicarchive.org/search/SoftwaresTo make the stuff you can’t found free!  GameEngine: Unity3D  Icon: InkSkape  Pictures: Gimp, MagicaVoxel  3D Models: Blender  Sound: Audacity  Music: ReaperSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170927-indiegame-free-resources-and-materialshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170927-indiegame-free-resources-and-materialsOriginhttps://damienfremont.com/2017/09/27/indiegame-free-resources-and-materials/",
        "url": "/2017/09/27/indiegame-free-resources-and-materials"
      },
    
      "2017-09-19-c-sharp-calculate-execution-time": {
        "title": "C Sharp Calculate Execution Time",
        "author": "",
        "category": "",
        "tags": "csharp, unity3d, quicktip",
        "content": "Stopwatch is designed for this purpose, and is one of the best way to measure time execution in .NET.ExamplesHere is a simple usecase.var watch = System.Diagnostics.Stopwatch.StartNew();// the code that you want to measure comes herewatch.Stop();var elapsedMs = watch.ElapsedMilliseconds;Do not use DateTimes to measure time execution in .NET.“It is worth mentioning that DateTime.Now often is quite a bit slower than DateTime.UtcNow due to the work that has to be done with timezones, DST and such.DateTime.UtcNow typically has a resolution of 15 ms. See John Chapman’s blog post about DateTime.Now precision for a great summary.”You can also check multiples times before you stop the watcher.long step1ElapsedMilliseconds;long step2ElapsedMilliseconds;var watch = System.Diagnostics.Stopwatch.StartNew(); // the code that you want to measure comes here 1/2step1ElapsedMilliseconds = watch.ElapsedMilliseconds; // the code that you want to measure comes here 2/2step2ElapsedMilliseconds = watch.ElapsedMilliseconds; watch.Stop();Debug.Log(\"Execution time for step 1 in m: \"    + step1ElapsedMilliseconds );Debug.Log(\"Execution time for step 2 in m: \"    + (step2ElapsedMilliseconds - step1ElapsedMilliseconds) );Debug.Log(\"Total Execution time in ms: \"    + watch.ElapsedMilliseconds);Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170919-c-sharp-calculate-execution-timehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170919-c-sharp-calculate-execution-timeReferenceshttps://stackoverflow.com/questions/14019510/calculate-the-execution-time-of-a-methodhttps://stackoverflow.com/questions/14019510/calculate-the-execution-time-of-a-methodOriginhttps://damienfremont.com/2017/09/19/c-sharp-calculate-execution-time/",
        "url": "/2017/09/19/c-sharp-calculate-execution-time"
      },
    
      "2017-08-20-food-lasagnes-vegetariennes-rapide-et-allege": {
        "title": "Food Lasagnes Vegetariennes Rapide Et Allege",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Lasagnes légères aux champignons, épinards et emmental.Pour 8 personnes, Très facile, Bon marché, Préparation 15 min, Cuisson 40 minIngrédients (8 personnes)  20 feuilles de lasagnes (1 boite)  800g champignons eminces (2 conserves 800g)  600g épinards hachés (1 boite surgelée)  400g gruyère  (2 sachets)  500g fromage blanc (1/2 pot)  50g farine  3 tomates  Poivre (1/2 cuillère café)  Ail en poudre (1 cuillère café)  Sel (1/4 cuillère café)PréparationEtape 1: PréparationPour les épinards: lancer la décongélation (8 minutes). Pour les champignons: égoutter (entrouvrir puis retourner la boite de conserve). Pour la cuisson (si four): préchauffage à 180°CEtape 2: Préparation SaucePour la béchamel : verser fromage blanc dans saladier/bol, ajouter la farine, poivrer (1/4 cuillère café), ajouter 1/2 verre eau pour consistance crèmeEtape 3: Préparation LégumesPour les champignons: disposer dans une assiette, mettre l’ail en poudre, poivrer (1/4 cuillère café), melangerPour les tomates: couper en petits morceaux (2 cm)Etape 4: 1ère couche du platDisposer dans l’ordre: beurrer/huiler le plat (optionnel), béchamel (1/5 du total)Etape 5: Couches intermédiairesDisposer dans l’ordre et aplanir avec une fourchette: feuilles de lasagnes (2 couches), béchamel (1/5 du total), champignons (1/3 du total), épinards (1/3 du total), emmental (1/4 du total)Répéter 3 fois.Etape 6: Dernière coucheDisposer dans l’ordre et finir: feuilles de lasagnes (2 couches), béchamel, tomates, emmentalEtape 7: CuireAu micro-onde/grill: puissance 60% + grill, 35 minutes …ou au four: 180°C + grill haut, 40 minutesRemarquesVérifier la cuisson en plantant un couteau propre dans le plat. Servir si le couteau ressort sec et que la pate est tendre.Boisson conseilléeVin blanc sec (Entre-deux-mer, Côtes du Rhône blanc, Chinon blanc, Chablis, Anjou blanc)Originhttp://www.750g.com/lasagnes-vegetariennes-rapide-et-allege-r202828.htmhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170820-food-lasagnes_vegetariennes_rapide_et_allegehttp://damienfremont.com/2017/08/20/food-lasagnes-vegetariennes-rapide-et-allege/",
        "url": "/2017/08/20/food-lasagnes-vegetariennes-rapide-et-allege"
      },
    
      "2017-06-14-git-merge-repositories-without-losing-commit-history": {
        "title": "Git Merge Repositories Without Losing Commit History",
        "author": "",
        "category": "",
        "tags": "git, quicktip",
        "content": "Sometimes, you need to merge multiples repos, but you don’t want to loose your commit history. In this tutorial, it’s basically repoSource1 + repoSource2 = repoTarget.Steps  Create source repoSource1, 2 (optionnal)  Check existing history on repoSource1, 2  Merge repoSource1, 2, to repoTarget  Check history on repoTarget1. Create repos 1, 2 (optionnal)In GIT command line &gt; create repo : create folder &gt; init git &gt; add commit: create file &gt; add to git &gt; commit.cd gitmkdir repoSource1cd repoSource1git initcopy null &gt; file1.txtgit add *git commit -m \"create file1.txt\"cd gitmkdir repoSource2cd repoSource2git initcopy null &gt; file2.txtgit add *git commit -m \"create file2.txt\"2. Check histories on existing reposIn GIT command line &gt; repo 1 &gt; git log &gt; repo 2 &gt; git log.cd git/repoSource1git logcd git/repoSource2git log3. Merge repos 1, 2, to repo 3In GIT command line &gt; create target repo &gt; add remote repo &gt; merge &gt; repeat…cd gitmkdir repoTargetcd repoTargetgit init git remote add repoSource2 ..\\repoSource2git fetch repoSource2git merge repoSource2/master --allow-unrelated-histories git log git remote add repoSource1 ..\\repoSource1git fetch repoSource1git merge repoSource1/master --allow-unrelated-histories git log4. Compare histories between reposIn GIT command line &gt; for each repo: &gt; git log &gt; compare commit hash code and datecd git\\repoTargetgit log cd ..\\repoSource1git log cd ..\\repoSource2git logConclusionWith this method, commit history and order (by date) is preserved.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170614-git-merge-repositories-without-losing-commit-historyhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170614-git-merge-repositories-without-losing-commit-historyReferencesMerging Two Git Repositories Into One Repository Without Losing File HistoryMerging Two Git Repositories Into One Repository Without Losing File Historyhttp://stackoverflow.com/questions/26502970/merge-multiple-git-repositories-into-one-keeping-branches-historyhttp://stackoverflow.com/questions/26502970/merge-multiple-git-repositories-into-one-keeping-branches-historyOriginhttps://damienfremont.com/2017/06/14/git-merge-repositories-without-losing-commit-history/",
        "url": "/2017/06/14/git-merge-repositories-without-losing-commit-history"
      },
    
      "2017-06-10-java-with-lombok-avoid-boilerplate-or-generated-code-like-get-set-construct-compare": {
        "title": "Java With Lombok Avoid Boilerplate Or Generated Code Like Get Set Construct Compare",
        "author": "",
        "category": "",
        "tags": "java",
        "content": "In this tutorial, you will compare the code between a “vanilla” approach (without library) and Lombok. With three classic use-cases: DTO (get, set, toString), Builder, Implementation (arg validation).Steps  Examples DTO Implementation Builder  Configure Project (Maven) IDE (Eclipse)DTO ExampleAvoid code like get(), set(), toString(), public() by using @Data, @RequiredArgsConstructor, @ToString.DTO_Lombock.javaimport java.util.Calendar;import lombok.*; @Data@ToString(exclude =  {\"id\"})@RequiredArgsConstructorpublic class DTO_Lombock {  @NonNull private Long id;  @NonNull private String firstName;  @NonNull private String lastName;           private Calendar birthdate;}DTO_Vanilla.javaimport java.util.Calendar; public class DTO_Vanilla {  private Long id;  private String firstName;  private String lastName;  private Calendar birthdate;   public DTO_Vanilla(Long id, String firstName, String lastName) {    super();    this.id = id;    this.firstName = firstName;    this.lastName = lastName;  }   @Override  public String toString() {    return \"DTO_Vanilla(firstName=\" + firstName + \", lastName=\" + lastName + \", birthdate=\" + birthdate + \")\";  }   public Long getId() {    return id;  }   public void setId(Long id) {    this.id = id;  }   public String getFirstName() {    return firstName;  }   public void setFirstName(String firstName) {    this.firstName = firstName;  }   public String getLastName() {    return lastName;  }   public void setLastName(String lastName) {    this.lastName = lastName;  }   public Calendar getBirthdate() {    return birthdate;  }   public void setBirthdate(Calendar birthdate) {    this.birthdate = birthdate;  }}DTOTest.javaimport static org.assertj.core.api.Assertions.assertThat;import org.junit.Test; public class DTOTest {   @Test  public void test_Vanilla() {    DTO_Vanilla obj = new DTO_Vanilla(1492L, \"Damien\", \"FREMONT\");     assertThat(obj.getId()).isEqualTo(1492L);    assertThat(obj.getFirstName()).isEqualTo(\"Damien\");    assertThat(obj.getLastName()).isEqualTo(\"FREMONT\");     assertThat(obj.toString()).isEqualTo(\"DTO_Vanilla(firstName=Damien, lastName=FREMONT, birthdate=null)\");  }   @Test  public void test_Lombock() {    DTO_Lombock obj = new DTO_Lombock(1492L, \"Damien\", \"FREMONT\");     assertThat(obj.getId()).isEqualTo(1492L);    assertThat(obj.getFirstName()).isEqualTo(\"Damien\");    assertThat(obj.getLastName()).isEqualTo(\"FREMONT\");     assertThat(obj.toString()).isEqualTo(\"DTO_Lombock(firstName=Damien, lastName=FREMONT, birthdate=null)\");  } }Implementation ExampleAvoid code like Logger log = …, if(null==…),) by using @Log, @NonNull.Implem_Lombock.javaimport lombok.*;import lombok.extern.java.Log; @Log@RequiredArgsConstructorpublic class Implem_Lombock {  @NonNull private String status;   public String execute(@NonNull String arg) {    log.info(\"Execute for arg=\" + arg);    return arg + \" \" + status;  }}Implem_Vanilla.javaimport java.util.logging.Logger; public class Implem_Vanilla {  private String status;   private final static Logger log = Logger.getLogger(Implem_Vanilla.class.getName());   public Implem_Vanilla(String status) {    super();    this.status = status;  }   public String execute(String arg) {    if (arg == null)      throw new NullPointerException(\"arg\");    log.info(\"Execute for arg=\" + arg);    return arg + \" \" + status;  }}ImplemTest.javaimport static org.assertj.core.api.Assertions.assertThat;import org.junit.Test; public class ImplemTest {   @Test  public void test_Vanilla() {    Implem_Vanilla obj = new Implem_Vanilla(\"suffix\");     String res = obj.execute(\"arg\");    assertThat(res).isEqualTo(\"arg suffix\");     try {      obj.execute(null);    } catch (NullPointerException e) {      assertThat(e.getMessage()).contains(\"arg\");    }  }   @Test  public void test_Lombock() {    Implem_Lombock obj = new Implem_Lombock(\"suffix\");     String res = obj.execute(\"arg\");    assertThat(res).isEqualTo(\"arg suffix\");     try {      obj.execute(null);    } catch (NullPointerException e) {      assertThat(e.getMessage()).contains(\"arg\");    }  }}Buidler ExampleThe builder pattern implementation.Builder_Lombock.javaimport java.util.Calendar;import lombok.*; @Builder@Getterpublic class Builder_Lombok {  private Long id;  private String firstName;  private String lastName;  private Calendar birthdate;}Builder_Vanilla.javapublic class Builder_Vanilla {  private Long id;  private String firstName;  private String lastName;   public Long getId() {    return id;  }   public void setId(Long id) {    this.id = id;  }   public String getFirstName() {    return firstName;  }   public void setFirstName(String firstName) {    this.firstName = firstName;  }   public String getLastName() {    return lastName;  }   public void setLastName(String lastName) {    this.lastName = lastName;  }   public static Builder builder() {    return new Builder();  }   public static class Builder {    private Builder_Vanilla obj;     public Builder() {      obj = new Builder_Vanilla();    }     public Builder id(Long arg) {      obj.id = arg;      return this;    }     public Builder firstName(String arg) {      obj.firstName = arg;      return this;    }     public Builder lastName(String arg) {      obj.lastName = arg;      return this;    }     public Builder_Vanilla build() {      return obj;    }  } }BuilderTest.javaimport static org.assertj.core.api.Assertions.assertThat;import org.junit.Test; public class BuilderTest {   @Test  public void test_Vanilla() {    Builder_Vanilla obj = Builder_Vanilla.builder() //        .id(1492L) //        .firstName(\"Damien\") //        .lastName(\"FREMONT\") //        .build();       assertThat(obj.getId()).isEqualTo(1492L);      assertThat(obj.getFirstName()).isEqualTo(\"Damien\");      assertThat(obj.getLastName()).isEqualTo(\"FREMONT\");  }   @Test  public void test_Lombock() {    Builder_Lombok obj = Builder_Lombok.builder() //        .id(1492L) //        .firstName(\"Damien\") //        .lastName(\"FREMONT\") //        .build();       assertThat(obj.getId()).isEqualTo(1492L);      assertThat(obj.getFirstName()).isEqualTo(\"Damien\");      assertThat(obj.getLastName()).isEqualTo(\"FREMONT\");  } }Configure Project (Maven)Add Lombok dependency to you Maven project config.pom.xml&lt;project ...&gt;...  &lt;dependencies&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;      &lt;artifactId&gt;lombok&lt;/artifactId&gt;      &lt;version&gt;1.16.16&lt;/version&gt;    &lt;/dependency&gt;...Configure IDE (Eclipse)You need to add a plugin to your IDE, because the compilation-validator and autocomplete won’t work (Lombok generate code during compilation time, too soon for your IDE).Go to official website, choose your IDE, then follow instructions.https://projectlombok.org/https://projectlombok.org/https://projectlombok.org/setup/eclipsehttps://projectlombok.org/setup/eclipseProjectSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170610-java-with-lombok-avoid-boilerplate-or-generated-codehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170610-java-with-lombok-avoid-boilerplate-or-generated-codeReferenceshttps://projectlombok.org/downloadhttps://projectlombok.org/downloadhttps://projectlombok.org/setup/eclipsehttps://projectlombok.org/setup/eclipsehttps://projectlombok.org/features/allhttps://projectlombok.org/features/allOriginhttps://damienfremont.com/2017/06/10/java-with-lombok-avoid-boilerplate-or-generated-code-like-get-set-construct-compare/",
        "url": "/2017/06/10/java-with-lombok-avoid-boilerplate-or-generated-code-like-get-set-construct-compare"
      },
    
      "2017-06-09-eclipse-ide-install-ui-dark-theme": {
        "title": "Eclipse Ide Install Ui Dark Theme",
        "author": "",
        "category": "",
        "tags": "tools, quicktip",
        "content": "A quicktip about how to change the User Interface in Eclise IDE to MoonRiseUI.Steps  Install Eclipse IDE  Install MoonRiseUI Package  Import Color Preferences1. Install Eclipsehttps://www.eclipse.org/downloads/https://www.eclipse.org/downloads/2. Install MoonRiseUI PackageIn Eclipse: Help &gt; Eclipse Marketplace &gt; search ‘dark’ &gt; click Find &gt; ..Wait for MoonRiseUI &gt; click Install &gt; …accept/next until death &gt; then restart3. Import Color PreferencesIn WebBrowser: Download RainbowDrops.epf at https://marketplace.eclipse.org/content/eclipse-moonrise-ui-themeIn Eclipse: File &gt; Import &gt; General &gt; Preferences &gt; open RainbowDrops.epf &gt; FinishSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170609-eclipse-ide-install-ui-dark-themehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170609-eclipse-ide-install-ui-dark-themeReferencehttps://marketplace.eclipse.org/content/eclipse-moonrise-ui-themehttps://marketplace.eclipse.org/content/eclipse-moonrise-ui-themeOriginhttps://damienfremont.com/2017/06/09/eclipse-ide-install-ui-dark-theme/",
        "url": "/2017/06/09/eclipse-ide-install-ui-dark-theme"
      },
    
      "2017-06-08-github-edit-markdown-files-locally-in-your-ide": {
        "title": "Github Edit Markdown Files Locally In Your Ide",
        "author": "",
        "category": "",
        "tags": "git, tools",
        "content": "To be more productive, you can test your README.md locally and preview it in your IDE.It’s faster than edit &gt; commit &gt; push &gt; open webbrowser &gt; edit &gt; commit &gt; …)Steps  Install Eclipse and GitHub client  Edit markdown files  Push to GitHub1. Install Eclipse and GitHub ClientEclipse IDE can do it &gt; install Eclipse IDE &gt; install GitHub desktop client.https://www.eclipse.org/downloads/https://www.eclipse.org/downloads/https://desktop.github.com/https://desktop.github.com/2. Edit markdown filesStart Eclipse IDE &gt; Open File ‘YOUR_PROJECT/README.md’ &gt; edit it &gt; … &gt; Click on Preview tab &gt; … &gt; Save3. Push to GitHubStart GitHub desktop client &gt; Add message ‘Update README’ &gt; Commit &gt; Push &gt; …wait &gt; go to website to see the result.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170608-github-edit-markdown-files-locallyhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170608-github-edit-markdown-files-locallyReferenceshttps://www.eclipse.org/downloads/https://www.eclipse.org/downloads/https://desktop.github.com/https://desktop.github.com/Originhttps://damienfremont.com/2017/06/08/github-edit-markdown-files-locally-in-your-ide/",
        "url": "/2017/06/08/github-edit-markdown-files-locally-in-your-ide"
      },
    
      "2017-06-07-github-create-a-simple-website-for-your-side-project": {
        "title": "Github Create A Simple Website For Your Side Project",
        "author": "",
        "category": "",
        "tags": "gamedev, git, tools",
        "content": "In this tutorial, you will see how to generate a website with your existing markdown documentation (like README.md …no need to rewrite everything).Examplehttp://damienfremont.github.io/blog/http://damienfremont.github.io/blog/Steps  Create or use existing project  Activate GitHub pages  Choose a theme  Write documentation in markdown  Edit remotely on GitHub1. Create or use existing projectYou need a project &gt; use your existing side project reposity.2. Activate GitHub pagesYou just need to follow GitHub documentation: activate GitHub pages in repo’s settings &gt; choose a theme.https://pages.github.com/https://pages.github.com/3. Choose a themeYour project site is not very prety &gt; use Theme chooser in your repo’s settings &gt; choose one &gt; test it.4. Write documentation in markdownYour website pages layout start with README.md &gt; after that it’s up to your links in the markdown files.https://guides.github.com/features/mastering-markdown/https://guides.github.com/features/mastering-markdown/  create README.md main page  create subpages  add link to theses subpages in README.mdYou can test it locally or onsite (GitHub). Depends of your goal (stable update lifecycle of your website with one-shot push,  or simpler with less tools but more chaotic).5. Edit remotely on GitHubThe simplest way is to edit your files with GitHub website (no merge problem, no tools, builtin preview).##Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170607-github-create-simple-websitehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170607-github-create-simple-websiteReferenceshttps://guides.github.com/features/mastering-markdown/https://guides.github.com/features/mastering-markdown/https://pages.github.com/https://pages.github.com/https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/https://help.github.com/articles/creating-a-github-pages-site-with-the-jekyll-theme-chooser/https://help.github.com/articles/creating-a-github-pages-site-with-the-jekyll-theme-chooser/Originhttps://damienfremont.com/2017/06/07/github-create-a-simple-website-for-your-side-project/",
        "url": "/2017/06/07/github-create-a-simple-website-for-your-side-project"
      },
    
      "2017-06-06-git-commit-message-conventions": {
        "title": "Git Commit Message Conventions",
        "author": "",
        "category": "",
        "tags": "git, quicktip",
        "content": "A quicktip about writing good commit messages. It’s inspired by major open sources projects, like AngularJS.Commit Message Conventions&lt;type&gt;(&lt;scope&gt;): &lt;subject&gt; (#&lt;task_id&gt;)&lt;BLANK LINE&gt;&lt;body&gt;&lt;BLANK LINE&gt;  title (less than 50 chars) type: ‘feat’, ‘doc’, ‘fix’, ‘refactor’, ‘build’ scope: your project task’s scope (one word) subject: the work done id: your task or issue or ticket unique ID  body (optionnal) details for big tasksExamplesfeat(menu): color, font (#102)doc(menu): get started (#103)fix(menu): color change bug (#399)feat(account): font (#104)doc(account): get started (#104)refactor: common font for menu, account (#652)fix: remove deprecated fonts (#901)  Removed:  * Arial.ttf  * Comic.ttfSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170606-git-commit-message-conventions/https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170606-git-commit-message-conventions/Referenceshttps://github.com/angular/material2/blob/master/CONTRIBUTING.mdhttps://github.com/angular/material2/blob/master/CONTRIBUTING.mdhttps://chris.beams.io/posts/git-commit/https://chris.beams.io/posts/git-commit/https://github.com/angular/material2/commits/masterhttps://github.com/angular/material2/commits/masterOriginhttps://damienfremont.com/2017/06/06/git-commit-message-conventions/",
        "url": "/2017/06/06/git-commit-message-conventions"
      },
    
      "2017-06-05-git-unity3d-gitignore": {
        "title": "Git Unity3d Gitignore",
        "author": "",
        "category": "",
        "tags": "git, quicktip, unity3d",
        "content": "A fulll .gitignore content for Unity3d users.File.gitignoreTempLibraryProjectSettingsbuildsobj*.log*.sln*.userprefs*.csproj*.pdb*_Data*.suo*.exe*.apkSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170605-git-unity3d-gitignorehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170605-git-unity3d-gitignoreOriginhttps://damienfremont.com/2017/06/05/git-unity3d-gitignore/",
        "url": "/2017/06/05/git-unity3d-gitignore"
      },
    
      "2017-06-05-git-java-gitignore": {
        "title": "Git Java Gitignore",
        "author": "",
        "category": "",
        "tags": "git, java, quicktip",
        "content": "A fulll .gitignore content for Java/maven users.File.gitignore*.class*.war*.ear.classpath.project.settingstargetSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170605-git-java-gitignorehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170605-git-java-gitignoreOriginhttps://damienfremont.com/2017/06/05/git-java-gitignore/",
        "url": "/2017/06/05/git-java-gitignore"
      },
    
      "2017-06-04-creer-rapidement-une-marque-sur-internet-nom-domain-site-reseaux-suivi": {
        "title": "Creer Rapidement Une Marque Sur Internet Nom Domain Site Reseaux Suivi",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Voici un rapide retour sur rendre une idée visible sur Internet. Et comment en faire le suivi, à moindre frais.Etapes  Construire un nom simple abstrait multilingue  Verifier la dispo societe domain et reseaux  Creer un site web acheter le domain creer un site minimaliste  Ajouter des réseaux Twitter Facebook…  Publier des actualités MultiPost avec Hootsuite  Faire le suivi Support et Contact Traffic Reseaux Tendances/Recherches1. Construire un nomSimpleVotre nom doit être facile à transmettre &gt; donc facile à épeller, prononcer ou écrir. Pas plus de 3-4 silabes. Pas de tirets ou de points.AbstraitVotre activité peut évoluer dans le temps &gt; ne pas inclure de terme du domaine métier. Le générer avec un site est une bonne source d’idéehttp://www.trouverunnom.comhttp://www.trouverunnom.comMultilingueLa langue ne doit pas être une barrière &gt; tester le nom prononcé en Français et Anglais. Vérifier que le nom/mot n’existe pas dans une autre langue.https://text-to-speech-demo.mybluemix.net/https://text-to-speech-demo.mybluemix.net/2. Verifier la dispoC’est très important, car après pas de retour possible!SocieteEviter tout conflit ultérieur &gt; le nom doit être disponible auprès du registre du commerce.https://www.infogreffe.frhttps://www.infogreffe.frPuis faire une demande de création d’entreprisehttps://www.insee.fr/fr/information/1401387https://www.insee.fr/fr/information/1401387Domain et ReseauxNe pas racheter un domain existant &gt; avoir un nom unique. Eviter le ‘cyber-squatage’ &gt; acheter à minima le .com (.fr, .net sont en option).Accèlerer les tests de noms &gt; utiliser un site dédié de férificationhttps://www.namecheck.com/search?searchterm=googlehttps://www.namecheck.com/search?searchterm=google######3. Creer un site webAcheter le domainLe nom doit vous apartenir &gt; souscrire chez un registrar sérieux avec une configuration simple et documentée. Au lieu de passer par wordpress.com et de leur demander de créer le domain.Eviter les surcout &gt; utiliser juste le site perso/static inclus dans l’offre de base domainhttps://www.gandi.net/?lang=frhttps://www.gandi.net/?lang=frCreer un site minimalisteLes pages doivent :  être reférencées par les robots &gt; mots clés et arborescence statiques  s’afficher en miniatures dans les reseaux sociaux &gt; pages statiques  s’afficher sur tous support et connections &gt; mobile et légerSimple &gt; pages accueil, produits,  contactUtilisateur débutant &gt; générer un site avec l’outil fourni par l’herbergeurUtilisateur avancé &gt; utiliser un moteur de site static comme Jekyll puis copier le résultat en FTP.4. Ajouter des réseauxAjouter les prioritaires &gt; Twitter et FacebookRéférencer ces comptes sur la page de votre site.Les autres sont optionnels (Google+,  LinkedIn).Pour Twitter vous pouvez augmenter votre nombre d’abonnées afin de rendre le compte plus attractif. Il suffit de suivre les comptes de ce site (attention à cibler ces comptes, eviter les comptes offensant ou trop loin de votre activité)http://www.letsallfollowback.com/http://www.letsallfollowback.com/5. Publier des actualitésPas besoin de faire un blog &gt; c’est un surcout et vos actualités ont plus de visibilité sur les reseaux.Ecrire une seule fois vos messages &gt; Eviter de dupliquer vos taches pour chaque réseaux, utiliser un seul point d’entré comme HootSuite qui fera suivre à chaque reseaux.https://hootsuite.com/https://hootsuite.com/6. Faire le suiviSupport et ContactSécurité &gt; éviter d’utiliser l’adresse mail du domain. Elle est plus facilement piratable et vous pouvez perdre votre domaine site. Utilsier GMailRéférencer ces adresses sur la page de votre site, mais en ajoutant des espaces pour limiter les spams.Traffic SiteLa solution sans frais est Google Traffic &gt; créer un compte &gt; ajouter la balise sur votre sitehttps://analytics.google.com/ahttps://analytics.google.com/aTraffic RéseauxTwitter fournit sa solution.https://analytics.twitter.com/https://analytics.twitter.com/Tendances/RecherchesGoogleTrends &gt; ajouter votre  et les termes concurrent ou procheshttps://trends.google.fr/https://trends.google.fr/Exemple 1  Société: Gaagle  Domain: adresses: gaagle.com acheté chez chez gandi.net 20€  Site: blog fournit par Gandi (moteur DotClear 2)  Réseaux: Twitter, Facebook Publier avec hootsuite  Suivi Contact et Support: contact-gaagle@gmail.ComExemple 2  Société: Gaagle  Domain adresses: gaagle.com, gaagle.fr acheté chez chez gandi.net 40€  Site: page web générée avec Jekyll, copié via FTP  Réseaux: Twitter, Facebook, LinkedIn, Google+ Publier avec hootsuite Stats avec hootsuite  Suivi Contact: contact-gaagle@gmail.com Support: support-gaagle@gmail.com Traffic site avec GoogleAnalytics Recherche avec GoogleTrendsConclusionBien penser à l’avance le nom et vérifier sa disponibilité sur les différentes plateformes (infogreffe, domain, réseaux), car c’ets impossible à changer ensuite.Créer la societé et réserver le domain et les réseaux le plus tôt possible, sinon vous aurez une source de problème par la suiteAvoir dès le début un support/contact et un suivi du traffic. Même si Twittter sert aussi de support.Referenceshttp://1001startups.fr/nom-entreprise/http://1001startups.fr/nom-entreprise/https://coreight.com/content/outils-pour-automatiser-reseaux-sociauxhttps://coreight.com/content/outils-pour-automatiser-reseaux-sociauxOriginhttps://damienfremont.com/2017/06/04/creer-rapidement-une-marque-sur-internet-nom-domain-site-reseaux-suivi/",
        "url": "/2017/06/04/creer-rapidement-une-marque-sur-internet-nom-domain-site-reseaux-suivi"
      },
    
      "2017-06-03-how-to-unity3d-use-visualstudio-script-editor-and-debug-project": {
        "title": "How To Unity3d Use Visualstudio Script Editor And Debug Project",
        "author": "",
        "category": "",
        "tags": "gamedev, csharp, unity3d, tools",
        "content": "In this tutorial, you’ll see a project configured with VisualStudio. And how to run and debug it.Steps  Open the ‘Example’ project  Choose a Script Editor  Add breakpoint in source code  Attach Script Editor to Unity3D  Debug1. Open the ‘Example’ projectIn Unity3D:  Projects &gt; Open &gt; ‘Example’ &gt; (wait) &gt; Open Scene &gt; ‘Sample Scenes Scenes/car.unity’  Edit &gt; Play &gt; (test it) &gt; Play (or click Play button, or press Ctrl+P)2. Choose a Script EditorIn Unity3d:  Edit &gt; Preferences &gt; External Tools &gt; ExternalScriptEditor: ‘MonoDevelop’  Assets &gt; Open C# Project3. Add Breakpoint in source codeIn VisualStudio:  Open ‘SampleScenes/Menu/Scripts/MenuSceneLoader.cs’  Add a breakpoint to line 144. Attach Script Editor to Unity3DIn VisualStudio:  Click the little show button next to ‘Attach to Unity’ &gt; Select ‘Attach to Unity and Play’5. DebugIn VisualStudio:  Click ‘Attach to Unity and Play’  (it’s in pause now, stopped at the breakpoint line)  Click Continue (or press F5)In Unity3d:  (play with it)In VisualStudio:  Click Stop (or press Shift+F5)ConclusionPros: More productive than MonoDevelop  (you don’t have to switch beetwen Editor and Unity3D to run a debug). Dark Them is nice too!Cons: More heavy on CPU/RAM than MonoDevelop. And it’s a Microsoft productHere is the same project opened on VisualStudio, MonoDevelop and a text Editor.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170603-unity3d-use-visualstudio-script-editor-and-debug/https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170603-unity3d-use-visualstudio-script-editor-and-debug/Referenceshttps://unity3d.com/fr/learn/tutorials/topics/scripting/debugging-unity-games-visual-studiohttps://unity3d.com/fr/learn/tutorials/topics/scripting/debugging-unity-games-visual-studioOriginhttps://damienfremont.com/2017/06/03/how-to-unity3d-use-visualstudio-script-editor-and-debug-project/",
        "url": "/2017/06/03/how-to-unity3d-use-visualstudio-script-editor-and-debug-project"
      },
    
      "2017-06-03-how-to-unity3d-use-monodevelop-script-editor-and-debug-project": {
        "title": "How To Unity3d Use Monodevelop Script Editor And Debug Project",
        "author": "",
        "category": "",
        "tags": "gamedev, csharp, unity3d",
        "content": "In this tutorial, you’ll see a project configured with MonoDevelop. And how to run and debug it.Steps  Open the ‘Example’ project  Choose a Script Editor  Add breakpoint in source code  Attach Script Editor to Unity3D  Debug1. Open the ‘Example’ projectIn Unity3D:  Projects &gt; Open &gt; ‘Example’ &gt; (wait) &gt; Open Scene &gt; ‘Sample Scenes Scenes/car.unity’  Edit &gt; Play &gt; (test it) &gt; Play (or click Play button, or press Ctrl+P)2. Choose a Script EditorIn Unity3d:  Edit &gt; Preferences &gt; External Tools &gt; ExternalScriptEditor: ‘MonoDevelop’  Assets &gt; Open C# Project##3. Add Breakpoint in source codeIn MonoDevelop:  Open ‘SampleScenes/Menu/Scripts/MenuSceneLoader.cs’  Add a breakpoint to line 144. Attach Script Editor to Unity3DIn MonoDevelop:  Run &gt; Attach to process &gt; Unity3d &gt; Attach5. DebugIn Unity3d:  Edit &gt; Play  (it’s in pause now, stopped at the breakpoint line)In MonoDevelop:  Run &gt; Continue Debugging (or click Continue button or press F5)In Unity3d:  (play with it)ConclusionPros: MonoDevelop is more productive than editing script in simple text editor or in Unity3d (compilation,  warnings, autocomplete, etc). It’s light on CPU/RAM consumption.Cons: Need to switch between Editor and Unity to run each debug. It’s also a little unstable (copy/paste from webbrowser sometime copy empty chars, compilation shutdown, etc).Here is the same project opened on VisualStudio, MonoDevelop and a text Editor.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170603-unity3d-use-monodevelop-script-editor-and-debug/https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170603-unity3d-use-monodevelop-script-editor-and-debug/Referenceshttp://answers.unity3d.com/questions/1240640/how-do-i-change-the-default-script-editor.htmlhttp://answers.unity3d.com/questions/1240640/how-do-i-change-the-default-script-editor.htmlOriginhttps://damienfremont.com/2017/06/03/how-to-unity3d-use-monodevelop-script-editor-and-debug-project/",
        "url": "/2017/06/03/how-to-unity3d-use-monodevelop-script-editor-and-debug-project"
      },
    
      "2017-06-02-how-to-unity3d-why-use-ui-instead-of-gui-imgui": {
        "title": "How To Unity3d Why Use Ui Instead Of Gui Imgui",
        "author": "",
        "category": "",
        "tags": "gamedev, csharp, unity3d",
        "content": "In this use-case, you will see the difference between GUI and UI API. And why use the later in your game, for constancy between platforms and API long term support.A lot of tutorials and feedbacks on Internet show code using GUI API. But it not a good approach to Unity3D.Here si the official Unity3D documentation: “The IMGUI system is not generally intended to be used for normal in-game user interfaces … For that you should use Unity’s main GameObject-based UI system“.https://docs.unity3d.com/Manual/GUIScriptingGuide.htmlhttps://docs.unity3d.com/Manual/GUIScriptingGuide.htmlSteps  GUI Example  UI Example Pros / Cons  Project Code  DemosGUI ExampleThe GUI is the fastest way to build UI, like on other platforms like webpage (HTML/JS/CSS), or Android (Java). But it’s not intended to be use in game code. It’s just for testing en Unity Editor.https://docs.unity3d.com/Manual/GUIScriptingGuide.htmlhttps://docs.unity3d.com/Manual/GUIScriptingGuide.html  Pros Productive (simple) Maintainable (less code, params)  Cons GUI is deprecated since Unity3D 5.x!!! Limited (don’t work properly on other plateforme than Windows) coordinates start at top/left (like webpage/android, are absolute in pixel)UI ExampleUnity3d.UI is the actual UI API. It’s complex, but fully customizable. But there is no convention or default behavior (like size, colors, textures).https://docs.unity3d.com/Manual/HOWTO-UIMultiResolution.htmlhttps://docs.unity3d.com/Manual/HOWTO-UIMultiResolution.html  Pros relative position (to parent object) consistancy, responsive (same UI between plateformes)  Cons Need an Event system (EventManager) very verbose (like WPF, GWT, or SWING) complex (you need lot of Canvas, GameObjects) coordinates start at bot/leftProject CodeYou can download or code this example project.  create empty 2D project  create a Startup.cs script for the Unity3D editor to add Script to scene automatically.  create three examples  run it on windows  run it on mobile  compare the resulthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170602-unity3d-use-ui-instead-of-gui-or-imgui/https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170602-unity3d-use-ui-instead-of-gui-or-imgui/Assets/Startup.csusing UnityEngine;using UnityEditor; // http://docs.unity3d.com/Manual/RunningEditorCodeOnLaunch.html[InitializeOnLoad]public class Startup{    static Startup ()    {        GameObject gameObject;        gameObject = GameObject.Find(\"Main Camera\");         Component script1 = gameObject.GetComponent&amp;amp;lt;GUIExample&amp;amp;gt;();        if (script1 == null) {            gameObject.AddComponent&amp;amp;lt;GUIExample&amp;amp;gt; ();        }         Component script2 = gameObject.GetComponent&amp;amp;lt;UIExample&amp;amp;gt;();        if (script2 == null) {            gameObject.AddComponent&amp;amp;lt;UIExample&amp;amp;gt; ();        }    }}https://docs.unity3d.com/ScriptReference/GameObject.Find.htmlhttps://docs.unity3d.com/ScriptReference/GameObject.Find.htmlAssets/Scripts/GUIExample.csusing System;using UnityEngine; // https://docs.unity3d.com/Manual/GUIScriptingGuide.htmlpublic class GUIExample : MonoBehaviour{    // Use this for initialization    void OnGUI ()    {        Rect rect = new Rect (10, 10, 100, 100);        Texture2D tex = new Texture2D (1, 1);        tex.SetPixels(new Color[]{Color.grey});         GUIStyle style = new GUIStyle ();        style.normal.background = tex;        // https://docs.unity3d.com/ScriptReference/GUILayout.BeginArea.html        GUILayout.BeginArea (rect, tex, style);        if (GUILayout.Button (\"Click me\"))            action ();        if (GUILayout.Button (\"Or me\"))            action ();        GUILayout.EndArea ();    }     private void action ()    {        Debug.Log (\"Hello!\");    }}Assets/Scripts/UIExample.csusing System;using UnityEngine;using UnityEngine.UI;using UnityEngine.Events;using UnityEngine.EventSystems; public class UIExample : MonoBehaviour{    // Use this for initialization    void Start ()    {        Rect rect = new Rect (0, 0, 100, 100);        Texture2D tex = new Texture2D (1, 1);        tex.SetPixels(new Color[]{Color.blue});         CreateEventSystem (this.transform);         GameObject a = area (this.transform, rect, tex);        GameObject b1 = button (a.transform, new Vector2(0,12), \"Click me\", delegate {            TaskOnClick();        });        GameObject b2 = button (a.transform, new Vector2(0,-12), \"Or me\",  delegate {            TaskOnClick();        });    }     public void TaskOnClick ()    {        Debug.Log (\"Hello!\");    }     // BOILER PLATE BELLOW...     GameObject area (Transform parent, Rect rect, Texture2D tex)    {        // OBJECT        GameObject canObj = new GameObject (\"UI:Canvas\");        canObj.transform.SetParent (parent);         // OBJECT:CANVAS        // http://docs.unity3d.com/Manual/UICanvas.html        Canvas can = canObj.AddComponent&lt;Canvas&gt; ();        can.renderMode = RenderMode.ScreenSpaceOverlay;        can.pixelPerfect = true;         // OBJECT:CANVAS:SCALER        // http://docs.unity3d.com/ScriptReference/UI.CanvasScaler.html        CanvasScaler canObjSca = canObj.AddComponent&lt;CanvasScaler&gt; ();        canObjSca.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;        canObjSca.referenceResolution = new Vector2(540, 480);         // OBJECT:CANVAS:RAYCASTER        // https://docs.unity3d.com/Manual/script-GraphicRaycaster.html        GraphicRaycaster canvasRayc = canObj.AddComponent&lt;GraphicRaycaster&gt; ();           // OBJECT:CANVAS:PANEL        GameObject panObj = new GameObject (\"UI:Panel\");        panObj.transform.SetParent (canObj.transform);        // https://docs.unity3d.com/Manual/UIBasicLayout.html        RectTransform panTrs = panObj.AddComponent&lt;RectTransform&gt; ();        panTrs.anchoredPosition = new Vector2 (rect.x, rect.y);        panTrs.localScale = new Vector3 (1.0f, 1.0f, 1.0f);        // SetSize(panTrs, new Vector2(rect.width, rect.height));         // OBJECT:CANVAS:PANEL:TEXTURE        Image img = panObj.AddComponent&lt;Image&gt; ();        img.sprite = Sprite.Create (tex, new Rect (0, 0, tex.width, tex.height),            new Vector2 (1.0f, 1.0f));         return canObj;    }     GameObject button (Transform parent, Vector2 coord, string textStr, UnityAction eventListner)    {        Vector2 size = new Vector2 (90, 25);         // OBJECT        GameObject btnObj = new GameObject (\"UI:Button\");        btnObj.transform.SetParent (parent);        RectTransform btnTrs = btnObj.AddComponent&lt;RectTransform&gt; ();        btnTrs.anchoredPosition = coord;        btnTrs.localScale = new Vector3 (1.0f, 1.0f, 1.0f);        SetSize(btnTrs, size);         // OBJECT:CANVAS:TEXTURE        // http://docs.unity3d.com/ScriptReference/Sprite.Create.html        Image img = btnObj.AddComponent&lt;Image&gt; ();        Texture2D tex = Resources.Load&lt;Texture2D&gt; (\"button_bkg\");        img.type = Image.Type.Sliced;        img.sprite = Sprite.Create (tex, new Rect (0, 0, tex.width, tex.height), new Vector2 (0.5f, 0.5f),            100.0f, 0, SpriteMeshType.Tight, new Vector4 (10, 10, 10, 10));         //  OBJECT:BUTTON        // https://docs.unity3d.com/ScriptReference/UI.Button-onClick.html        Button btn = btnObj.AddComponent&lt;Button&gt; ();        btn.interactable = true;        btn.onClick.AddListener (eventListner);        // https://docs.unity3d.com/ScriptReference/UI.Selectable-transition.html        btn.targetGraphic = img;        btn.transition = Selectable.Transition.ColorTint;         //  OBJECT:TEXT        // https://docs.unity3d.com/ScriptReference/UI.Text.html        GameObject btnTxtObj = new GameObject (\"UI:Text\");        btnTxtObj.transform.SetParent (btnObj.transform);        RectTransform btnTxtTrs = btnTxtObj.AddComponent&lt;RectTransform&gt; ();        btnTxtTrs.anchoredPosition = new Vector2(0,0);        // SetSize(btnTxtTrs, size);        Text txt = btnTxtObj.AddComponent&lt;Text&gt; ();        txt.supportRichText = true;        txt.text = textStr;        txt.fontSize = 12;        txt.font = Resources.GetBuiltinResource(typeof(Font), \"Arial.ttf\") as Font;        txt.alignment = TextAnchor.MiddleCenter;        txt.horizontalOverflow = HorizontalWrapMode.Overflow;        txt.color = Color.black;         return btnObj;    }     public static void SetSize (RectTransform trans, Vector2 size)    {        Vector2 currSize = trans.rect.size;        Vector2 sizeDiff = size - currSize;        trans.offsetMin = trans.offsetMin -            new Vector2 (sizeDiff.x * trans.pivot.x,                sizeDiff.y * trans.pivot.y);        trans.offsetMax = trans.offsetMax +            new Vector2 (sizeDiff.x * (1.0f - trans.pivot.x),                sizeDiff.y * (1.0f - trans.pivot.y));    }     public static GameObject CreateEventSystem (Transform parent)    {        // https://docs.unity3d.com/Manual/EventSystem.html        GameObject esObj = new GameObject (\"EventSystem\");        esObj.transform.SetParent (parent);         EventSystem esClz = esObj.AddComponent&lt;EventSystem&gt; ();        esClz.sendNavigationEvents = true;        esClz.pixelDragThreshold = 5;         StandaloneInputModule stdIn = esObj.AddComponent&lt;StandaloneInputModule&gt; ();        stdIn.horizontalAxis = \"Horizontal\";        stdIn.verticalAxis = \"Vertical\";         TouchInputModule touchIn = esObj.AddComponent&lt;TouchInputModule&gt; ();         return esObj;    }}DemoIn this demo, we will test the two API side by side.  on UnityEditor Preview test onClick action test responsive in low and high screen resolution in portrait and landscape orientation  on Android Mobile Device##Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170602-unity3d-use-ui-instead-of-gui-or-imgui/https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170602-unity3d-use-ui-instead-of-gui-or-imgui/Referenceshttps://unity3d.com/fr/learn/tutorials/topics/user-interface-uihttps://unity3d.com/fr/learn/tutorials/topics/user-interface-uihttps://docs.unity3d.com/Manual/GUIScriptingGuide.htmlhttps://docs.unity3d.com/Manual/GUIScriptingGuide.htmlOriginhttps://damienfremont.com/2017/06/02/how-to-unity3d-why-use-ui-instead-of-gui-imgui/",
        "url": "/2017/06/02/how-to-unity3d-why-use-ui-instead-of-gui-imgui"
      },
    
      "2017-06-01-how-to-unity3d-configure-project-for-android-and-run-it-on-mobile-device": {
        "title": "How To Unity3d Configure Project For Android And Run It On Mobile Device",
        "author": "",
        "category": "",
        "tags": "gamedev, android, unity3d",
        "content": "In this tutorial, you start from scratch. You will install Unity3D, Android SDK, then configure a project for Android, and run it on a mobile device.Steps  Choose Your Mobile Plateforme  Install Unity3D and Android Plugin  Install AndroidWorks  Install Android Driver (optional)  Activate Dev Debug mode  Configure Project  Build, Run and Play!1. Choose Your Mobile PlateformeTargeting a technology is always the same. Because it change over time, it’s safer to choose the “largest lesser” version (and not the latest) at your product launch to allow you to reach most devices .Examples:  2016: choose Android 4.4, you’ll reach 80-90% of the devices.  2012: choose Android 2.3.3, you’ll reach 70%…  2010: choose Android 2.1…https://en.wikipedia.org/wiki/Android_version_historyhttps://en.wikipedia.org/wiki/Android_version_history2. Install Unity3D And Android Plugin (Windows)Unity3D and his Android package is needed.  download your installer (perso, pro, etc)  run installer  choose components Example Project Android Build Support  Wait for download to complete (4 Go)3. Install AndroidWorks (Windows)You need to install Android SDK for Unity3D compatibility (API 23/Android6.0 for Unity3D 5.6) and for your target devices (API 19/Android 4.4.2)  got to https://developer.nvidia.com/codeworks-android Create and Nvidia account download codeworks for Windows 64  install  wait for manager popup after download stage check install Unity3D android target Version (6.0). check install your android target Version (4.4). uncheck NVidia stuff like Android NDK, Developer Tools check  auto resolve click next  ignore warnings  accepts licences  wait for download to complete (12 Go)4. Install Android USB Driver (Windows)Sometimes, to enable debug mode, you need to install a specific USB driver for your phone.https://developer.android.com/studio/run/win-usb.htmlhttps://developer.android.com/studio/run/win-usb.html5. Activate Dev Debug Mode (Android)Settings &gt; About Phone &gt; Build number &gt; Tap it 7 times to become developer;Settings &gt; Developer Options &gt; USB Debugging.https://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htmhttps://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htm6. Configure Project (Unity3d)We will use the “Standard Assets Example Project”, but limit to only ONE scene because of the load of the entire project during deployment to the mobile device (one scene is 30sec, all scenes is 10min).  Open the Unity3d project Update Build SettingsCheck only ONE project Choose Android, with dev build  Update Player Settings Select Android Choose targets API (ex 4.4)  Test it locally (Windows)  Save7. Build, Run and Play!Project and device are ready.  Build and Run  Choose APK name, Save  Autorise usb debug on for device from android  Wait for deployment (‘Hold On’ popup)  Play!  Get APK from Project folder (on Windows, ‘Example Project.apk’)ConclusionAndroidWorks provide a simple way to install and manage android sdk installation.Choosing Android version first is better, because latter it’s harder to do that latter in the project: you can run into Unity3D API changes, or bugs in your game, and you don’t want to do that just before your final release!These example have been tested on multiple devices:  LG G4 (2015) Android 6.x high specs  Samsung Galaxy A5 (2016) Android 7.x low specs no gyroIf you change your mind about the Android Version, just relaunch AndroidWorks.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170601-unity3d-configure-project-for-android-and-run-ithttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170601-unity3d-configure-project-for-android-and-run-itReferenceshttps://en.wikipedia.org/wiki/Android_version_historyhttps://en.wikipedia.org/wiki/Android_version_historyhttps://store.unity.comhttps://store.unity.comhttps://docs.nvidia.com/gameworks/content/developertools/mobile/androidworks/androidworks_install.htmhttps://docs.nvidia.com/gameworks/content/developertools/mobile/androidworks/androidworks_install.htmhttps://developer.android.com/studio/run/win-usb.htmlhttps://developer.android.com/studio/run/win-usb.htmlhttps://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htmhttps://www.kingoapp.com/root-tutorials/how-to-enable-usb-debugging-mode-on-android.htmOriginhttps://damienfremont.com/2017/06/01/how-to-unity3d-configure-project-for-android-and-run-it-on-mobile-device/",
        "url": "/2017/06/01/how-to-unity3d-configure-project-for-android-and-run-it-on-mobile-device"
      },
    
      "2017-05-29-js-react-material-express-setting-up-a-project-using-npm-webpack-babel": {
        "title": "Js React Material Express Setting Up A Project Using Npm Webpack Babel",
        "author": "",
        "category": "",
        "tags": "expressjs, javascript, nodejs, reactjs",
        "content": "This is the simplest example to build a webapp using ReactJS, MaterialUI and ExpressJS in a project with Npm, Webpack, Babel.A lot of these tools are not required to use React. But using ES6, JSX is more productive.Stack  NodeJs – A JavaScript runtime built on Chrome’s V8 JavaScript engine.  Npm – The package manager for JavaScript and the world’s largest software registry.  ReactJS – The state based framework for your Views  ExpressJS – The node framework to serve your views to the world when they hit the server at example.com or example.com/awesome.html  MaterialUI – A Set of React Components that ImplementGoogle’s Material Design  Webpack – The module binder which takes all your JS files from different directories and compiles them into a single app.bundle.js (you can change the filename of course) so you can include it in a HTML page  Babel – The compiler to compile your JS files with es6, es7, JSX syntax to regular javascriptSteps  Init NodeJs, Project  Add Express  Add React  Add Material1. Init NodeJs, ProjectGo to NodeJs website and download the stable version (LTS).https://nodejs.org/en/https://nodejs.org/en/Create a new folder ‘YOUR_PROJECT_NAME’ and initialize it with npm.mkdir YOUR_PROJECT_NAMEcd YOUR_PROJECT_NAMEnpm initAnswer all the questions about your project.npm installnpm install webpack -g2. Add Express\"dependencies\": { \"express\": \"4.13.3\", \"compression\": \"1.6.0\" }, \"devDependencies\": { }Add then Implement Express Server (server.js).It’s a simple example with a REST API that provide server’s status.// Module dependencies.var express = require('express'), compression = require('compression'); // Configurationvar app = express();app.set('port', (process.env.PORT || 5000));app.use(compression());var http = require('http').Server(app); // Routesapp.use('/', express.static('./public')); // RESTapp.get('/api/status', function (req, res) { var status = \"ONLINE (v1.0.0)\"; res.send(status);}); // Start servervar server = http.listen(app.get('port'), function(){ var host = server.address().address; var port = server.address().port; console.log('Example app listening at http://%s:%s', host, port);});Buildnpm installStartnpm startTesthttp://localhost:5000/api/statushttp://localhost:5000/api/status3. Add Reactpackage.json\"scripts\": { \"start\": \"node server.js\", \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\" }, \"dependencies\": {   \"express\": \"4.13.3\",  \"compression\": \"1.6.0\",   \"react\": \"15.4.2\",  \"react-dom\": \"15.4.2\",   \"babel-core\": \"6.24.1\", }, \"devDependencies\": {    \"babel-loader\": \"6.4.0\",   \"babel-preset-es2015\":  \"6.24.1\",   \"babel-preset-react\":   \"6.24.1\",   \"babel-preset-stage-1\": \"6.24.1\",    \"webpack\": \"2.6.1\",   \"webpack-dev-server\": \"2.4.5\", \"html-webpack-plugin\": \"2.28.0\" }webpack.config.js'use strict'; var path = require('path');var webpack = require('webpack');var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = [{entry: './views/index.jsx',output: {path: __dirname + '/public/',filename: '[name].js',publicPath: '/'},plugins: [new webpack.optimize.UglifyJsPlugin(),new HtmlWebpackPlugin({template: 'views/index.tpl.html',inject: 'body',filename: 'index.html'})],module: {loaders: [{test: /\\.jsx?$/,exclude: /node_modules/,loader: 'babel-loader',query: {\"presets\": [\"react\", \"es2015\"]}}]}}];views/index.tpl.html&lt;!doctype html&gt;&lt;html lang=\"en\"&gt;  &lt;head&gt;    &lt;meta charset=\"utf-8\"&gt;    &lt;meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\"&gt;    &lt;title&gt;JS React Material Express&lt;/title&gt;    &lt;meta name=\"description\" content=\"Setting Up a Project Using Npm, Webpack, Babel\"&gt;    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;  &lt;/head&gt;  &lt;body&gt;&lt;div id=\"app\"&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;views/index.jsximport React from 'react';import ReactDOM from 'react-dom';import App from './app.jsx'; ReactDOM.render(    &lt;App /&gt;,    document.getElementById('app'));views/app.jsximport React from 'react'; export default class App extends React.Component {  constructor(props) {    super(props);    this.state = {test: 'foo'};  }  render() {    return (&lt;div&gt;        Hello World!&lt;/div&gt;);  }}npm installwebpacknode server4. Add Materialpackage.json\"dependencies\": {  ...  \"material-ui\": \"0.18.1\",  \"react-tap-event-plugin\": \"2.0.1\"},views/index.jsximport React from 'react';import ReactDOM from 'react-dom';import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';import App from './app.jsx'; import injectTapEventPlugin from 'react-tap-event-plugin';injectTapEventPlugin(); ReactDOM.render(  &lt;MuiThemeProvider&gt;    &lt;App /&gt;  &lt;/MuiThemeProvider&gt;,    document.getElementById('app'));views/app.jsximport React from 'react';import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';import FlatButton from 'material-ui/FlatButton'; export default class App extends React.Component {  constructor(props) {    super(props);    this.state = {test: 'foo'};  }  render() {    return (  &lt;Card&gt;    &lt;CardHeader       title=\"Hello Title\"       subtitle=\"Subtitle\"       actAsExpander={true}       showExpandableButton={true}     /&gt;    &lt;CardActions&gt;      &lt;FlatButton label=\"OK\" /&gt;      &lt;FlatButton label=\"CANCEL\" /&gt;    &lt;/CardActions&gt;    &lt;CardText expandable={true}&gt;      Lorem ipsum dolor sit amet, consectetur adipiscing elit.      Donec mattis pretium massa. Aliquam erat volutpat. Nulla facilisi.      Donec vulputate interdum sollicitudin. Nunc lacinia auctor quam sed pellentesque.      Aliquam dui mauris, mattis quis lacus id, pellentesque lobortis odio.    &lt;/CardText&gt;  &lt;/Card&gt;    );  }}CodeHere is the final project content.  views app.jsx index.jsx index.tpl.html  package.json  server.js  webpack.config.jspackage.json{  \"name\": \"20170529-js-react-material-express-setting_up_a_project\",  \"version\": \"1.0.0\",  \"description\": \"JS React Material Express: Setting Up a Project Using Npm, Webpack, Babel\",  \"author\": \"Damien FREMONT\",   \"main\": \"server.js\",  \"scripts\": {    \"start\": \"node server.js\",    \"test\": \"echo \\\"Error: no test specified\\\" &amp;&amp; exit 1\"  },   \"dependencies\": {     \"express\": \"4.13.3\",    \"compression\": \"1.6.0\",     \"react\": \"15.4.2\",    \"react-dom\": \"15.4.2\",     \"babel-core\": \"6.24.1\",     \"material-ui\": \"0.18.1\",    \"react-tap-event-plugin\": \"2.0.1\"  },  \"devDependencies\": {     \"babel-loader\": \"6.4.0\",    \"babel-preset-es2015\":  \"6.24.1\",    \"babel-preset-react\":   \"6.24.1\",    \"babel-preset-stage-1\": \"6.24.1\",     \"webpack\": \"2.6.1\",    \"webpack-dev-server\": \"2.4.5\",     \"html-webpack-plugin\": \"2.28.0\"  }}webpack.config.js'use strict'; var path = require('path');var webpack = require('webpack');var HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = [{  entry: './views/index.jsx',  output: {    path: __dirname + '/public/',    filename: '[name].js',    publicPath: '/'  },  plugins: [    new webpack.optimize.UglifyJsPlugin(),    new HtmlWebpackPlugin({      template: 'views/index.tpl.html',      inject: 'body',      filename: 'index.html'    })  ],  module: {    loaders: [{      test: /\\.jsx?$/,      exclude: /node_modules/,      loader: 'babel-loader',      query: {        \"presets\": [\"react\", \"es2015\"]      }    }]  }}];server.js// Module dependencies.var express = require('express'), compression = require('compression'); // Configurationvar app = express();app.set('port', (process.env.PORT || 5000));app.use(compression());var http = require('http').Server(app); // VIEW Routesapp.use('/', express.static('./public')); // RESTapp.get('/api/status', function (req, res) {  var status = \"ONLINE (v1.0.0)\";  res.send(status);}); // Start servervar server = http.listen(app.get('port'), function(){  var host = server.address().address;  var port = server.address().port;  console.log('Example app listening at http://%s:%s', host, port);});views/index.tpl.html&lt;!doctype html&gt;&lt;html lang=\"en\"&gt;  &lt;head&gt;    &lt;meta charset=\"utf-8\"&gt;    &lt;meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\"&gt;    &lt;title&gt;JS React Material Express&lt;/title&gt;    &lt;meta name=\"description\" content=\"Setting Up a Project Using Npm, Webpack, Babel\"&gt;    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;  &lt;/head&gt;  &lt;body&gt;&lt;div id=\"app\"&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;views/index.jsximport React from 'react';import ReactDOM from 'react-dom';import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';import App from './app.jsx'; import injectTapEventPlugin from 'react-tap-event-plugin';injectTapEventPlugin(); ReactDOM.render(  &lt;MuiThemeProvider&gt;    &lt;App /&gt;  &lt;/MuiThemeProvider&gt;,    document.getElementById('app'));views/app.jsximport React from 'react';import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';import FlatButton from 'material-ui/FlatButton'; export default class App extends React.Component {  constructor(props) {    super(props);    this.state = {test: 'foo'};  }  render() {    return (  &lt;Card&gt;    &lt;CardHeader       title=\"Hello Title\"       subtitle=\"Subtitle\"       actAsExpander={true}       showExpandableButton={true}     /&gt;    &lt;CardActions&gt;      &lt;FlatButton label=\"OK\" /&gt;      &lt;FlatButton label=\"CANCEL\" /&gt;    &lt;/CardActions&gt;    &lt;CardText expandable={true}&gt;      Lorem ipsum dolor sit amet, consectetur adipiscing elit.      Donec mattis pretium massa. Aliquam erat volutpat. Nulla facilisi.      Donec vulputate interdum sollicitudin. Nunc lacinia auctor quam sed pellentesque.      Aliquam dui mauris, mattis quis lacus id, pellentesque lobortis odio.    &lt;/CardText&gt;  &lt;/Card&gt;    );  }}Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170529-js-react-material-express-setting_up_a_projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20170529-js-react-material-express-setting_up_a_projectReferencehttps://www.python.org/downloads/https://www.python.org/downloads/https://facebook.github.io/react/https://facebook.github.io/react/http://www.material-ui.com/#/http://www.material-ui.com/#/https://webpack.js.org/guides/installation/#local-installationhttps://webpack.js.org/guides/installation/#local-installationhttps://github.com/christianalfoni/webpack-express-boilerplatehttps://github.com/christianalfoni/webpack-express-boilerplatehttps://github.com/tahnik/react-express-webpack-babelhttps://github.com/tahnik/react-express-webpack-babelOriginhttps://damienfremont.com/2017/05/29/js-react-material-express-setting-up-a-project-using-npm-webpack-babel/",
        "url": "/2017/05/29/js-react-material-express-setting-up-a-project-using-npm-webpack-babel"
      },
    
      "2017-05-24-some-books-update-2017": {
        "title": "Some Books Update 2017",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Here are some, well known, books that I think are useful for IT projects… in any case, they were for me!",
        "url": "/2017/05/24/some-books-update-2017"
      },
    
      "2017-05-11-javaee-angularjs-bootstrap-tutorials": {
        "title": "Javaee Angularjs Bootstrap Tutorials",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "Here are all my tutorials about JavaEE/AngularJS/Bootstrap, from 2015 to 2016 (it’s time to change for ReactJS).ListJavaEE AngularJS : Web Packaging – Concat – MinifyJavaEE AngularJS : Loading ScreenJavaEE AngularJs: Browser Compatibility AlertJavaEE AngularJs: Browser URLs Cache and VersionJavaEE AngularJS Bootstrap: How to Authent (Basic)JavaEE AngularJS Bootstrap: HowTo Charts with D3JSJavaEE AngularJS Bootstrap: How to Multilingual (i18n, l10n)JavaEE AngularJS Bootstrap: How to Breadcrumb and NavBarJavaEE AngularJS Bootstrap: How to Infinite-ScrollJavaEE AngularJS Bootstrap: How to Sort with Smart-TableJavaEE AngularJS Bootstrap: How to Pagination with Smart-TableJavaEE AngularJS Bootstrap: How to FilteringJavaEE AngularJS Bootstrap: DataTable and Excel ExportJavaEE AngularJS Bootstrap: File UploadJavaEE AngularJS Bootstrap: Date PickerJavaEE AngularJS Bootstrap: Form Bean Validation (front and back)JavaEE AngularJS Bootstrap: Form (Basic: read, post)JavaEE AngularJS Bootstrap: routes, templates, redirection and paramsJavaEE AngularJS Bootstrap: IntegrationOriginhttps://damienfremont.com/2017/05/11/javaee-angularjs-bootstrap-tutorials/",
        "url": "/2017/05/11/javaee-angularjs-bootstrap-tutorials"
      },
    
      "2016-08-20-how-to-silkuli-test-ui-without-programming-advanced": {
        "title": "How To Silkuli Test Ui Without Programming Advanced",
        "author": "",
        "category": "",
        "tags": "python, test",
        "content": "This tutorial show how to organize UI tests and reuse most of your existing usecases elements, like comments and screenshots.Note: see the previous post ‘How to Silkuli - Test UI without programming’ for a quick start.https://damienfremont.com/2016/08/19/how-to-silkuli-test-ui-without-programming/DemoStepsWe will create a two usecase project  Define usecases  Create projects  Create usecase A test  Reuse elements for usecase B  Create usecase B test  Run tests1. Define usecases2. Create projects3. Create usecase A test4. Reuse elements for usecase B5. Create usecase B test6. Run testsFinal WordThe element reuse is not a direct reference to the original screenshot. If you change a button, you’ll need to update all the usecases.Next step will be automation with scripts. Like running all tests at once, using properties andProjecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160820-test-silkuli-ide-advancedReferenceshttp://doc.sikuli.org/keys.htmlOriginhttps://damienfremont.com/2016/08/20/how-to-silkuli-test-ui-without-programming-advanced/",
        "url": "/2016/08/20/how-to-silkuli-test-ui-without-programming-advanced"
      },
    
      "2016-08-19-how-to-silkuli-test-ui-without-programming": {
        "title": "How To Silkuli Test Ui Without Programming",
        "author": "",
        "category": "",
        "tags": "python, test",
        "content": "This tutorial show how to organize UI tests and reuse most of your existing usecases elements, like comments and screenshots.Note: see the previous post ‘How to Silkuli - Test UI without programming’ for a quick start.https://damienfremont.com/2016/08/19/how-to-silkuli-test-ui-without-programming/DemoStepsWe will create a two usecase project  Define usecases  Create projects  Create usecase A test  Reuse elements for usecase B  Create usecase B test  Run tests1. Define usecases2. Create projects3. Create usecase A test4. Reuse elements for usecase B5. Create usecase B test6. Run testsFinal WordThe element reuse is not a direct reference to the original screenshot. If you change a button, you’ll need to update all the usecases.Next step will be automation with scripts. Like running all tests at once, using properties andProjecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160819-test-silkuli-ide-advancedReferenceshttp://doc.sikuli.org/keys.htmlOriginhttps://damienfremont.com/2016/08/20/how-to-silkuli-test-ui-without-programming-advanced/",
        "url": "/2016/08/19/how-to-silkuli-test-ui-without-programming"
      },
    
      "2016-05-22-javaee-angularjs-web-packaging-concat-minify": {
        "title": "Javaee Angularjs Web Packaging Concat Minify",
        "author": "",
        "category": "",
        "tags": "angularjs, css, javascript, java",
        "content": "This tutorial is intended to make a Maven web packaging like NodeJS+Brunch or NodeJS+WebPack. With HTML to JS, Single JS file, Minify. It’s usefull for web release because you’ll to limit the number of HTTP request, have a simple artifact to update, and limit the size of your app.DemoA simple two pages app: 2 templates, 2 controllers.Concat HTML files to single JS fileAll HTML templates files are merged into a single JS file : template.js. Used with require.js. Limiting the number of HTTP requests done by the client (better for mobile network) and doing a better job on handling browser cache than URL to HTML templates.Build it with the default ‘dev’ maven profile.mvn package -P devBeforeAftertemplates.js (generated)/*jshint -W099 */angular.module('templates-main', []).run(['$templateCache', function($templateCache) {    $templateCache.put('/js/page1/page1.html',    \"&lt;div class=\\\"page1\\\" ng-controller=\\\"Page1Ctrl\\\"&gt;\\n\" +    \"  &lt;h2&gt;Page 1&lt;/h2&gt;\\n\" +    \"  &lt;button ng-click=\\\"goToPage2()\\\"&gt;Go to Page 2 &gt;&gt;&lt;/button&gt;\\n\" +    \"&lt;/div&gt;\");    $templateCache.put('/js/page2/page2.html',    \"&lt;div class=\\\"page2\\\" ng-controller=\\\"Page2Ctrl\\\"&gt;\\n\" +    \"  &lt;h2&gt;Page 2&lt;/h2&gt;\\n\" +    \"  &lt;button ng-click=\\\"goToPage1()\\\"&gt;Go to Page 1 &gt;&gt;&lt;/button&gt;\\n\" +    \"&lt;/div&gt;\");}]);index_dev.html&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/angularjs/${angularjs.version}/angular-csp.css\"&gt; &lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/requirejs/${requirejs.version}/require${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route${javascript.min}.js\"&gt;&lt;/script&gt; &lt;!-- YOUR APP --&gt; &lt;!-- YOUR CSS --&gt;&lt;link rel=\"stylesheet\" href=\"css/page1.css?nocache=${project.version}\"&gt;&lt;link rel=\"stylesheet\" href=\"css/page2.css?nocache=${project.version}\"&gt; &lt;!-- YOUR JS --&gt;&lt;script src=\"js/templates.js?nocache=${project.version}\"&gt;&lt;/script&gt;&lt;script src=\"js/app.js?nocache=${project.version}\"&gt;&lt;/script&gt;&lt;script src=\"js/page1/page1.js?nocache=${project.version}\"&gt;&lt;/script&gt;&lt;script src=\"js/page2/page2.js?nocache=${project.version}\"&gt;&lt;/script&gt; &lt;/head&gt;&lt;body ng-app=\"myapp\"&gt;&lt;div class=\"container\"&gt;   &lt;h1&gt;Packaging&lt;/h1&gt;   &lt;!-- MAIN CONTENT --&gt;  &lt;div class=\"view-animate\" ng-view &gt;&lt;/div&gt; &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;Concat JS ans CSS Files to single Minimize fileAll JS files (included templates.js) are merged into a single file. Then the same is done with CSS files. Limiting the number of HTTP requests done by the client (better for mobile network).Build it with the ‘prod’ maven profile.mvn package -P prodBeforeAfterWarning: You’ll need to write angular files in a certain way, in order to be compatible with minification.Before: global app var, simple injection  var app = angular.module…  app.controller…  …Ctrl’, function(…var app = angular.module('myapp', [ //'ngResource', //'ngRoute', //'templates-main' //]);...app.controller('Page2Ctrl', function($scope, $location) {  ...});Now: global module, injection with array before function  angular.module…  angular.module(…).controller…  …Ctrl’, [ “$scope”, …, function(…angular.module('myapp', [ //'ngResource', //'ngRoute', //'templates-main' //]);...angular.module('myapp').controller('Page2Ctrl', [ \"$scope\", \"$location\", function($scope, $location) {  ...} ]);index_prod.html&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/angularjs/${angularjs.version}/angular-csp.css\"&gt; &lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/requirejs/${requirejs.version}/require${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route${javascript.min}.js\"&gt;&lt;/script&gt; &lt;!-- YOUR APP --&gt;&lt;link rel=\"stylesheet\" href=\"css/style.min.css?nocache=${project.version}\"&gt;&lt;script src=\"js/script.min.js?nocache=${project.version}\"&gt;&lt;/script&gt; &lt;/head&gt;&lt;body ng-app=\"myapp\"&gt;&lt;div class=\"container\"&gt;   &lt;h1&gt;Packaging&lt;/h1&gt;   &lt;!-- MAIN CONTENT --&gt;  &lt;div class=\"view-animate\" ng-view &gt;&lt;/div&gt; &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;ProjectSourcepom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160522-javaee-angularjs-webpackaging_min_single_file&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;requirejs.version&gt;2.2.0&lt;/requirejs.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- WEB DEPENDENCIES MANAGER --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB DEPENDENCIES --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;requirejs&lt;/artifactId&gt;      &lt;version&gt;${requirejs.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;       &lt;!-- REPLACE KEYS IN FILES (ECLIPSE IDE) --&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.html&lt;/include&gt;          &lt;include&gt;WEB-INF/web.xml&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;!-- REPLACE KEYS IN FILES (BUILD) --&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.html&lt;/include&gt;                &lt;include&gt;WEB-INF/web.xml&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;!-- HTML TO JS (BUILD) --&gt;      &lt;plugin&gt;        &lt;groupId&gt;com.keithbranton.mojo&lt;/groupId&gt;        &lt;artifactId&gt;angular-maven-plugin&lt;/artifactId&gt;        &lt;version&gt;0.3.4&lt;/version&gt;        &lt;executions&gt;          &lt;execution&gt;            &lt;phase&gt;generate-resources&lt;/phase&gt;            &lt;goals&gt;              &lt;goal&gt;html2js&lt;/goal&gt;            &lt;/goals&gt;          &lt;/execution&gt;        &lt;/executions&gt;        &lt;configuration&gt;          &lt;sourceDir&gt;${basedir}/src/main/webapp/js/&lt;/sourceDir&gt;          &lt;angularDependency&gt;angular&lt;/angularDependency&gt;          &lt;include&gt;**/*.html&lt;/include&gt;          &lt;exclude&gt;index*.html&lt;/exclude&gt;          &lt;target&gt;${basedir}/src/main/webapp/js/templates.js&lt;/target&gt;          &lt;addRequireWrapper&gt;false&lt;/addRequireWrapper&gt;          &lt;prefix&gt;/js&lt;/prefix&gt;          &lt;multiModule&gt;false&lt;/multiModule&gt;          &lt;preambles&gt;            &lt;preamble&gt;/*jshint -W099 */&lt;/preamble&gt;          &lt;/preambles&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;!-- ASSEMBLE AND MINIFY --&gt;      &lt;plugin&gt;        &lt;groupId&gt;com.samaxes.maven&lt;/groupId&gt;        &lt;artifactId&gt;minify-maven-plugin&lt;/artifactId&gt;        &lt;version&gt;1.7.4&lt;/version&gt;        &lt;executions&gt;          &lt;execution&gt;            &lt;id&gt;default-minify&lt;/id&gt;            &lt;goals&gt;              &lt;goal&gt;minify&lt;/goal&gt;            &lt;/goals&gt;            &lt;configuration&gt;              &lt;charset&gt;UTF-8&lt;/charset&gt;              &lt;cssSourceIncludes&gt;                &lt;cssSourceInclude&gt;**/*.css&lt;/cssSourceInclude&gt;              &lt;/cssSourceIncludes&gt;              &lt;cssSourceExcludes&gt;                &lt;cssSourceExclude&gt;**/*.min.css&lt;/cssSourceExclude&gt;              &lt;/cssSourceExcludes&gt;              &lt;jsSourceIncludes&gt;                &lt;jsSourceInclude&gt;**/app.js&lt;/jsSourceInclude&gt;                &lt;jsSourceInclude&gt;**/template.js&lt;/jsSourceInclude&gt;                &lt;jsSourceInclude&gt;**/**/*.*js&lt;/jsSourceInclude&gt;              &lt;/jsSourceIncludes&gt;              &lt;jsEngine&gt;CLOSURE&lt;/jsEngine&gt;              &lt;jsFinalFile&gt;&lt;/jsFinalFile&gt;            &lt;/configuration&gt;          &lt;/execution&gt;        &lt;/executions&gt;      &lt;/plugin&gt;     &lt;/plugins&gt;    &lt;pluginManagement&gt;      &lt;plugins&gt;        &lt;!-- HTML TO JS (FOR ECLIPSE IDE) --&gt;        &lt;plugin&gt;          &lt;groupId&gt;org.eclipse.m2e&lt;/groupId&gt;          &lt;artifactId&gt;lifecycle-mapping&lt;/artifactId&gt;          &lt;version&gt;1.0.0&lt;/version&gt;          &lt;configuration&gt;            &lt;lifecycleMappingMetadata&gt;              &lt;pluginExecutions&gt;                &lt;pluginExecution&gt;                  &lt;pluginExecutionFilter&gt;                    &lt;groupId&gt;com.keithbranton.mojo&lt;/groupId&gt;                    &lt;artifactId&gt;angular-maven-plugin&lt;/artifactId&gt;                    &lt;versionRange&gt;[0.1-SNAPSHOT,)&lt;/versionRange&gt;                    &lt;goals&gt;                      &lt;goal&gt;html2js&lt;/goal&gt;                    &lt;/goals&gt;                  &lt;/pluginExecutionFilter&gt;                  &lt;action&gt;                    &lt;execute&gt;                      &lt;runOnIncremental&gt;true&lt;/runOnIncremental&gt;                    &lt;/execute&gt;                  &lt;/action&gt;                &lt;/pluginExecution&gt;              &lt;/pluginExecutions&gt;            &lt;/lifecycleMappingMetadata&gt;          &lt;/configuration&gt;        &lt;/plugin&gt;      &lt;/plugins&gt;    &lt;/pluginManagement&gt;  &lt;/build&gt;  &lt;profiles&gt;    &lt;profile&gt;           &lt;!-- NO ASSEMBLY, NO MINIFIY, NO CACHE --&gt;      &lt;id&gt;dev&lt;/id&gt;      &lt;activation&gt;        &lt;activeByDefault&gt;true&lt;/activeByDefault&gt;      &lt;/activation&gt;      &lt;properties&gt;        &lt;profile.id&gt;dev&lt;/profile.id&gt;        &lt;javascript.min&gt;&lt;/javascript.min&gt;        &lt;webjars.disablecache&gt;true&lt;/webjars.disablecache&gt;      &lt;/properties&gt;    &lt;/profile&gt;    &lt;profile&gt;           &lt;!-- ASSEMBLY, MINIFIY, NOCACHE --&gt;      &lt;id&gt;prod&lt;/id&gt;      &lt;properties&gt;        &lt;profile.id&gt;prod&lt;/profile.id&gt;        &lt;javascript.min&gt;.min&lt;/javascript.min&gt;        &lt;webjars.disablecache&gt;false&lt;/webjars.disablecache&gt;      &lt;/properties&gt;    &lt;/profile&gt;  &lt;/profiles&gt;&lt;/project&gt;page1.css.page1 {  color: green;}page2.css.page2 {  color: orange;}index_dev.html&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/angularjs/${angularjs.version}/angular-csp.css\"&gt; &lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/requirejs/${requirejs.version}/require${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route${javascript.min}.js\"&gt;&lt;/script&gt; &lt;!-- YOUR APP --&gt; &lt;!-- YOUR CSS --&gt;&lt;link rel=\"stylesheet\" href=\"css/page1.css?nocache=${project.version}\"&gt;&lt;link rel=\"stylesheet\" href=\"css/page2.css?nocache=${project.version}\"&gt; &lt;!-- YOUR JS --&gt;&lt;script src=\"js/templates.js?nocache=${project.version}\"&gt;&lt;/script&gt;&lt;script src=\"js/app.js?nocache=${project.version}\"&gt;&lt;/script&gt;&lt;script src=\"js/page1/page1.js?nocache=${project.version}\"&gt;&lt;/script&gt;&lt;script src=\"js/page2/page2.js?nocache=${project.version}\"&gt;&lt;/script&gt; &lt;/head&gt;&lt;body ng-app=\"myapp\"&gt;&lt;div class=\"container\"&gt;   &lt;h1&gt;Packaging&lt;/h1&gt;   &lt;!-- MAIN CONTENT --&gt;  &lt;div class=\"view-animate\" ng-view &gt;&lt;/div&gt; &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;index_prod.html&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/angularjs/${angularjs.version}/angular-csp.css\"&gt; &lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/requirejs/${requirejs.version}/require${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource${javascript.min}.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route${javascript.min}.js\"&gt;&lt;/script&gt; &lt;!-- YOUR APP --&gt;&lt;link rel=\"stylesheet\" href=\"css/style.min.css?nocache=${project.version}\"&gt;&lt;script src=\"js/script.min.js?nocache=${project.version}\"&gt;&lt;/script&gt; &lt;/head&gt;&lt;body ng-app=\"myapp\"&gt;&lt;div class=\"container\"&gt;   &lt;h1&gt;Packaging&lt;/h1&gt;   &lt;!-- MAIN CONTENT --&gt;  &lt;div class=\"view-animate\" ng-view &gt;&lt;/div&gt; &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;app.js'use strict'; angular.module('myapp', [ //'ngResource', //'ngRoute', //'templates-main' //]) // CONFIG.config([ \"$routeProvider\", function($routeProvider) {   // ROUTE  $routeProvider   // PAGE1  .when('/page1', {    templateUrl : '/js/page1/page1.html',    controller : 'Page1Ctrl'  })  // PAGE 2  .when('/page2', {    templateUrl : '/js/page2/page2.html',    controller : 'Page2Ctrl'  })  // DEFAULT  .otherwise('/page1');} ]);page1.html&lt;div class=\"page1\" ng-controller=\"Page1Ctrl\"&gt;  &lt;h2&gt;Page 1&lt;/h2&gt;  &lt;button ng-click=\"goToPage2()\"&gt;Go to Page 2 &gt;&gt;&lt;/button&gt;&lt;/div&gt;page1.jsangular.module('myapp') .controller('Page1Ctrl', [ \"$scope\", \"$location\", function($scope, $location) {  $scope.goToPage2 = function() {    $location.path('/page2');  }} ]);page2.html&lt;div class=\"page2\" ng-controller=\"Page2Ctrl\"&gt;  &lt;h2&gt;Page 2&lt;/h2&gt;  &lt;button ng-click=\"goToPage1()\"&gt;Go to Page 1 &gt;&gt;&lt;/button&gt;&lt;/div&gt;page2.jsangular.module('myapp') .controller('Page2Ctrl', [ \"$scope\", \"$location\", function($scope, $location) {  $scope.goToPage1 = function() {    $location.path('/page1');  }} ]);web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"  version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;${webjars.disablecache}&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;welcome-file-list&gt;    &lt;welcome-file&gt;index_${profile.id}.html&lt;/welcome-file&gt;  &lt;/welcome-file-list&gt; &lt;/web-app&gt;ConclusionNot so easy to build. Very complex lifecycle. Not as good as NodeJS builds, but doing the job.You’ll need it if you intend to deploy a web app. But for intranet apps, you don’t.For big projects: use nodejs build for front-end, and maven for back-end.Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160522-javaee-angularjs-webpackaging_min_single_filehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160522-javaee-angularjs-webpackaging_min_single_fileReferenceshttps://github.com/keithbranton/angular-maven-pluginhttps://github.com/keithbranton/angular-maven-pluginhttps://github.com/samaxes/minify-maven-pluginhttps://github.com/samaxes/minify-maven-pluginhttp://maven.apache.org/plugins/maven-dependency-plugin/examples/unpacking-artifacts.htmlhttp://maven.apache.org/plugins/maven-dependency-plugin/examples/unpacking-artifacts.htmlhttp://stackoverflow.com/questions/35784489/angular-javascript-minification-cause-error-injectormodulerr-module-errorhttp://stackoverflow.com/questions/35784489/angular-javascript-minification-cause-error-injectormodulerr-module-errorOriginhttps://damienfremont.com/2016/05/22/javaee-angularjs-web-packaging-concat-minify/ ",
        "url": "/2016/05/22/javaee-angularjs-web-packaging-concat-minify"
      },
    
      "2016-05-09-how-to-cucumber-test-report-plugin-2-with-maven-and-java": {
        "title": "How To Cucumber Test Report Plugin 2 With Maven And Java",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, junit, test",
        "content": "It is often useful to show the results of our tests to others people who are not developers, like managers or executive. This tutorial shows how to integrate a Cucumber reporting a Java plugin in Maven project. The result is a simple web page, which does not require a special tool to be read.This tutorial will cover 3 reports plugins : JSON, HTML Pretty and Cucumber Report 2.Native JSON ResultHow to:pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160509-test-cucumber_plugin_reporting_2&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;jar&lt;/packaging&gt;  &lt;properties&gt;    &lt;cucumber.version&gt;1.2.5&lt;/cucumber.version&gt;    &lt;java.version&gt;8&lt;/java.version&gt;  &lt;/properties&gt;  &lt;dependencies&gt;    &lt;dependency&gt;      &lt;groupId&gt;info.cukes&lt;/groupId&gt;      &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;      &lt;version&gt;${cucumber.version}&lt;/version&gt;      &lt;scope&gt;test&lt;/scope&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;info.cukes&lt;/groupId&gt;      &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;      &lt;version&gt;${cucumber.version}&lt;/version&gt;      &lt;scope&gt;test&lt;/scope&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;build&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.3&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;        &lt;version&gt;2.18.1&lt;/version&gt;        &lt;configuration&gt;          &lt;testFailureIgnore&gt;true&lt;/testFailureIgnore&gt;          &lt;includes&gt;            &lt;exclude&gt;**/*BDDTest.java&lt;/exclude&gt;          &lt;/includes&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;RunBDDTest.javapackage com.damienfremont.blog; import org.junit.runner.RunWith;import cucumber.api.CucumberOptions;import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class)@CucumberOptions(strict = false, features = \"features\", format = { \"pretty\",    \"json:target/cucumber.json\" }, tags = { \"~@ignore\" })public class RunBDDTest { }Demo:Launch with JUnit ormvn testThe result is at /target/cucumber.jsonNative HTML PluginHow to:RunBDDTest.javapackage com.damienfremont.blog; import org.junit.runner.RunWith;import cucumber.api.CucumberOptions;import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class)@CucumberOptions(strict = false, features = \"features\", format = { \"pretty\",    \"html:target/site/cucumber-pretty\",    \"json:target/cucumber.json\" }, tags = { \"~@ignore\" })public class RunBDDTest { }Demo:Launch with JUnit ormvn testThe result is at /target/site/cucumber-pretty/index.htmlCucumber-Reports HTML PluginHow to:pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160509-test-cucumber_plugin_reporting_2&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;jar&lt;/packaging&gt;  &lt;properties&gt;    &lt;cucumber.version&gt;1.2.5&lt;/cucumber.version&gt;    &lt;java.version&gt;8&lt;/java.version&gt;  &lt;/properties&gt;  &lt;dependencies&gt;    &lt;dependency&gt;      &lt;groupId&gt;info.cukes&lt;/groupId&gt;      &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;      &lt;version&gt;${cucumber.version}&lt;/version&gt;      &lt;scope&gt;test&lt;/scope&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;info.cukes&lt;/groupId&gt;      &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;      &lt;version&gt;${cucumber.version}&lt;/version&gt;      &lt;scope&gt;test&lt;/scope&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;build&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.3&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;        &lt;version&gt;2.18.1&lt;/version&gt;        &lt;configuration&gt;          &lt;testFailureIgnore&gt;true&lt;/testFailureIgnore&gt;          &lt;includes&gt;            &lt;exclude&gt;**/*BDDTest.java&lt;/exclude&gt;          &lt;/includes&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;net.masterthought&lt;/groupId&gt;        &lt;artifactId&gt;maven-cucumber-reporting&lt;/artifactId&gt;        &lt;version&gt;2.0.0&lt;/version&gt;        &lt;executions&gt;          &lt;execution&gt;            &lt;id&gt;execution&lt;/id&gt;            &lt;phase&gt;verify&lt;/phase&gt;            &lt;goals&gt;              &lt;goal&gt;generate&lt;/goal&gt;            &lt;/goals&gt;            &lt;configuration&gt;              &lt;projectName&gt;cucumber-jvm-example&lt;/projectName&gt;              &lt;outputDirectory&gt;${project.build.directory}/site/cucumber-reports&lt;/outputDirectory&gt;              &lt;cucumberOutput&gt;${project.build.directory}/cucumber.json&lt;/cucumberOutput&gt;              &lt;skippedFails&gt;true&lt;/skippedFails&gt;              &lt;enableFlashCharts&gt;false&lt;/enableFlashCharts&gt;              &lt;buildNumber&gt;42&lt;/buildNumber&gt;            &lt;/configuration&gt;          &lt;/execution&gt;        &lt;/executions&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;RunBDDTest.javapackage com.damienfremont.blog; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions;import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class)@CucumberOptions(strict = false, features = \"features\", format = { \"pretty\",    \"json:target/cucumber.json\" }, tags = { \"~@ignore\" })public class RunBDDTest { }Demo:Launch withmvn test verifyThe result is at /target/site/cucumber-reports/feature-overview.htmlConclusionJSON is OK for integration with other tools (jenkins plugin, reports, etc).Pretty HTML is OK during development phase (like a JUnit or Surefire report for versionning).Cucumber-Reports is good for reporting outside of the dev team (like managers).Sourcehttps://damienfremont.com/2016/05/09/how-to-cucumber-test-report-plugin-2-with-maven-and-javahttps://damienfremont.com/2016/05/09/how-to-cucumber-test-report-plugin-2-with-maven-and-javahttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160509-test-cucumber_plugin_reporting_2https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160509-test-cucumber_plugin_reporting_2Referenceshttps://cucumber.io/docs/reference/jvmhttps://cucumber.io/docs/reference/jvmhttps://github.com/masterthought/cucumber-reportinghttps://github.com/masterthought/cucumber-reportinghttp://www.masterthought.net/section/cucumber-reportinghttp://www.masterthought.net/section/cucumber-reportingOriginhttps://damienfremont.com/2016/05/09/how-to-cucumber-test-report-plugin-2-with-maven-and-java/",
        "url": "/2016/05/09/how-to-cucumber-test-report-plugin-2-with-maven-and-java"
      },
    
      "2016-01-18-javaee-angularjs-loading-screen": {
        "title": "Javaee Angularjs Loading Screen",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript",
        "content": "A simple way to handle loading screen before javascript kick-in, rely on ng-if.DemoSourcepom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160118-javaee-angularjs-loading_screen&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;   &lt;packaging&gt;war&lt;/packaging&gt;  &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;  &lt;/properties&gt;  &lt;dependencies&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;index.html&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;     &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;app.js&lt;/include&gt;                &lt;include&gt;index.html&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;app.js'use strict'; angular.module('app', []); angular.module('app').controller('ExampleCtrl', function($scope) {    $scope.message = 'Loaded!';});index.html&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;body&gt;   &lt;!-- LOADING SCREEN--&gt;  &lt;div class=\"m-app-loading\" ng-if=\"false\"&gt;    &lt;!--      HACKY CODE WARNING: I'm putting Style block inside directive so that it      will be removed from the DOM when we remove the directive container.    --&gt;    &lt;style type=\"text/css\"&gt;      .m-app-loading .spinner {        width: 30%;        max-width: 100px;        height: 30%;        max-height: 100px;      }      div.m-app-loading {        position: fixed ;      }      div.m-app-loading div.animated-container {        background-color: #FFFFFF ;        bottom: 0px ;        left: 0px ;        opacity: 1.0 ;        position: fixed ;        right: 0px ;        top: 0px ;        z-index: 999999 ;      }      div.m-app-loading div.messaging {        color:  #2089B6;        left: 0px ;        margin-top: -37px ;        position: absolute ;        right: 0px ;        text-align: center ;        top: 40% ;      }      div.m-app-loading h1 {        font-size: 26px ;        line-height: 35px ;        margin: 0px 0px 20px 0px ;      }    &lt;/style&gt;    &lt;!-- BEGIN: Actual animated container. --&gt;    &lt;div class=\"animated-container\" ng-class=\"ng-leave\"&gt;      &lt;div class=\"messaging\"&gt;        &lt;h1&gt;          MY APP        &lt;/h1&gt;         &lt;img class=\"spinner\" src=\"img/loading-blue.gif\"&gt;      &lt;/div&gt;    &lt;/div&gt;    &lt;!-- END: Actual animated container. --&gt;  &lt;/div&gt;   &lt;!-- VIEW/PAGE --&gt;  &lt;div ng-controller=\"ExampleCtrl\"&gt;    Loading...  &lt;/div&gt;   &lt;!-- YOUR JS 2nd --&gt;  &lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;  &lt;script src=\"app.js?version=${project.version}\"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;     &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160118-javaee-angularjs-loading_screenhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160118-javaee-angularjs-loading_screenReferenceshttp://www.bennadel.com/blog/2758-creating-a-pre-bootstrap-loading-screen-in-angularjs.htmhttp://www.bennadel.com/blog/2758-creating-a-pre-bootstrap-loading-screen-in-angularjs.htmJavaEE AngularJS : Loading ScreenJavaEE AngularJS : Loading ScreenOriginhttps://damienfremont.com/2016/01/18/javaee-angularjs-loading-screen/",
        "url": "/2016/01/18/javaee-angularjs-loading-screen"
      },
    
      "2016-01-17-javaee-angularjs-browser-compatibility-alert": {
        "title": "Javaee Angularjs Browser Compatibility Alert",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript",
        "content": "An example of alert in case of client side incompatible browser, like IE8. On others browsers like Chrome, FF or Safari, it will not popup.DemoOn IE11 Browser.Now change your compatibility to IE8 after F12.On IE8 Browser.On Edge Browser.On Chrome Browser.Sourcepom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160117-javaee-angularjs-browser_compatibility_alert&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;   &lt;packaging&gt;war&lt;/packaging&gt;  &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;  &lt;/properties&gt;  &lt;dependencies&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;index.html&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;     &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;app.js&lt;/include&gt;                &lt;include&gt;index.html&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;app.js'use strict'; angular.module('app', []); angular.module('app').controller('ExampleCtrl', function($scope) {    $scope.message = 'Loaded!';});index.html&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- YOUR CSS --&gt;&lt;!--[if gte IE 9]&gt;  &lt;link rel=\"stylesheet\" href=\"css/main.css?version=${project.version}\"&gt;&lt;![endif]--&gt;&lt;/head&gt;&lt;body&gt; &lt;!-- BROWSER COMPATIBILITY ALERT --&gt;&lt;!--[if lte IE 8]&gt;&lt;style type=\"text/css\"&gt;.ie8-alert {  padding-top: 20%;  padding: 20%;  background-color: #FDF2AB;  height: 100%;  widht: 100%;  margin: 0px;}.ie8-alert a {  color: #fff;  background-color: #0370ea;  font-size: 13px;  font-weight: 700;  line-height: 1.3;  display: inline-block;  padding: 6px 12px;  margin: 6px 12px;}&lt;/style&gt;&lt;div class=\"ie8-alert\"\"&gt;  &lt;p&gt;    &lt;img src=\"img/browsers/dialog-warning.gif\"/&gt;    Your browser (Internet Explorer 8) is out of date.    It has known security flaws and may not display all    features of this and other websites.    &lt;strong&gt;Please use another Internet Browser like Firefox, Chrome or InternetExplorer10&lt;/strong&gt;.  &lt;/p&gt;  &lt;p&gt;    &lt;a href=\"https://browser-update.org/en/update.html\"&gt;      Learn how to update your browser    &lt;/a&gt;  &lt;/p&gt;&lt;/div&gt;&lt;![endif]--&gt; &lt;!-- YOUR PAGE AND JS 2nd --&gt;&lt;!--[if IE]&gt;&lt;![if gte IE 9]&gt;&lt;![endif]--&gt;   &lt;div ng-controller=\"ExampleCtrl\"&gt;    Loading...  &lt;/div&gt;   &lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;  &lt;script src=\"app.js?version=${project.version}\"&gt;&lt;/script&gt;&lt;!--[if IE]&gt;&lt;![endif]&gt;&lt;![endif]--&gt;&lt;/body&gt;&lt;/html&gt;web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;     &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160117-javaee-angularjs-browser_compatibility_alerthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160117-javaee-angularjs-browser_compatibility_alertReferenceshttp://www.impressivewebs.com/conditional-comments/http://www.impressivewebs.com/conditional-comments/Originhttps://damienfremont.com/2016/01/17/javaee-angularjs-browser-compatibility-alert/",
        "url": "/2016/01/17/javaee-angularjs-browser-compatibility-alert"
      },
    
      "2016-01-09-javaee-angularjs-browser-urls-cache-and-version": {
        "title": "Javaee Angularjs Browser Urls Cache And Version",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript",
        "content": "This tutorial provides a way for the browser to manage different versions of the same resource.Because new version of your website is deployed, especially with a rich client, you may encounter some issues, like browser caching (ex: you have updated your-lib.js, but some users still experienced the old lib behavior : it’s caused by browser cache on this file, they still have the old version and CTRL+F5 keys do not always resolves this).DemoYou need Eclipse, Maven, Tomcat.There are two parts: the vendor URLs version (like angular.js) and your app URLs version (like  app.js, home.html, main.css).You can update versions in pom.xml.And after restarting the app server, the URLs have changed.Details of vendor URLs version (like angular.js):pom.xml: versionindex.html: urlbrowser: real worldDetails of webapp URLs version (like app.js):Sourcepom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160109-javaee-angularjs-browser_url_version_cache&lt;/artifactId&gt;     &lt;!-- APP VERSION (USED FOR CACHE) --&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;     &lt;packaging&gt;war&lt;/packaging&gt;  &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;         &lt;!-- WEB JAR VERSION (USED FOR CACHE) --&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;       &lt;/properties&gt;  &lt;dependencies&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;index.html&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;     &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;configuration&gt;                     &lt;!-- REPLACE ALL FOR WEBJARS URLS --&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;app.js&lt;/include&gt;                &lt;include&gt;index.html&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;app.js'use strict'; angular.module('app', [ 'ngRoute' ]) // CONFIG .config(function($routeProvider) {     var version = '?nocache=${project.version}';     // ROUTE: URLs  $routeProvider  // HOME  .when('/home', {    templateUrl : 'modules/home/home.html'+version  })  // DEFAULT  .otherwise('/home');});main.cssh2 {    color: grey;}index.html&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- APP CSS--&gt;&lt;link rel=\"stylesheet\" href=\"css/main.css?version=${project.version}\"&gt; &lt;/head&gt;&lt;body&gt;     &lt;!-- VIEW/PAGE --&gt;    &lt;div ng-view&gt;Loading...&lt;/div&gt;             &lt;!-- LIBS JS --&gt;    &lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;    &lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;     &lt;!-- APP JS --&gt;    &lt;script src=\"app.js?version=${project.version}\"&gt;&lt;/script&gt;    &lt;script src=\"modules/home/home.js?version=${project.version}\"&gt;&lt;/script&gt; &lt;/body&gt;&lt;/html&gt;home.html&lt;div ng-controller=\"HomeCtrl\"&gt;  &lt;h2&gt;This is home&lt;/h2&gt;  &lt;p&gt;&lt;/p&gt;&lt;/div&gt;home.js'use strict'; angular.module('app') // .controller('HomeCtrl', function($scope) {  $scope.message = 'Nothing is like home.';});web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;     &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160109-javaee-angularjs-browser_url_version_cachehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160109-javaee-angularjs-browser_url_version_cacheOriginhttps://damienfremont.com/2016/01/09/javaee-angularjs-browser-urls-cache-and-version/",
        "url": "/2016/01/09/javaee-angularjs-browser-urls-cache-and-version"
      },
    
      "2016-01-08-maven-project-with-embedded-repository": {
        "title": "Maven Project With Embedded Repository",
        "author": "",
        "category": "",
        "tags": "java, quicktip",
        "content": "Use this when : a dependency is not available on a public Maven repository and you need your project portable (ex: unreachable repository), or it’s not a maven dependency at all (ex: proprietary IBM jars)Warning: It is not recommended that you store your JARs in CVS. See the folowing page:https://maven.apache.org/guides/introduction/introduction-to-repositories.htmlhttps://maven.apache.org/guides/introduction/introduction-to-repositories.htmlDemoYou’ll need Eclipse, Maven, Java.Two jars are embedded in the project. One in a system path way like Ant, and the other like an embedded Maven repo. The second solution is the better, because it looks like a maven repo and integrate easly in Maven lifecycle and plugins (versus systemPath where it’s not easy to embedded the jar in the final app, like a war).No compile error here: you can use these jars.Sourcepom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20160108-maven-project_embedded_repo&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;jar&lt;/packaging&gt;  &lt;dependencies&gt;     &lt;!-- METHOD 1: SYSTEM PATH --&gt;     &lt;dependency&gt;      &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;      &lt;artifactId&gt;hamcrest-core-1.3.jar&lt;/artifactId&gt;      &lt;version&gt;1.3&lt;/version&gt;      &lt;scope&gt;system&lt;/scope&gt;      &lt;systemPath&gt;${project.basedir}/libs1/hamcrest-core-1.3.jar&lt;/systemPath&gt;    &lt;/dependency&gt;     &lt;!-- METHOD 2: LOCAL REPO --&gt;     &lt;dependency&gt;      &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;      &lt;artifactId&gt;commons-csv&lt;/artifactId&gt;      &lt;version&gt;1.2&lt;/version&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;repositories&gt;    &lt;repository&gt;      &lt;id&gt;in-project&lt;/id&gt;      &lt;name&gt;In Project Repo&lt;/name&gt;      &lt;url&gt;file://${project.basedir}/libs2&lt;/url&gt;    &lt;/repository&gt;  &lt;/repositories&gt;&lt;/project&gt;TestDependencies.javapackage com.damienfremont.blog; import org.apache.commons.csv.CSVFormat;import org.hamcrest.BaseMatcher; public class TestDependencies {   // TEST METHOD 1: SYSTEM PATH  BaseMatcher&lt;?&gt; test1;   // TEST METHOD 2: LOCAL REPO  CSVFormat test2;}Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160108-maven-project_embedded_repohttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20160108-maven-project_embedded_repoReferenceshttps://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#System_Dependencieshttps://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#System_Dependencieshttps://maven.apache.org/guides/introduction/introduction-to-repositories.htmlhttps://maven.apache.org/guides/introduction/introduction-to-repositories.htmlOriginhttps://damienfremont.com/2016/01/08/maven-project-with-embedded-repository/",
        "url": "/2016/01/08/maven-project-with-embedded-repository"
      },
    
      "2015-12-03-developpeur-freelance-en-2015-la-routine-les-missions-23": {
        "title": "Developpeur Freelance En 2015 La Routine Les Missions 23",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Suite du post Développeur freelance en 2015 : se lancer (1/3), autour des missions et de la paperasse quotidienne.Rappel: pensez à souscrire à une AGA avant de passer à la suite!6. La rechercheLes moyensLe réseau : faites savoir à vos collègues et anciens collègues que vous passez freelance. N’hésitez pas non plus à contacter les commerciaux de vos anciennes missions, même la SSII que vous quittez proposera du travaille.Les outils : Freelance-info principalement, dans une moindre mesure Viadeo.http://www.freelance-info.fr/http://www.freelance-info.fr/http://fr.viadeo.com/fr/http://fr.viadeo.com/fr/http://fr.linkedin.com/http://fr.linkedin.com/Il est même possible de rester dans votre mission actuelle et de passer Freelance en étant “porté” par votre SSII actuelle (mais ça fait long la mission après).Exemple : dans mon cas c’est un collègue qui m’a fait passer des missions provenant de ma 1ere boite (merci Franck)!Le contactPrivilégier les SSII de confiance (stable ou importante par exemple). Eviter les mauvais payeurs et ceux qui payent systématiquement en retard. Voir même pas du tout en cas de faillite.Exemple : contacte pour une mission, demander :– le nom du client ou au moins le contexte métier (quel service, etc.)– les grandes lignes du projet,– le rôle attendu (chef de projet, etc.)– la durée estimée de la mission– la date de démarrage espérée– le tarif cible ou le budget client7. La rencontre avec la SSIINégociationLe taux journalier demandé : rester ferme, il ne s’agit pas de courir à la faillite ni de démarrer la mission avec un arrière goût de défaite et encore moins de la quitter pour cette raison.Le taux journalier final : demander un droit de regard, cela donne une indication sur la transparence de la SSII  et permet de savoir combien vous valez réellement (utile pour la prochaine mission).La SSII prendra en général 12-20% de commission sur la prestation. Au delà demandez-vous si vous ne vous êtes pas sous-estimé (d’autres crierons au vol, mais c’est plus une erreur de négociation à la base ou alors votre commercial à du talent auprès du client final).Exemple : pour 500€ facturé par le freelance, c’est 570€ facturé chez le client. Ce qui fait 14% pour la SSII.TransparenceLe client final doit savoir que vous êtes freelance et non salarié de la SSII. Par contre au quotidien cela peut être différent (à voir entre vous, le client et la SSII intermédiaire s’il y a).8. Le contrat de prestationPréavisAttention, il doit être réciproque entre les 2 partis (vous et SSII). Idéalement 30 jours.Paiement  Attention aux frais caché de fin d’année  Attention à la date de paiement &lt;60 joursExemple : l’idéal reste un préavis réciproque de 1 mois (un départ trop long diminue la productivité/moral et fait retomber dans les contraintes d’un salarié) et une date de paiement à 30 jrs max, sans frais de fin d’année.Documents demandés (tous les 3 mois)  Equivalent du KBIS en EIhttp://avis-situation-sirene.insee.fr/avisitu/http://avis-situation-sirene.insee.fr/avisitu/  Attestation de vigilance Urssaf à jourhttp://www.urssaf.fr/http://www.urssaf.fr/ATTENTION au délai, la procédure de création en ligne fonctionne mal (numéro TI à taille fixe par injection de 0 à la place d’espace …bref) et le mot de passe sera reçu par courrier.  Attestation de non emploi de travailleurs étrangersGouv.fr ne fournit pas de modèle (merci…) mais vous pouvez en trouver sur le net  La société n’emploie pas de salariés étrangers entrant dans le cadre des articles D8254-2 et L522L-2 du code du travail      Dans le cas où cette situation changerait, la société s’engage lors du renouvellement des documents obligatoires imposé par l’article L.8222-L du code du travail à déclarer ses salariés étrangers dans les conditions établies par les articles D8254-2 etL522L-2 du code du travail.    D’établir une attestation ou un certificat faisant état de faits matériellement inexacts  De falsifier une attestation ou un certificat originairement sincère  De faire usage d’une attestation ou d’un certificat inexact ou falsifié.Exemple de tampon/cachet (à fabriquer-coller avec Paint, pas la peine d’en commander un, ni de s’embêter plus que ça).9. La routine en missionRien ne change par rapport à avant, on retrouve le CRA mensuelFrais de bouche (journalier ou annuel)Deux options sont possible : le réel ou le forfait.  Forfait: en fin d’année, vous compterez le nombre de jours  Réel: journalier, il faut demander et conserver toutes les factures papier avec TVA de vos repas, qui représenteront 80% de votre comptabilité annuelle.Comment choisir? Si vous ne manger pas/chez vous le midi ou que vous voulez vous simplifier la compta: forfait. Si vous repas sont pris dans un restaurant ou self: réel.CRA (journalier)Le Compte-Rendu-d’Activité, dont le but est de compter les jours.A faire signer par votre client à la fin de chaque mois. Il peut venir de différents acteurs: parfois c’est le CRA client qui fait foi, parfois le vôtre, parfois celui de la SSII …posez la question.Exemple: 1 mois de 22 jours avec 3 jours de congés en Octobre##Facture (mensuel)Exemple: le même mois, en se basant sur le CRA précédent (merci Didier)!Facturer à la SSII/Client (fin de mois)Exemple: émission d’une facture le 1er Novembre concernant le mois d’Octobre.  Avoir le CRA signé (voir précédemment)  Créer la facture (voir précédemment)  Envoyer  ces 2 pièces (par mail ou courrier, selon ce que vous impose la SSII ou le client si vous êtes en direct)  Vérifier sur vos comptes si le versement est bien fait  au bout de 30 jours max  En cas d’impayés (cela arrive avec les clients/SSII pas sérieux),  il faut régler la situation dès le premier défaut …sinon ce ne sera plus tenable dans plusieurs mois.Exemple: mail10. Les frais annexes à anticiper pour le bilan annuelC’est une partie qui interviendra en fin d’année dans la compta. A ne pas négliger car elle peut représenter un gain par rapport au status de salarié.Pour certains achats, faire passer cela sur le professionnel en achetant avec votre compte pro et en demandant une facture indiquant au minimum votre raison sociale / numéro de SIRET.  Journalier: -20% pas de TVA à payer.  Annuel: achat en partie déduis des charges  cotisations socialesCela concerne tous ce que vous utilisez dans le cadre de votre travail.  frais de bouche: repas  transports: pass Navigo  fournitures de bureau: encre, papier, outils  matériel informatique: ordinateur, clé USB, imprimante, etc  frais annexes: site web, internet, mobile, formation (l’occasion d’aller à DevoxxFR ou BestOfWebExemples:LDLC ProAcheter hors TVA sur LDLC Pro avec la facture contenant le numéro de SIRET.Acheter sur Amazon ou autre avec le nom qui colle si vous êtes en EI ou EIRL (le numéro de SIRET n’est pas obligatoire car le patrimoine de la personne et la société est fusionné).ConclusionUn peu de paperasse tous les mois, compter 1h en tout.Mais plus de libertés qu’en étant salarié, et une prise de risque minime dans l’état actuel du marché de la prestation IT sur Paris.Le plus gros reste à venir avec la compta, les impôts et la “communication” avec les autres entités de secu/retraite/allocations (URSAFF, RSI, CIPAV, RAM, etc).Référenceshttp://tarifs.freelance-info.fr/developpeur/http://tarifs.freelance-info.fr/developpeur/http://www.freelance-info.fr/http://www.freelance-info.fr/http://fr.viadeo.com/fr/http://fr.viadeo.com/fr/http://fr.linkedin.com/http://fr.linkedin.com/http://avis-situation-sirene.insee.fr/avisitu/http://avis-situation-sirene.insee.fr/avisitu/http://www.urssaf.fr/http://www.urssaf.fr/Originhttps://damienfremont.com/2015/12/03/developpeur-freelance-en-2015-la-routine-les-missions-23/",
        "url": "/2015/12/03/developpeur-freelance-en-2015-la-routine-les-missions-23"
      },
    
      "2015-11-19-javaee-angularjs-bootstrap-how-to-authent-basic": {
        "title": "Javaee Angularjs Bootstrap How To Authent Basic",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "This post is about basic authentification with AngularJs, Satellizer and JAX-RS Jersey.Warning: it only covers auth and token. For a production-ready app, you need to add Keystore, back-end URL filtering, encryption.Note: a lot of examples are on Satellizer’s GitHubhttps://github.com/sahat/satellizer/tree/master/examples/clienthttps://github.com/sahat/satellizer/tree/master/examples/clienthttps://github.com/sahat/satellizer/tree/master/examples/server/javahttps://github.com/sahat/satellizer/tree/master/examples/server/javaDemoStart Tomcat and open your Internet Browser at :http://localhost:8080/20151119-javaee-angularjs-bootstrap-auth_basic/#/http://localhost:8080/20151119-javaee-angularjs-bootstrap-auth_basic/#/Only Login and Home menu’s buttons are visible.Login redirect to the Login page (login=user1@mail.com, password=pass1).The login view call the Java backend, and as a response there’ll be a token. After login, the Home page is displayed.And the navbar now contains a “Datas” button. Also, Login is now more visible, but Logout is.This secured page by route authent and navbar is now displayed with a message from the REST backend server.On Logout, the app’s first state is restored (no auth, need to login).It’s no longer possible to access #/datas page (route url is also secured).Sourcepom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151119-javaee-angularjs-bootstrap-auth_basic&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;jquery.version&gt;2.1.4&lt;/jquery.version&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;satellizer.version&gt;0.12.5&lt;/satellizer.version&gt;    &lt;ui-router.version&gt;0.2.9&lt;/ui-router.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;com.nimbusds&lt;/groupId&gt;      &lt;artifactId&gt;nimbus-jose-jwt&lt;/artifactId&gt;      &lt;version&gt;3.1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- JAVA LANGUAGE EXTENSION --&gt;    &lt;dependency&gt;      &lt;groupId&gt;joda-time&lt;/groupId&gt;      &lt;artifactId&gt;joda-time&lt;/artifactId&gt;      &lt;version&gt;2.7&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;com.google.guava&lt;/groupId&gt;      &lt;artifactId&gt;guava&lt;/artifactId&gt;      &lt;version&gt;18.0&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;jquery&lt;/artifactId&gt;      &lt;version&gt;${jquery.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;ui-router&lt;/artifactId&gt;      &lt;version&gt;${ui-router.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;satellizer&lt;/artifactId&gt;      &lt;version&gt;${satellizer.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;index.html&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;AuthUtils.javapackage com.damienfremont.blog; import java.text.ParseException; import org.joda.time.DateTime; import com.nimbusds.jose.JOSEException;import com.nimbusds.jose.JWSAlgorithm;import com.nimbusds.jose.JWSHeader;import com.nimbusds.jose.JWSSigner;import com.nimbusds.jose.crypto.MACSigner;import com.nimbusds.jose.crypto.MACVerifier;import com.nimbusds.jwt.JWTClaimsSet;import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;import com.nimbusds.jwt.SignedJWT;  /** * @see https://github.com/sahat/satellizer/blob/master/examples/server/java/src/main/java/com/example/helloworld/auth/AuthUtils.java */public class AuthUtils {  private static final JWSHeader JWT_HEADER = new JWSHeader(JWSAlgorithm.HS256);  private static final String TOKEN_SECRET = \"aliceinwonderland\";  public static final String AUTH_HEADER_KEY = \"Authorization\";   public static String getSubject(String authHeader) throws ParseException, JOSEException {    return decodeToken(authHeader).getSubject();  }   public static ReadOnlyJWTClaimsSet decodeToken(String authHeader) throws ParseException, JOSEException {    SignedJWT signedJWT = SignedJWT.parse(getSerializedToken(authHeader));    if (signedJWT.verify(new MACVerifier(TOKEN_SECRET))) {      return signedJWT.getJWTClaimsSet();    } else {      throw new JOSEException(\"Signature verification failed\");    }  }   public static Token createToken(String host, long sub) throws JOSEException {    JWTClaimsSet claim = new JWTClaimsSet();    claim.setSubject(Long.toString(sub));    claim.setIssuer(host);    claim.setIssueTime(DateTime.now().toDate());    claim.setExpirationTime(DateTime.now().plusDays(14).toDate());     JWSSigner signer = new MACSigner(TOKEN_SECRET);    SignedJWT jwt = new SignedJWT(JWT_HEADER, claim);    jwt.sign(signer);     return new Token(jwt.serialize());  }   public static String getSerializedToken(String authHeader) {    return authHeader.split(\" \")[1];  }}MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    s.add(ServiceAuth.class);    return s;  }}ServiceAuth.javapackage com.damienfremont.blog; import java.util.HashMap;import java.util.Map; import javax.servlet.http.HttpServletRequest;import javax.validation.Valid;import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.Context;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response;import javax.ws.rs.core.Response.Status; import com.damienfremont.blog.ServiceJAXRS.Content;import com.google.common.base.Optional;import com.nimbusds.jose.JOSEException; /** * @see https://github.com/sahat/satellizer/blob/master/examples/server/java/src/main/java/com/example/helloworld/resources/AuthResource.java */@Path(\"/auth\")@Produces(MediaType.APPLICATION_JSON)@Consumes(MediaType.APPLICATION_JSON)public class ServiceAuth {   static Map&lt;String, User&gt; users = new HashMap&lt;&gt;();   static {    users.put(\"user1@mail.com\", new User(1L, \"user1@mail.com\", \"pass1\"));    users.put(\"user2@mail.com\", new User(2L, \"user2@mail.com\", \"pass2\"));  }   @GET  @Produces(MediaType.APPLICATION_JSON)  public Content get() {    Content res = new Content();    res.content = \"this is from backend!!!\";    return res;  }   @Path(\"/login\")  @POST  public Response login(@Valid final User user, @Context final HttpServletRequest request) throws JOSEException {    final Optional&lt;User&gt; foundUser = findByEmail(user.email);    if (foundUser.isPresent() &amp;&amp; checkPassword(user.password, foundUser.get().password)) {      final Token token = AuthUtils.createToken(request.getRemoteHost(), foundUser.get().id);      return Response.ok().entity(token).build();    }    return Response.status(Status.UNAUTHORIZED).entity(\"LOGING_ERROR_MSG\").build();  }   private boolean checkPassword(String password, String password2) {    // TODO BUILD YOUR OWN ENCRYPT PASSWORD CHECKER    return password.equals(password2);  }   private Optional&lt;User&gt; findByEmail(String email) {    // TODO BUILD YOUR OWN DAO    return Optional.fromNullable(users.get(email));  }   static class User {    public Long id;    public String email;    public String password;     public User() {    }     public User(Long id, String email, String password) {      this.id = id;      this.email = email;      this.password = password;    }   } }ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType; @Path(\"/data\")public class ServiceJAXRS {   @GET  @Produces(MediaType.APPLICATION_JSON)  public Content get() {    Content res = new Content();    res.content = \"this is from backend!!!\";    return res;  }     static class Content implements Serializable {    private static final long serialVersionUID = 611255415996442390L;    public String content;  } }Token.javapackage com.damienfremont.blog; import com.fasterxml.jackson.annotation.JsonProperty; /** * @see https://github.com/sahat/satellizer/blob/master/examples/server/java/src/main/java/com/example/helloworld/core/Token.java */public class Token {  String token;   public Token(@JsonProperty(\"token\") String token) {    this.token = token;  }   public String getToken() {    return token;  }}app.js'use strict'; var app = angular.module('app', [ 'ngResource', 'ngRoute',  'ui.router', 'satellizer' ]); // CONFIGapp.config(function($routeProvider, $authProvider) {       // ROUTE  $routeProvider    .when('/', {      templateUrl: 'views/home.html',      controller: 'HomeCtrl'    })    .when('/login', {      templateUrl: 'views/login.html',      controller: 'LoginCtrl'    })    .when('/logout', {      templateUrl: 'views/home.html',      controller: 'LogoutCtrl'    })    .when('/datas', {      templateUrl: 'views/datas.html',      controller: 'DatasCtrl',      resolve: {          loginRequired: loginRequired        }    })    .otherwise('/');   // SECURITY  $authProvider.withCredentials = true;  $authProvider.tokenRoot = null;  $authProvider.cordova = false;  $authProvider.baseUrl = './api/';  $authProvider.loginUrl = '/auth/login';  $authProvider.signupUrl = '/auth/signup';  $authProvider.unlinkUrl = '/auth/unlink/';  $authProvider.tokenName = 'token';  $authProvider.tokenPrefix = 'satellizer';  $authProvider.authHeader = 'Authorization';  $authProvider.authToken = 'Bearer';  $authProvider.storageType = 'localStorage';   }); function skipIfLoggedIn($q, $auth) {    var deferred = $q.defer();    if ($auth.isAuthenticated()) {      deferred.reject();    } else {      deferred.resolve();    }    return deferred.promise;  }   function loginRequired($q, $location, $auth) {    var deferred = $q.defer();    if ($auth.isAuthenticated()) {      deferred.resolve();    } else {      $location.path('/login');    }    return deferred.promise;  } app.factory('Service', function($resource) {  return $resource('api/data');}); // COMMON CTRL app.controller('ParentCtrl', function($scope, $auth) {  $scope.isAuthenticated = function() {    return $auth.isAuthenticated();  };}); app.controller('NavbarCtrl', function($scope, $auth) {   });datas.js'use strict'; app.controller('DatasCtrl', function($scope, $auth, Service) {     // GET DATAS IF AUTH OK  if ($auth.isAuthenticated()) {    Service.get(function(obj) {      $scope.content = obj.content;    });  }});home.js'use strict'; app.controller('HomeCtrl', function($scope, $auth, Service) {     // GET DATAS IF AUTH OK  if ($auth.isAuthenticated()) {    $scope.message = \"You are logged in!\";  } else {    $scope.message = \"You must login to access Datas.\";    }});login.js'use strict'; app.controller('LoginCtrl', function($scope, $auth, $location, $route) {   $scope.emailLogin = function() {  $auth.login({email: $scope.email, password: $scope.password})      .then(function() {//        toastr.success('You have successfully signed in!');        $location.path('/');        $route.reload();      })      .catch(function(error) {//        toastr.error(error.data.message, error.status);      });  };});logout.js'use strict'; app.controller('LogoutCtrl', function($location, $auth) {  if (!$auth.isAuthenticated()) { return; }  $auth.logout()  .then(function() {//  toastr.info('You have been logged out');    $location.path('/');  });});index.html&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;!-- YOU NEED THIS TAG TO PREVENT D3JS CHARACTER ERROR!!! --&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;/head&gt;&lt;body ng-app=\"app\"&gt;&lt;div class=\"container\" ng-controller=\"ParentCtrl\"&gt;&lt;h1&gt;Auth&lt;/h1&gt;   &lt;!-- MENU --&gt;  &lt;div class=\"slide-animate\"  ng-include=\"'menu.html'\" &gt;&lt;/div&gt;   &lt;!-- MAIN CONTENT --&gt;  &lt;div class=\"view-animate\"  ng-view &gt;&lt;/div&gt; &lt;/div&gt; &lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/jquery/${jquery.version}/jquery.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/bootstrap/${bootstrap.version}/js/bootstrap.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/satellizer/${satellizer.version}/satellizer.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/ui-router/${ui-router.version}/release/angular-ui-router.js\"&gt;&lt;/script&gt; &lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;script src=\"controllers/home.js\"&gt;&lt;/script&gt;&lt;script src=\"controllers/datas.js\"&gt;&lt;/script&gt;&lt;script src=\"controllers/login.js\"&gt;&lt;/script&gt;&lt;script src=\"controllers/logout.js\"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;menu.html&lt;!-- MENU --&gt;&lt;nav class=\"navbar navbar-default\" &gt;&lt;div class=\"container-fluid\" ng-controller=\"NavbarCtrl\"&gt; &lt;!-- HEADER AND MOBILE BUTTON --&gt;&lt;div class=\"navbar-header\"&gt;  &lt;button type=\"button\" class=\"navbar-toggle\"    data-toggle=\"collapse\"    data-target=\"#bs-example-navbar-collapse-1\"    aria-expanded=\"true\"&gt;    &lt;span class=\"sr-only\"&gt;Toggle navigation&lt;/span&gt;    &lt;span class=\"icon-bar\"&gt;&lt;/span&gt;    &lt;span class=\"icon-bar\"&gt;&lt;/span&gt;    &lt;span class=\"icon-bar\"&gt;&lt;/span&gt;  &lt;/button&gt;       &lt;!-- LOGO --&gt;  &lt;a class=\"navbar-brand\" href=\"#/\"&gt;    MyApp&lt;/a&gt;&lt;/div&gt;   &lt;!-- MENU ITEMS --&gt;&lt;div class=\"navbar-collapse collapse\"  id=\"bs-example-navbar-collapse-1\"  aria-expanded=\"true\"&gt;&lt;ul class=\"nav navbar-nav\"&gt;  &lt;li&gt;&lt;a href=\"#/\"&gt;Home&lt;/a&gt;&lt;/li&gt;  &lt;li ng-if=\"isAuthenticated()\"&gt;&lt;a href=\"#/datas\"&gt;Datas&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;ul ng-if=\"!isAuthenticated()\" class=\"nav navbar-nav navbar-right\"&gt;    &lt;li&gt;&lt;a href=\"#/login\"&gt;Login&lt;/a&gt;&lt;/li&gt;  &lt;/ul&gt;  &lt;ul ng-if=\"isAuthenticated()\" class=\"nav navbar-nav navbar-right\"&gt;    &lt;li&gt;&lt;a href=\"#/logout\"&gt;Logout&lt;/a&gt;&lt;/li&gt;  &lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;/nav&gt;datas.html&lt;h2&gt;Datas&lt;/h2&gt;&lt;!-- SECURED CONTENT FROM BACKEND--&gt;&lt;div ng-if=\"isAuthenticated()\"&gt;  Content: &lt;!-- Github ribbon--&gt;&lt;a href=\"https://github.com/DamienFremont/blog\" target=\"_blank\"&gt;    &lt;img style=\"position: absolute; top: 50px; right: 0; border: 0;\"        src=\"/assets/img/forkme_right_green_007200.png\" alt=\"Fork me on GitHub\"&gt;&lt;/a&gt;&lt;div class=\"container-fluid\"&gt;    &lt;div class=\"row p-3 p-md-5 p-xl-3 p-xxl-5\"&gt;        &lt;div class=\"d-none d-sm-none d-md-none d-lg-block col-lg-2 offset-0\"&gt;            &lt;div class=\"bg-body-tertiary p-4\"&gt;&lt;div class=\"px-3\"&gt;    &lt;ul class=\"list-unstyled site-tag-list\"&gt;        &lt;li&gt;            &lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/posts/\"&gt;                &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tags\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M3 2v4.586l7 7L14.586 9l-7-7zM2 2a1 1 0 0 1 1-1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 2 6.586z\"/&gt;  &lt;path d=\"M5.5 5a.5.5 0 1 1 0-1 .5.5 0 0 1 0 1m0 1a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3M1 7.086a1 1 0 0 0 .293.707L8.75 15.25l-.043.043a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 0 7.586V3a1 1 0 0 1 1-1z\"/&gt;&lt;/svg&gt; All Tutorials (96)            &lt;/a&gt;        &lt;/li&gt;    &lt;/ul&gt;&lt;/div&gt;&lt;hr/&gt;&lt;h3 class=\"pt-0\"&gt;Popular Topics&lt;/h3&gt;    &lt;div class=\"px-3\"&gt;        &lt;ul class=\"list-unstyled site-tag-list\"&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=java\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; java (46)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=cucumber\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; cucumber (7)&lt;/a&gt; BDD&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=javascript\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; javascript (29)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=angularjs\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; angularjs (21)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=bootstrap\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; bootstrap (19)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=unity3d\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; unity3d (11)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=junit\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; junit (7)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=agile\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; agile (4)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=rest\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; rest (5)&lt;/a&gt; API&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=git\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; git (8)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=spring\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; spring (4)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=design\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; design (3)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=photoshop\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; photoshop (2)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=nodejs\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; nodejs (4)&lt;/a&gt;&lt;/li&gt;            &lt;li class=\"my-2\"&gt;&lt;a class=\"text-reset text-decoration-none my-3\" rel=\"tag\" href=\"/tag/?query=selenium\"&gt;    &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-tag\" viewBox=\"0 0 16 16\"&gt;  &lt;path d=\"M6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0m-1 0a.5.5 0 1 0-1 0 .5.5 0 0 0 1 0\"/&gt;  &lt;path d=\"M2 1h4.586a1 1 0 0 1 .707.293l7 7a1 1 0 0 1 0 1.414l-4.586 4.586a1 1 0 0 1-1.414 0l-7-7A1 1 0 0 1 1 6.586V2a1 1 0 0 1 1-1m0 5.586 7 7L13.586 9l-7-7H2z\"/&gt;&lt;/svg&gt; selenium (3)&lt;/a&gt;&lt;/li&gt;        &lt;/ul&gt;    &lt;/div&gt;&lt;/div&gt;        &lt;/div&gt;        &lt;div class=\"col-sm-12 col-md-8 col-lg-7 offset-0 px-xxl-5\"&gt;            &lt;div class=\"article-header wp-block-group mb-3\"&gt;    &lt;h2 class=\"article-title wp-block-post-title fw-bold\"&gt;        &lt;span class=\"site-strapline\"&gt;Dev.&lt;/span&gt;        Javaee Angularjs Bootstrap Howto Charts With D3js    &lt;/h2&gt;    &lt;div class=\"post-meta taxonomy-category d-flex flex-wrap\"&gt;        &lt;div class=\"\"&gt;            &lt;small&gt;By &lt;a class=\"text-reset wp-block-heading\" href=\"/about\"&gt;Damien&lt;/a&gt;&lt;/small&gt;            ·            &lt;small class=\"date wp-block-post-date\"&gt;2015-11-08&lt;/small&gt;            &amp;nbsp;        &lt;/div&gt;        &lt;div class=\"flex-grow-1\"&gt;                        &lt;a href=\"/tag/?query=angularjs\"                class=\"badge rounded-pill bg-secondary text-decoration-none\" rel=\"tag\"&gt;angularjs&lt;/a&gt;                        &lt;a href=\"/tag/?query=java\"                class=\"badge rounded-pill bg-secondary text-decoration-none\" rel=\"tag\"&gt;java&lt;/a&gt;                        &lt;a href=\"/tag/?query=javascript\"                class=\"badge rounded-pill bg-secondary text-decoration-none\" rel=\"tag\"&gt;javascript&lt;/a&gt;                        &lt;a href=\"/tag/?query=bootstrap\"                class=\"badge rounded-pill bg-secondary text-decoration-none\" rel=\"tag\"&gt;bootstrap&lt;/a&gt;                    &lt;/div&gt;    &lt;/div&gt;&lt;/div&gt;&lt;div class=\"post-content wp-block-post-content\"&gt;&lt;p&gt;&lt;img src=\"/upload/post-thumbnail-angularjs.png\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;p&gt;Here simple use cases: a static Bar chart and a dynamic Line chart. It’s build with d3js and nvd3 for angularjs integration and java jersey for backend datas.&lt;/p&gt;&lt;p&gt;Note: for more advanced use cases, you’ll need to create your own angularjs directive working directly with d3js.&lt;/p&gt;&lt;h1 id=\"demo\"&gt;Demo&lt;/h1&gt;&lt;p&gt;&lt;a href=\"http://localhost:8080/20151108-javaee-angularjs-bootstrap-charts_d3js/\"&gt;http://localhost:8080/20151108-javaee-angularjs-bootstrap-charts_d3js/&lt;/a&gt;http://localhost:8080/20151108-javaee-angularjs-bootstrap-charts_d3js/&lt;/p&gt;&lt;p&gt;Here the two uses cases: bar charts and line charts.&lt;/p&gt;&lt;p&gt;&lt;img src=\"/upload/160523003625912.png\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;p&gt;There is a tooltip for each datas in charts.&lt;/p&gt;&lt;p&gt;&lt;img src=\"/upload/160523003626367.png\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;p&gt;There are two instances of Line chart:&lt;/p&gt;&lt;ul&gt;  &lt;li&gt;static (unique update at loading time)&lt;/li&gt;  &lt;li&gt;dynamic (refreshing every second)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;img src=\"/upload/160523003626513.gif\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;p&gt;Caution: for each refresh you’ll ended with a backend request. Pay attention to performance and load (bigger refresh interval, or replace only with new datas)&lt;/p&gt;&lt;p&gt;&lt;img src=\"/upload/160523003627210.png\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;p&gt;Java Data back-end response (build with Jersey JAX-RS impl).&lt;/p&gt;&lt;p&gt;&lt;img src=\"/upload/160523003627446.png\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;h1 id=\"source\"&gt;Source&lt;/h1&gt;&lt;p&gt;&lt;img src=\"/upload/160523003627906.png\" alt=\"alt text\" /&gt;&lt;/p&gt;&lt;p&gt;MyAppCONFIG.java&lt;/p&gt;&lt;div class=\"language-java highlighter-rouge\"&gt;&lt;div class=\"highlight\"&gt;&lt;pre class=\"highlight\"&gt;&lt;code&gt;&lt;span class=\"kn\"&gt;package&lt;/span&gt; &lt;span class=\"nn\"&gt;com.damienfremont.blog&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;java.util.HashSet&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;java.util.Set&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;javax.ws.rs.core.Application&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"kd\"&gt;public&lt;/span&gt; &lt;span class=\"kd\"&gt;class&lt;/span&gt; &lt;span class=\"nc\"&gt;MyAppCONFIG&lt;/span&gt; &lt;span class=\"kd\"&gt;extends&lt;/span&gt; &lt;span class=\"nc\"&gt;Application&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;   &lt;span class=\"nd\"&gt;@Override&lt;/span&gt;  &lt;span class=\"kd\"&gt;public&lt;/span&gt; &lt;span class=\"nc\"&gt;Set&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;Class&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=\"n\"&gt;getClasses&lt;/span&gt;&lt;span class=\"o\"&gt;()&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;    &lt;span class=\"nc\"&gt;Set&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;Class&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;?&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=\"n\"&gt;s&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"k\"&gt;new&lt;/span&gt; &lt;span class=\"nc\"&gt;HashSet&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;Class&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;?&amp;gt;&amp;gt;();&lt;/span&gt;    &lt;span class=\"n\"&gt;s&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;add&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"nc\"&gt;ServiceJAXRS&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;class&lt;/span&gt;&lt;span class=\"o\"&gt;);&lt;/span&gt;    &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"n\"&gt;s&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"o\"&gt;}&lt;/span&gt;&lt;span class=\"o\"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;ServiceJAXRS.java&lt;/p&gt;&lt;div class=\"language-java highlighter-rouge\"&gt;&lt;div class=\"highlight\"&gt;&lt;pre class=\"highlight\"&gt;&lt;code&gt;&lt;span class=\"kn\"&gt;package&lt;/span&gt; &lt;span class=\"nn\"&gt;com.damienfremont.blog&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;java.util.List&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;java.util.Random&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;javax.ws.rs.GET&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;javax.ws.rs.Path&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;javax.ws.rs.Produces&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;&lt;span class=\"kn\"&gt;import&lt;/span&gt; &lt;span class=\"nn\"&gt;javax.ws.rs.core.MediaType&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"nd\"&gt;@Path&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"s\"&gt;\"/datas\"&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt;&lt;span class=\"kd\"&gt;public&lt;/span&gt; &lt;span class=\"kd\"&gt;class&lt;/span&gt; &lt;span class=\"nc\"&gt;ServiceJAXRS&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;   &lt;span class=\"nd\"&gt;@Path&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"s\"&gt;\"/values\"&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt;  &lt;span class=\"nd\"&gt;@GET&lt;/span&gt;  &lt;span class=\"nd\"&gt;@Produces&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"nc\"&gt;MediaType&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt;  &lt;span class=\"kd\"&gt;public&lt;/span&gt; &lt;span class=\"nc\"&gt;List&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;List&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"nf\"&gt;getAll&lt;/span&gt;&lt;span class=\"o\"&gt;()&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;    &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"n\"&gt;mockDatas&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"o\"&gt;}&lt;/span&gt;     &lt;span class=\"nd\"&gt;@Path&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"s\"&gt;\"/values-big\"&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt;  &lt;span class=\"nd\"&gt;@GET&lt;/span&gt;  &lt;span class=\"nd\"&gt;@Produces&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"nc\"&gt;MediaType&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt;  &lt;span class=\"kd\"&gt;public&lt;/span&gt; &lt;span class=\"nc\"&gt;List&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;List&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"nf\"&gt;getAllReal&lt;/span&gt;&lt;span class=\"o\"&gt;()&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;    &lt;span class=\"c1\"&gt;// MOCK: UPDATE FOR REAL TIME&lt;/span&gt;    &lt;span class=\"n\"&gt;mockDatasReal&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;remove&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"mi\"&gt;0&lt;/span&gt;&lt;span class=\"o\"&gt;);&lt;/span&gt;    &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;+&lt;/span&gt; &lt;span class=\"n\"&gt;mockInterval&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;    &lt;span class=\"n\"&gt;mockDatasReal&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;add&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;newValue&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;mockStart&lt;/span&gt;&lt;span class=\"o\"&gt;));&lt;/span&gt;    &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"n\"&gt;mockDatasReal&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"o\"&gt;}&lt;/span&gt;     &lt;span class=\"c1\"&gt;// MOCK&lt;/span&gt;  &lt;span class=\"c1\"&gt;// MOCK: INIT&lt;/span&gt;  &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;List&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"n\"&gt;mockDatas&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"k\"&gt;new&lt;/span&gt; &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;  &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;    &lt;span class=\"kt\"&gt;long&lt;/span&gt; &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;1025409600000L&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;    &lt;span class=\"kt\"&gt;long&lt;/span&gt; &lt;span class=\"n\"&gt;mockInterval&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;2592000000L&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;    &lt;span class=\"k\"&gt;for&lt;/span&gt; &lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"kt\"&gt;int&lt;/span&gt; &lt;span class=\"n\"&gt;i&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;1&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"n\"&gt;i&lt;/span&gt; &lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt; &lt;span class=\"mi\"&gt;10&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"n\"&gt;i&lt;/span&gt;&lt;span class=\"o\"&gt;++)&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;      &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;+&lt;/span&gt; &lt;span class=\"n\"&gt;mockInterval&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;      &lt;span class=\"n\"&gt;mockDatas&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;add&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;newValue&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;mockStart&lt;/span&gt;&lt;span class=\"o\"&gt;));&lt;/span&gt;    &lt;span class=\"o\"&gt;}&lt;/span&gt;  &lt;span class=\"o\"&gt;}&lt;/span&gt;     &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;List&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"n\"&gt;mockDatasReal&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"k\"&gt;new&lt;/span&gt; &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;  &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"kt\"&gt;long&lt;/span&gt; &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;1&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"kt\"&gt;long&lt;/span&gt; &lt;span class=\"n\"&gt;mockInterval&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;1&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;    &lt;span class=\"k\"&gt;for&lt;/span&gt; &lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"kt\"&gt;int&lt;/span&gt; &lt;span class=\"n\"&gt;i&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;1&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"n\"&gt;i&lt;/span&gt; &lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt; &lt;span class=\"mi\"&gt;50&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt; &lt;span class=\"n\"&gt;i&lt;/span&gt;&lt;span class=\"o\"&gt;++)&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;      &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"n\"&gt;mockStart&lt;/span&gt; &lt;span class=\"o\"&gt;+&lt;/span&gt; &lt;span class=\"n\"&gt;mockInterval&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;      &lt;span class=\"n\"&gt;mockDatasReal&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;add&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;newValue&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;mockStart&lt;/span&gt;&lt;span class=\"o\"&gt;));&lt;/span&gt;    &lt;span class=\"o\"&gt;}&lt;/span&gt;  &lt;span class=\"o\"&gt;}&lt;/span&gt;  &lt;span class=\"kd\"&gt;private&lt;/span&gt; &lt;span class=\"kd\"&gt;static&lt;/span&gt; &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;Long&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"nf\"&gt;newValue&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"kt\"&gt;long&lt;/span&gt; &lt;span class=\"n\"&gt;start&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt; &lt;span class=\"o\"&gt;{&lt;/span&gt;    &lt;span class=\"kt\"&gt;long&lt;/span&gt; &lt;span class=\"n\"&gt;randomNum&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"k\"&gt;new&lt;/span&gt; &lt;span class=\"nc\"&gt;Random&lt;/span&gt;&lt;span class=\"o\"&gt;().&lt;/span&gt;&lt;span class=\"na\"&gt;nextInt&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"mi\"&gt;50&lt;/span&gt;&lt;span class=\"o\"&gt;)&lt;/span&gt; &lt;span class=\"o\"&gt;+&lt;/span&gt; &lt;span class=\"mi\"&gt;1&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;    &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&lt;/span&gt;&lt;span class=\"nc\"&gt;Long&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"n\"&gt;value&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"k\"&gt;new&lt;/span&gt; &lt;span class=\"nc\"&gt;ArrayList&lt;/span&gt;&lt;span class=\"o\"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;    &lt;span class=\"n\"&gt;value&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;add&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;start&lt;/span&gt;&lt;span class=\"o\"&gt;);&lt;/span&gt;    &lt;span class=\"n\"&gt;value&lt;/span&gt;&lt;span class=\"o\"&gt;.&lt;/span&gt;&lt;span class=\"na\"&gt;add&lt;/span&gt;&lt;span class=\"o\"&gt;(&lt;/span&gt;&lt;span class=\"n\"&gt;randomNum&lt;/span&gt;&lt;span class=\"o\"&gt;);&lt;/span&gt;    &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"n\"&gt;value&lt;/span&gt;&lt;span class=\"o\"&gt;;&lt;/span&gt;  &lt;span class=\"o\"&gt;}&lt;/span&gt; &lt;span class=\"o\"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;web.xml&lt;/p&gt;&lt;div class=\"language-xml highlighter-rouge\"&gt;&lt;div class=\"highlight\"&gt;&lt;pre class=\"highlight\"&gt;&lt;code&gt;&lt;span class=\"nt\"&gt;&amp;lt;web-app&lt;/span&gt; &lt;span class=\"na\"&gt;xmlns=&lt;/span&gt;&lt;span class=\"s\"&gt;\"http://xmlns.jcp.org/xml/ns/javaee\"&lt;/span&gt; &lt;span class=\"na\"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class=\"s\"&gt;\"http://www.w3.org/2001/XMLSchema-instance\"&lt;/span&gt; &lt;span class=\"na\"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class=\"s\"&gt;\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"&lt;/span&gt; &lt;span class=\"na\"&gt;version=&lt;/span&gt;&lt;span class=\"s\"&gt;\"3.1\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;   &lt;span class=\"nt\"&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;REST&lt;span class=\"nt\"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;org.glassfish.jersey.servlet.ServletContainer&lt;span class=\"nt\"&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;javax.ws.rs.Application&lt;span class=\"nt\"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;com.damienfremont.blog.MyAppCONFIG&lt;span class=\"nt\"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;jersey.config.server.provider.classnames&lt;span class=\"nt\"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;span class=\"nt\"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;load-on-startup&amp;gt;&lt;/span&gt;1&lt;span class=\"nt\"&gt;&amp;lt;/load-on-startup&amp;gt;&lt;/span&gt;  &lt;span class=\"nt\"&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;  &lt;span class=\"nt\"&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;REST&lt;span class=\"nt\"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/api/*&lt;span class=\"nt\"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;  &lt;span class=\"nt\"&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/span&gt;   &lt;span class=\"nt\"&gt;&amp;lt;servlet&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;WEBJARS&lt;span class=\"nt\"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;servlet-class&amp;gt;&lt;/span&gt;org.webjars.servlet.WebjarsServlet&lt;span class=\"nt\"&gt;&amp;lt;/servlet-class&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;init-param&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;param-name&amp;gt;&lt;/span&gt;disableCache&lt;span class=\"nt\"&gt;&amp;lt;/param-name&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;param-value&amp;gt;&lt;/span&gt;true&lt;span class=\"nt\"&gt;&amp;lt;/param-value&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;/init-param&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;load-on-startup&amp;gt;&lt;/span&gt;2&lt;span class=\"nt\"&gt;&amp;lt;/load-on-startup&amp;gt;&lt;/span&gt;  &lt;span class=\"nt\"&gt;&amp;lt;/servlet&amp;gt;&lt;/span&gt;  &lt;span class=\"nt\"&gt;&amp;lt;servlet-mapping&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;servlet-name&amp;gt;&lt;/span&gt;WEBJARS&lt;span class=\"nt\"&gt;&amp;lt;/servlet-name&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;url-pattern&amp;gt;&lt;/span&gt;/webjars/*&lt;span class=\"nt\"&gt;&amp;lt;/url-pattern&amp;gt;&lt;/span&gt;  &lt;span class=\"nt\"&gt;&amp;lt;/servlet-mapping&amp;gt;&lt;/span&gt; &lt;span class=\"nt\"&gt;&amp;lt;/web-app&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;app.js&lt;/p&gt;&lt;div class=\"language-javascript highlighter-rouge\"&gt;&lt;div class=\"highlight\"&gt;&lt;pre class=\"highlight\"&gt;&lt;code&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;use strict&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;;&lt;/span&gt; &lt;span class=\"kd\"&gt;var&lt;/span&gt; &lt;span class=\"nx\"&gt;app&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"nx\"&gt;angular&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;module&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;app&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"p\"&gt;[&lt;/span&gt; &lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;ngResource&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;nvd3ChartDirectives&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt; &lt;span class=\"p\"&gt;]);&lt;/span&gt; &lt;span class=\"c1\"&gt;// BAR *************&lt;/span&gt; &lt;span class=\"nx\"&gt;app&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;factory&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;Service&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;$resource&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;  &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"nx\"&gt;$resource&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;api/datas/values&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;);&lt;/span&gt;&lt;span class=\"p\"&gt;});&lt;/span&gt; &lt;span class=\"nx\"&gt;app&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;controller&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;BarCtrl&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"nx\"&gt;Service&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;   &lt;span class=\"c1\"&gt;// FORMATTING FUNCTION (OPTIONNAL)&lt;/span&gt;  &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;xAxisTickFormatFunction&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;()&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;    &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;d&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;      &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"nx\"&gt;d3&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;time&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;format&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;%b&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;)(&lt;/span&gt;&lt;span class=\"k\"&gt;new&lt;/span&gt; &lt;span class=\"nb\"&gt;Date&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;d&lt;/span&gt;&lt;span class=\"p\"&gt;));&lt;/span&gt;    &lt;span class=\"p\"&gt;}&lt;/span&gt;  &lt;span class=\"p\"&gt;}&lt;/span&gt;     &lt;span class=\"c1\"&gt;// INIT&lt;/span&gt;  &lt;span class=\"nx\"&gt;Service&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;query&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;datas&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;    &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;exampleData&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"p\"&gt;[&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;      &lt;span class=\"dl\"&gt;\"&lt;/span&gt;&lt;span class=\"s2\"&gt;key&lt;/span&gt;&lt;span class=\"dl\"&gt;\"&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"dl\"&gt;\"&lt;/span&gt;&lt;span class=\"s2\"&gt;Series 1&lt;/span&gt;&lt;span class=\"dl\"&gt;\"&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt;      &lt;span class=\"dl\"&gt;\"&lt;/span&gt;&lt;span class=\"s2\"&gt;values&lt;/span&gt;&lt;span class=\"dl\"&gt;\"&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"nx\"&gt;datas&lt;/span&gt;    &lt;span class=\"p\"&gt;}&lt;/span&gt; &lt;span class=\"p\"&gt;];&lt;/span&gt;  &lt;span class=\"p\"&gt;});&lt;/span&gt;&lt;span class=\"p\"&gt;});&lt;/span&gt; &lt;span class=\"c1\"&gt;// LINE IN REAL TIME ******&lt;/span&gt; &lt;span class=\"nx\"&gt;app&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;factory&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;ServiceReal&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;$resource&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;  &lt;span class=\"k\"&gt;return&lt;/span&gt; &lt;span class=\"nx\"&gt;$resource&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;api/datas/values-big&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;);&lt;/span&gt;&lt;span class=\"p\"&gt;});&lt;/span&gt; &lt;span class=\"nx\"&gt;app&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;controller&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;RealTimeCtrl&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"nx\"&gt;Service&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt; &lt;span class=\"nx\"&gt;ServiceReal&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;       &lt;span class=\"c1\"&gt;// REFRESH VALUE:  0.1 SEC&lt;/span&gt;  &lt;span class=\"kd\"&gt;var&lt;/span&gt; &lt;span class=\"nx\"&gt;refreshInterval&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"mi\"&gt;1&lt;/span&gt; &lt;span class=\"o\"&gt;*&lt;/span&gt; &lt;span class=\"mi\"&gt;1000&lt;/span&gt;&lt;span class=\"p\"&gt;;&lt;/span&gt;     &lt;span class=\"c1\"&gt;// UPDATE&lt;/span&gt;  &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;fetchData&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;()&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;      &lt;span class=\"nx\"&gt;ServiceReal&lt;/span&gt;    &lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;query&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;datas&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;        &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;exampleData&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"p\"&gt;[&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;          &lt;span class=\"na\"&gt;key&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;Series 1&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt;          &lt;span class=\"na\"&gt;values&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"nx\"&gt;datas&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt;          &lt;span class=\"na\"&gt;color&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;#ff7f0e&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;        &lt;span class=\"p\"&gt;}&lt;/span&gt; &lt;span class=\"p\"&gt;];&lt;/span&gt;      &lt;span class=\"p\"&gt;});&lt;/span&gt;  &lt;span class=\"p\"&gt;}&lt;/span&gt;  &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;fetchData2&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;()&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;      &lt;span class=\"nx\"&gt;ServiceReal&lt;/span&gt;        &lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;query&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"nx\"&gt;datas&lt;/span&gt;&lt;span class=\"p\"&gt;)&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;            &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;exampleData2&lt;/span&gt; &lt;span class=\"o\"&gt;=&lt;/span&gt; &lt;span class=\"p\"&gt;[&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;              &lt;span class=\"na\"&gt;key&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;Series 1&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt;              &lt;span class=\"na\"&gt;values&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"nx\"&gt;datas&lt;/span&gt;&lt;span class=\"p\"&gt;,&lt;/span&gt;              &lt;span class=\"na\"&gt;color&lt;/span&gt; &lt;span class=\"p\"&gt;:&lt;/span&gt; &lt;span class=\"dl\"&gt;'&lt;/span&gt;&lt;span class=\"s1\"&gt;#ff7f0e&lt;/span&gt;&lt;span class=\"dl\"&gt;'&lt;/span&gt;            &lt;span class=\"p\"&gt;}&lt;/span&gt; &lt;span class=\"p\"&gt;];&lt;/span&gt;          &lt;span class=\"p\"&gt;});&lt;/span&gt;      &lt;span class=\"p\"&gt;}&lt;/span&gt;       &lt;span class=\"c1\"&gt;// EVERY X TIME&lt;/span&gt;  &lt;span class=\"nx\"&gt;setInterval&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;()&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;    &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;$apply&lt;/span&gt;&lt;span class=\"p\"&gt;(&lt;/span&gt;&lt;span class=\"kd\"&gt;function&lt;/span&gt;&lt;span class=\"p\"&gt;()&lt;/span&gt; &lt;span class=\"p\"&gt;{&lt;/span&gt;        &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;fetchData2&lt;/span&gt;&lt;span class=\"p\"&gt;();&lt;/span&gt;    &lt;span class=\"p\"&gt;})&lt;/span&gt;  &lt;span class=\"p\"&gt;},&lt;/span&gt; &lt;span class=\"nx\"&gt;refreshInterval&lt;/span&gt;&lt;span class=\"p\"&gt;);&lt;/span&gt;     &lt;span class=\"c1\"&gt;// INIT&lt;/span&gt;  &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;fetchData&lt;/span&gt;&lt;span class=\"p\"&gt;();&lt;/span&gt;  &lt;span class=\"nx\"&gt;$scope&lt;/span&gt;&lt;span class=\"p\"&gt;.&lt;/span&gt;&lt;span class=\"nx\"&gt;fetchData2&lt;/span&gt;&lt;span class=\"p\"&gt;();&lt;/span&gt;&lt;span class=\"p\"&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;index.html&lt;/p&gt;&lt;div class=\"language-xml highlighter-rouge\"&gt;&lt;div class=\"highlight\"&gt;&lt;pre class=\"highlight\"&gt;&lt;code&gt;&lt;span class=\"cp\"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;span class=\"c\"&gt;&amp;lt;!-- YOU NEED THIS TAG TO PREVENT D3JS CHARACTER ERROR!!! --&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=\"na\"&gt;charset=&lt;/span&gt;&lt;span class=\"s\"&gt;\"utf-8\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt; &lt;span class=\"c\"&gt;&amp;lt;!-- LIBS CSS --&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;link&lt;/span&gt; &lt;span class=\"na\"&gt;rel=&lt;/span&gt;&lt;span class=\"s\"&gt;\"stylesheet\"&lt;/span&gt; &lt;span class=\"na\"&gt;href=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;link&lt;/span&gt; &lt;span class=\"na\"&gt;rel=&lt;/span&gt;&lt;span class=\"s\"&gt;\"stylesheet\"&lt;/span&gt; &lt;span class=\"na\"&gt;href=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/nvd3/${nvd3.version}/nv.d3.css\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;body&lt;/span&gt; &lt;span class=\"na\"&gt;ng-app=&lt;/span&gt;&lt;span class=\"s\"&gt;\"app\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;div&lt;/span&gt; &lt;span class=\"na\"&gt;class=&lt;/span&gt;&lt;span class=\"s\"&gt;\"container\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Charts&lt;span class=\"nt\"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt; &lt;span class=\"c\"&gt;&amp;lt;!-- BARS --&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;Bar Charts&lt;span class=\"nt\"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;div&lt;/span&gt; &lt;span class=\"na\"&gt;ng-controller=&lt;/span&gt;&lt;span class=\"s\"&gt;\"BarCtrl\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;nvd3-discrete-bar-chart&lt;/span&gt;        &lt;span class=\"na\"&gt;data=&lt;/span&gt;&lt;span class=\"s\"&gt;\"exampleData\"&lt;/span&gt;        &lt;span class=\"na\"&gt;showXAxis=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;        &lt;span class=\"na\"&gt;showYAxis=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;        &lt;span class=\"na\"&gt;xAxisTickFormat=&lt;/span&gt;&lt;span class=\"s\"&gt;\"xAxisTickFormatFunction()\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;            &lt;span class=\"nt\"&gt;&amp;lt;svg&amp;gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;/nvd3-discrete-bar-chart&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=\"c\"&gt;&amp;lt;!-- REAL TIME --&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;h4&amp;gt;&lt;/span&gt;Real Time Charts&lt;span class=\"nt\"&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;div&lt;/span&gt; &lt;span class=\"na\"&gt;ng-controller=&lt;/span&gt;&lt;span class=\"s\"&gt;\"RealTimeCtrl\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;   &lt;span class=\"nt\"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Static&lt;span class=\"nt\"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;   &lt;span class=\"nt\"&gt;&amp;lt;nvd3-line-chart&lt;/span&gt;     &lt;span class=\"na\"&gt;data=&lt;/span&gt;&lt;span class=\"s\"&gt;\"exampleData\"&lt;/span&gt;     &lt;span class=\"na\"&gt;showXAxis=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;     &lt;span class=\"na\"&gt;showYAxis=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;     &lt;span class=\"na\"&gt;tooltips=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;     &lt;span class=\"na\"&gt;interactive=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;        &lt;span class=\"nt\"&gt;&amp;lt;svg&amp;gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;/nvd3-line-chart&amp;gt;&lt;/span&gt;      &lt;span class=\"nt\"&gt;&amp;lt;h5&amp;gt;&lt;/span&gt;Real&lt;span class=\"nt\"&gt;&amp;lt;/h5&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;nvd3-line-chart&lt;/span&gt;     &lt;span class=\"na\"&gt;data=&lt;/span&gt;&lt;span class=\"s\"&gt;\"exampleData2\"&lt;/span&gt;     &lt;span class=\"na\"&gt;showXAxis=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;     &lt;span class=\"na\"&gt;showYAxis=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;     &lt;span class=\"na\"&gt;tooltips=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;     &lt;span class=\"na\"&gt;interactive=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;           &lt;span class=\"na\"&gt;objectEquality=&lt;/span&gt;&lt;span class=\"s\"&gt;\"true\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&lt;/span&gt;        &lt;span class=\"nt\"&gt;&amp;lt;svg&amp;gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;    &lt;span class=\"nt\"&gt;&amp;lt;/nvd3-line-chart&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt; &lt;span class=\"c\"&gt;&amp;lt;!-- LIBS JS --&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;script&lt;/span&gt; &lt;span class=\"na\"&gt;src=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/angularjs/${angularjs.version}/angular.js\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;script&lt;/span&gt; &lt;span class=\"na\"&gt;src=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;script&lt;/span&gt; &lt;span class=\"na\"&gt;src=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/d3js/${d3js.version}/d3.js\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;script&lt;/span&gt; &lt;span class=\"na\"&gt;src=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/nvd3/${nvd3.version}/nv.d3.js\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;script&lt;/span&gt; &lt;span class=\"na\"&gt;src=&lt;/span&gt;&lt;span class=\"s\"&gt;\"webjars/angularjs-nvd3-directives/${angularjs-nvd3-directives.version}/angularjs-nvd3-directives.js\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt; &lt;span class=\"c\"&gt;&amp;lt;!-- YOUR JS --&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;script&lt;/span&gt; &lt;span class=\"na\"&gt;src=&lt;/span&gt;&lt;span class=\"s\"&gt;\"app.js\"&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class=\"nt\"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;h1 id=\"project\"&gt;Project&lt;/h1&gt;&lt;p&gt;&lt;a href=\"https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151108-javaee-angularjs-bootstrap-charts_d3js\"&gt;https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151108-javaee-angularjs-bootstrap-charts_d3js&lt;/a&gt;https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151108-javaee-angularjs-bootstrap-charts_d3js&lt;/p&gt;&lt;h1 id=\"references\"&gt;References&lt;/h1&gt;&lt;p&gt;&lt;a href=\"http://cmaurer.github.io/angularjs-nvd3-directives/\"&gt;http://cmaurer.github.io/angularjs-nvd3-directives/&lt;/a&gt;http://cmaurer.github.io/angularjs-nvd3-directives/&lt;/p&gt;&lt;p&gt;&lt;a href=\"http://ngmodules.org/modules/angularjs-nvd3-directives\"&gt;http://ngmodules.org/modules/angularjs-nvd3-directives&lt;/a&gt;http://ngmodules.org/modules/angularjs-nvd3-directives&lt;/p&gt;&lt;p&gt;&lt;a href=\"https://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives\"&gt;https://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives&lt;/a&gt;https://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives&lt;/p&gt;&lt;p&gt;&lt;a href=\"https://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives/blob/master/examples/objectEquality.html\"&gt;https://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives/blob/master/examples/objectEquality.html&lt;/a&gt;https://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives/blob/master/examples/objectEquality.html&lt;/p&gt;&lt;p&gt;&lt;a href=\"http://busypeoples.github.io/post/promises-in-angular-js/\"&gt;http://busypeoples.github.io/post/promises-in-angular-js/&lt;/a&gt;http://busypeoples.github.io/post/promises-in-angular-js/&lt;/p&gt;&lt;h2 id=\"origin\"&gt;Origin&lt;/h2&gt;&lt;p&gt;&lt;a href=\"https://damienfremont.com/2015/11/08/javaee-angularjs-bootstrap-howto-charts-with-d3js/\"&gt;https://damienfremont.com/2015/11/08/javaee-angularjs-bootstrap-howto-charts-with-d3js/&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;            &lt;div class=\"row border rounded p-3 mt-5\"&gt;    &lt;div class=\"col-4 cold-md-2 p-3\"&gt;        &lt;img class=\"rounded-circle float-end\" width=\"96\" height=\"96\" src=\"/assets/img/avatar-damien.jpg\" /&gt;    &lt;/div&gt;    &lt;div class=\"col-8 cold-md-10\"&gt;        &lt;h5&gt;Hi, I'm &lt;a class=\"text-reset\" href=\"/about\"&gt;Damien&lt;/a&gt;&lt;/h5&gt;        &lt;p class=\"text-muted\"&gt;            Software Developer        &lt;/p&gt;        &lt;p&gt;            &lt;a class=\"p-2 text-reset text-decoration-none\" href=\"https://www.linkedin.com/in/damienfremont/\" target=\"_blank\" rel=\"noopener\"&gt;                &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-linkedin\"    viewBox=\"0 0 16 16\"&gt;    &lt;path        d=\"M0 1.146C0 .513.526 0 1.175 0h13.65C15.474 0 16 .513 16 1.146v13.708c0 .633-.526 1.146-1.175 1.146H1.175C.526 16 0 15.487 0 14.854zm4.943 12.248V6.169H2.542v7.225zm-1.2-8.212c.837 0 1.358-.554 1.358-1.248-.015-.709-.52-1.248-1.342-1.248S2.4 3.226 2.4 3.934c0 .694.521 1.248 1.327 1.248zm4.908 8.212V9.359c0-.216.016-.432.08-.586.173-.431.568-.878 1.232-.878.869 0 1.216.662 1.216 1.634v3.865h2.401V9.25c0-2.22-1.184-3.252-2.764-3.252-1.274 0-1.845.7-2.165 1.193v.025h-.016l.016-.025V6.169h-2.4c.03.678 0 7.225 0 7.225z\" /&gt;&lt;/svg&gt;            &lt;/a&gt;            &lt;a class=\"p-2 text-reset text-decoration-none\" href=\"https://github.com/damienfremont\" target=\"_blank\" rel=\"noopener\"&gt;                &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-github\"    viewBox=\"0 0 16 16\"&gt;    &lt;path        d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8\" /&gt;&lt;/svg&gt;            &lt;/a&gt;            &lt;a class=\"p-2 text-reset text-decoration-none\" href=\"https://x.com/damien_fremont\" target=\"_blank\" rel=\"noopener\"&gt;                &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" role=\"img\" viewBox=\"0 0 1024 1024\"&gt;    &lt;title&gt;X&lt;/title&gt;    &lt;path fill=\"currentColor\"        d=\"M818 800 498.11 333.745l.546.437L787.084 0h-96.385L455.738 272 269.15 0H16.367l298.648 435.31-.036-.037L0 800h96.385l261.222-302.618L565.217 800zM230.96 72.727l448.827 654.546h-76.38L154.217 72.727z\"        transform=\"translate(103 112)\" /&gt;&lt;/svg&gt;            &lt;/a&gt;        &lt;/p&gt;        &lt;p class=\"text-muted\"&gt;            Founder of this blog, love Java and Open Source stuff. Follow him on Twitter.        &lt;/p&gt;    &lt;/div&gt;&lt;/div&gt;        &lt;/div&gt;        &lt;div class=\"col-sm-6 col-md-4 col-lg-3 offset-0\"&gt;                        &lt;h3 class=\"pt-0 fw-bold text-secondary\"&gt;Most Read&lt;/h3&gt;&lt;div class=\"list-group shadow\"&gt;        &lt;div class=\"pb-xl-2 list-group-item\"&gt;        &lt;a href=\"/2021/02/18/test-driven-development-tdd-in-java-helloworld-examples\" class=\"text-reset text-decoration-none h-100\"&gt;            &lt;div class=\"row\"&gt;                &lt;div class=\"col-md-2\"&gt;                    &lt;span class=\"display-6\"&gt;                        1                    &lt;/span&gt;                &lt;/div&gt;                &lt;div class=\"col\"&gt;                    &lt;h6 class=\"fw-bold text-limit-line-2 my-0\"&gt;                        &lt;span class=\"site-strapline\"&gt;Dev.&lt;/span&gt;                        How-to JUnit: Test Driven Development / TDD In Java (Step by step with Helloworld Examples)                    &lt;/h6&gt;                    &lt;div&gt;                        &lt;small class=\"text-body-secondary\"&gt;                                                        &lt;span class=\"text-muted\"&gt; java &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; junit &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; spring &lt;/span&gt;                                                    &lt;/small&gt;                    &lt;/div&gt;                &lt;/div&gt;            &lt;/div&gt;        &lt;/a&gt;    &lt;/div&gt;        &lt;div class=\"pb-xl-2 list-group-item\"&gt;        &lt;a href=\"/2017/11/23/rest-api-maturity-levels-from-0-to-5\" class=\"text-reset text-decoration-none h-100\"&gt;            &lt;div class=\"row\"&gt;                &lt;div class=\"col-md-2\"&gt;                    &lt;span class=\"display-6\"&gt;                        2                    &lt;/span&gt;                &lt;/div&gt;                &lt;div class=\"col\"&gt;                    &lt;h6 class=\"fw-bold text-limit-line-2 my-0\"&gt;                        &lt;span class=\"site-strapline\"&gt;Dev.&lt;/span&gt;                        RESTful API Maturity Levels - From 0 To 5                    &lt;/h6&gt;                    &lt;div&gt;                        &lt;small class=\"text-body-secondary\"&gt;                                                        &lt;span class=\"text-muted\"&gt; design &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; rest &lt;/span&gt;                                                    &lt;/small&gt;                    &lt;/div&gt;                &lt;/div&gt;            &lt;/div&gt;        &lt;/a&gt;    &lt;/div&gt;        &lt;div class=\"pb-xl-2 list-group-item\"&gt;        &lt;a href=\"/2017/11/11/maslows-hierarchy-of-needs-for-software-developers\" class=\"text-reset text-decoration-none h-100\"&gt;            &lt;div class=\"row\"&gt;                &lt;div class=\"col-md-2\"&gt;                    &lt;span class=\"display-6\"&gt;                        3                    &lt;/span&gt;                &lt;/div&gt;                &lt;div class=\"col\"&gt;                    &lt;h6 class=\"fw-bold text-limit-line-2 my-0\"&gt;                        &lt;span class=\"site-strapline\"&gt;Dev.&lt;/span&gt;                        Maslows Hierarchy Of Needs For Software Developers (Not Food!)                    &lt;/h6&gt;                    &lt;div&gt;                        &lt;small class=\"text-body-secondary\"&gt;                                                        &lt;span class=\"text-muted\"&gt; agile &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; quicktip &lt;/span&gt;                                                    &lt;/small&gt;                    &lt;/div&gt;                &lt;/div&gt;            &lt;/div&gt;        &lt;/a&gt;    &lt;/div&gt;        &lt;div class=\"pb-xl-2 list-group-item\"&gt;        &lt;a href=\"/2015/07/23/how-to-cucumber-java-reuse-same-scenario-for-core-service-and-web-ui-tests\" class=\"text-reset text-decoration-none h-100\"&gt;            &lt;div class=\"row\"&gt;                &lt;div class=\"col-md-2\"&gt;                    &lt;span class=\"display-6\"&gt;                        4                    &lt;/span&gt;                &lt;/div&gt;                &lt;div class=\"col\"&gt;                    &lt;h6 class=\"fw-bold text-limit-line-2 my-0\"&gt;                        &lt;span class=\"site-strapline\"&gt;Dev.&lt;/span&gt;                        How-To Cucumber: Re-use Same Scenario For Core Service And Web UI Tests                    &lt;/h6&gt;                    &lt;div&gt;                        &lt;small class=\"text-body-secondary\"&gt;                                                        &lt;span class=\"text-muted\"&gt; bdd &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; cucumber &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; java &lt;/span&gt;                                                    &lt;/small&gt;                    &lt;/div&gt;                &lt;/div&gt;            &lt;/div&gt;        &lt;/a&gt;    &lt;/div&gt;        &lt;div class=\"pb-xl-2 list-group-item\"&gt;        &lt;a href=\"/2014/12/19/how-to-expandcollapse-table-rows-with-bootstrap\" class=\"text-reset text-decoration-none h-100\"&gt;            &lt;div class=\"row\"&gt;                &lt;div class=\"col-md-2\"&gt;                    &lt;span class=\"display-6\"&gt;                        5                    &lt;/span&gt;                &lt;/div&gt;                &lt;div class=\"col\"&gt;                    &lt;h6 class=\"fw-bold text-limit-line-2 my-0\"&gt;                        &lt;span class=\"site-strapline\"&gt;Dev.&lt;/span&gt;                        How-To Bootstrap: Expand and Collapse Table Rows With Bootstrap                    &lt;/h6&gt;                    &lt;div&gt;                        &lt;small class=\"text-body-secondary\"&gt;                                                        &lt;span class=\"text-muted\"&gt; bootstrap &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; css &lt;/span&gt;                                                        &lt;span class=\"text-muted\"&gt; javascript &lt;/span&gt;                                                    &lt;/small&gt;                    &lt;/div&gt;                &lt;/div&gt;            &lt;/div&gt;        &lt;/a&gt;    &lt;/div&gt;    &lt;/div&gt;            &lt;br /&gt;            &lt;div class=\"bg-body-tertiary px-4 py-3\"&gt;            &lt;h4 class=\"pt-0\"&gt;Follow on&lt;/h4&gt;&lt;ul class=\"list-unstyled wp-container-62130c4b8662b wp-block-social-links has-normal-icon-size\"&gt;    &lt;li&gt;&lt;a target=\"_blank\" href=\"https://www.linkedin.com/in/damienfremont\"            class=\"text-reset text-decoration-none\"&gt;            &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-linkedin\"    viewBox=\"0 0 16 16\"&gt;    &lt;path        d=\"M0 1.146C0 .513.526 0 1.175 0h13.65C15.474 0 16 .513 16 1.146v13.708c0 .633-.526 1.146-1.175 1.146H1.175C.526 16 0 15.487 0 14.854zm4.943 12.248V6.169H2.542v7.225zm-1.2-8.212c.837 0 1.358-.554 1.358-1.248-.015-.709-.52-1.248-1.342-1.248S2.4 3.226 2.4 3.934c0 .694.521 1.248 1.327 1.248zm4.908 8.212V9.359c0-.216.016-.432.08-.586.173-.431.568-.878 1.232-.878.869 0 1.216.662 1.216 1.634v3.865h2.401V9.25c0-2.22-1.184-3.252-2.764-3.252-1.274 0-1.845.7-2.165 1.193v.025h-.016l.016-.025V6.169h-2.4c.03.678 0 7.225 0 7.225z\" /&gt;&lt;/svg&gt;            &lt;span class=\"mx-2\"&gt;LinkedIn&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;        &lt;li&gt;&lt;a target=\"_blank\" href=\"https://github.com/damienfremont\"            class=\"text-reset text-decoration-none\"&gt;            &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-github\"    viewBox=\"0 0 16 16\"&gt;    &lt;path        d=\"M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8\" /&gt;&lt;/svg&gt;            &lt;span class=\"mx-2\"&gt;Github&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;        &lt;li&gt;&lt;a target=\"_blank\" href=\"http://x.com/damien_fremont\"            class=\"text-reset text-decoration-none\"&gt;            &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" role=\"img\" viewBox=\"0 0 1024 1024\"&gt;    &lt;title&gt;X&lt;/title&gt;    &lt;path fill=\"currentColor\"        d=\"M818 800 498.11 333.745l.546.437L787.084 0h-96.385L455.738 272 269.15 0H16.367l298.648 435.31-.036-.037L0 800h96.385l261.222-302.618L565.217 800zM230.96 72.727l448.827 654.546h-76.38L154.217 72.727z\"        transform=\"translate(103 112)\" /&gt;&lt;/svg&gt;            &lt;span class=\"mx-2\"&gt;X / Twitter&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;        &lt;li&gt;&lt;a target=\"_blank\" href=\"https://www.facebook.com/DamienFremontBlog/\"            class=\"text-reset text-decoration-none\"&gt;            &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-facebook\"    viewBox=\"0 0 16 16\"&gt;    &lt;path        d=\"M16 8.049c0-4.446-3.582-8.05-8-8.05C3.58 0-.002 3.603-.002 8.05c0 4.017 2.926 7.347 6.75 7.951v-5.625h-2.03V8.05H6.75V6.275c0-2.017 1.195-3.131 3.022-3.131.876 0 1.791.157 1.791.157v1.98h-1.009c-.993 0-1.303.621-1.303 1.258v1.51h2.218l-.354 2.326H9.25V16c3.824-.604 6.75-3.934 6.75-7.951\" /&gt;&lt;/svg&gt;            &lt;span class=\"mx-2\"&gt;Facebook&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;        &lt;li&gt;&lt;a target=\"_blank\" href=\"https://play.google.com/store/apps/dev?id=8294041563468906844\"            class=\"text-reset text-decoration-none\"&gt;            &lt;svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-google-play\"    viewBox=\"0 0 16 16\"&gt;    &lt;path        d=\"M14.222 9.374c1.037-.61 1.037-2.137 0-2.748L11.528 5.04 8.32 8l3.207 2.96zm-3.595 2.116L7.583 8.68 1.03 14.73c.201 1.029 1.36 1.61 2.303 1.055zM1 13.396V2.603L6.846 8zM1.03 1.27l6.553 6.05 3.044-2.81L3.333.215C2.39-.341 1.231.24 1.03 1.27\" /&gt;&lt;/svg&gt;            &lt;span class=\"mx-2\"&gt;GooglePlay&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a target=\"_blank\" href=\"https://discord.com/invite/PPTjWjjm9a\"            class=\"text-reset text-decoration-none\"&gt;            &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;&lt;!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --&gt;&lt;svg fill=\"currentColor\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\"&gt;    &lt;path        d=\"M9.593 10.971c-.542 0-.969.475-.969 1.055 0 .578.437 1.055.969 1.055.541 0 .968-.477.968-1.055.011-.581-.427-1.055-.968-1.055zm3.468 0c-.542 0-.969.475-.969 1.055 0 .578.437 1.055.969 1.055.541 0 .968-.477.968-1.055-.001-.581-.427-1.055-.968-1.055z\" /&gt;    &lt;path        d=\"M17.678 3H4.947A1.952 1.952 0 0 0 3 4.957v12.844c0 1.083.874 1.957 1.947 1.957H15.72l-.505-1.759 1.217 1.131 1.149 1.064L19.625 22V4.957A1.952 1.952 0 0 0 17.678 3zM14.01 15.407s-.342-.408-.626-.771c1.244-.352 1.719-1.13 1.719-1.13-.39.256-.76.438-1.093.562a6.679 6.679 0 0 1-3.838.398 7.944 7.944 0 0 1-1.396-.41 5.402 5.402 0 0 1-.693-.321c-.029-.021-.057-.029-.085-.048a.117.117 0 0 1-.039-.03c-.171-.094-.266-.16-.266-.16s.456.76 1.663 1.121c-.285.36-.637.789-.637.789-2.099-.067-2.896-1.444-2.896-1.444 0-3.059 1.368-5.538 1.368-5.538 1.368-1.027 2.669-.998 2.669-.998l.095.114c-1.71.495-2.499 1.245-2.499 1.245s.21-.114.561-.275c1.016-.446 1.823-.57 2.156-.599.057-.009.105-.019.162-.019a7.756 7.756 0 0 1 4.778.893s-.751-.712-2.366-1.206l.133-.152s1.302-.029 2.669.998c0 0 1.368 2.479 1.368 5.538 0-.001-.807 1.376-2.907 1.443z\" /&gt;&lt;/svg&gt;            &lt;span class=\"mx-2\"&gt;Discord Server&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;            &lt;br /&gt;            &lt;div class=\"bg-body-tertiary px-4 py-3\"&gt;    &lt;h4 class=\"pt-0\"&gt;Support this project!&lt;/h4&gt;    &lt;ul class=\"list-unstyled\"&gt;                &lt;li&gt;            &lt;a class=\"text-reset text-decoration-none text-limit-line-1\"                href=\"https://buymeacoffee.com/damienfremont\" target=\"_blank\"&gt;                &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;&lt;!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --&gt;&lt;svg fill=\"currentColor\" width=\"16\" height=\"16\" viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\"&gt;  &lt;path     d=\"M822.592 192h14.272a32 32 0 0 1 31.616 26.752l21.312 128A32 32 0 0 1 858.24 384h-49.344l-39.04 546.304A32 32 0 0 1 737.92 960H285.824a32 32 0 0 1-32-29.696L214.912 384H165.76a32 32 0 0 1-31.552-37.248l21.312-128A32 32 0 0 1 187.136 192h14.016l-6.72-93.696A32 32 0 0 1 226.368 64h571.008a32 32 0 0 1 31.936 34.304L822.592 192zm-64.128 0 4.544-64H260.736l4.544 64h493.184zm-548.16 128H820.48l-10.688-64H214.208l-10.688 64h6.784zm68.736 64 36.544 512H708.16l36.544-512H279.04z\" /&gt;&lt;/svg&gt;                &lt;span class=\"\"&gt;buymeacoffee.com/damienfremont&lt;/span&gt;            &lt;/a&gt;        &lt;/li&gt;                                &lt;li&gt;            &lt;a class=\"text-reset text-decoration-none text-limit-line-1\"                href=\"https://www.paypal.com/donate/?hosted_button_id=5WTGL666THA58\" target=\"_blank\"&gt;                &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;&lt;!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --&gt;&lt;svg fill=\"currentColor\" width=\"16\" height=\"16\" viewBox=\"0 0 512 512\" id=\"Layer_1\" data-name=\"Layer 1\"    xmlns=\"http://www.w3.org/2000/svg\"&gt;    &lt;path        d=\"M424.81,148.79c-.43,2.76-.93,5.58-1.49,8.48-19.17,98-84.76,131.8-168.54,131.8H212.13a20.67,20.67,0,0,0-20.47,17.46L169.82,444.37l-6.18,39.07a10.86,10.86,0,0,0,9.07,12.42,10.72,10.72,0,0,0,1.7.13h75.65a18.18,18.18,0,0,0,18-15.27l.74-3.83,14.24-90,.91-4.94a18.16,18.16,0,0,1,18-15.3h11.31c73.3,0,130.67-29.62,147.44-115.32,7-35.8,3.38-65.69-15.16-86.72A72.27,72.27,0,0,0,424.81,148.79Z\" /&gt;    &lt;path        d=\"M385.52,51.09C363.84,26.52,324.71,16,274.63,16H129.25a20.75,20.75,0,0,0-20.54,17.48l-60.55,382a12.43,12.43,0,0,0,10.39,14.22,12.58,12.58,0,0,0,1.94.15h89.76l22.54-142.29-.7,4.46a20.67,20.67,0,0,1,20.47-17.46h42.65c83.77,0,149.36-33.86,168.54-131.8.57-2.9,1.05-5.72,1.49-8.48h0C410.94,98.06,405.19,73.41,385.52,51.09Z\" /&gt;&lt;/svg&gt;                &lt;span class=\"\"&gt;paypal.com/damienfremont&lt;/span&gt;            &lt;/a&gt;        &lt;/li&gt;                        &lt;li&gt;            &lt;a class=\"text-reset text-decoration-none text-limit-line-1\"                href=\"https://damienfremont.itch.io/\" target=\"_blank\"&gt;                &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt;&lt;!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --&gt;&lt;svg fill=\"currentColor\" xmlns=\"http://www.w3.org/2000/svg\" aria-label=\"itch.io\" role=\"img\" width=\"18\" height=\"18\" viewBox=\"0 0 512 512\"&gt;    &lt;rect  rx=\"15%\" /&gt;    &lt;path        d=\"M118 95c-16 10-49 47-49 56v16c0 21 19 38 36 38 21 0 38-17 38-37 0 20 17 37 38 37 20 0 36-17 36-37 0 20 18 37 39 37s39-17 39-37c0 20 16 37 36 37 21 0 38-17 38-37 0 20 17 37 38 37 17 0 36-17 36-38v-16c0-9-33-46-49-56a3511 3511 0 00-276 0zm99 101l-7 9a43 43 0 01-68-9l-7 9c-8 8-19 13-31 13l-4-1-2 46v18c0 36-4 118 16 138 30 7 86 10 142 10s112-3 142-10c20-20 16-102 16-138v-18l-2-46-4 1c-12 0-23-5-31-13l-7-9-7 9a43 43 0 01-68-9 43 43 0 01-38 22h-1-1a43 43 0 01-38-22zm-31 40c12 0 23 0 37 15l33-2 33 2c14-15 25-15 37-15 6 0 29 0 45 46l18 63c13 46-4 47-26 47-31-1-49-24-49-47a371 371 0 01-117 0c1 23-17 46-48 47-22 0-39-1-26-47l18-63c16-46 39-46 45-46zm70 36s-33 31-39 42l22-1v19h34v-19l22 1c-6-11-39-42-39-42z\" /&gt;&lt;/svg&gt;                &lt;span class=\"\"&gt;itchio.com/damienfremont&lt;/span&gt;            &lt;/a&gt;        &lt;/li&gt;                &lt;!-- TODO: patreon.com/damienfremont --&gt;        &lt;!-- TODO: ko-fi.com/damienfremont --&gt;            &lt;/ul&gt;&lt;/div&gt;        &lt;/div&gt;    &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;home.html&lt;h2&gt;Home&lt;/h2&gt;&lt;p&gt;&lt;/p&gt;login.html&lt;!-- FROM https://github.com/sahat/satellizer/blob/master/examples/client/partials/login.html --&gt; &lt;div class=\"panel panel-default col-md-4 col-md-offset-4\"&gt;  &lt;div class=\"panel-body\"&gt;    &lt;h4 class=\"text-center\"&gt;      &lt;i class=\"glyphicon glyphicon-log-in\"&gt;&lt;/i&gt; Log in    &lt;/h4&gt;     &lt;form name=\"loginForm\" ng-submit=\"emailLogin()\" novalidate&gt;       &lt;!-- LOGIN --&gt;      &lt;div class=\"form-group has-feedback\"        ng-class=\"{ 'has-error': loginForm.email.$invalid &amp;&amp; loginForm.email.$dirty }\"&gt;        &lt;input server-error class=\"form-control input-lg\" type=\"text\"          name=\"email\" ng-model=\"email\" placeholder=\"Email\" required          autofocus&gt;        &lt;div class=\"help-block\" ng-if=\"loginForm.email.$dirty\"          ng-messages=\"loginForm.email.$error\"&gt;          &lt;div ng-message=\"required\"&gt;Please enter your email&lt;/div&gt;          &lt;div ng-message=\"server\"&gt;&lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;       &lt;!-- PASSWORD --&gt;      &lt;div class=\"form-group has-feedback\"        ng-class=\"{ 'has-error': loginForm.password.$invalid &amp;&amp; loginForm.password.$dirty }\"&gt;        &lt;input server-error class=\"form-control input-lg\"          type=\"password\" name=\"password\" ng-model=\"password\"          placeholder=\"Password\" required&gt;        &lt;div class=\"help-block\" ng-if=\"loginForm.password.$dirty\"          ng-messages=\"loginForm.password.$error\"&gt;          &lt;div ng-message=\"required\"&gt;Please enter your password&lt;/div&gt;          &lt;div ng-message=\"server\"&gt;&lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;       &lt;!-- SUBMIT --&gt;      &lt;button type=\"submit\" class=\"btn btn-block btn-success\"        ng-disabled=\"loginForm.$invalid\"&gt;Log in&lt;/button&gt;     &lt;/form&gt;  &lt;/div&gt;&lt;/div&gt;web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;init-param&gt;      &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;      &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151119-javaee-angularjs-bootstrap-auth_basichttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151119-javaee-angularjs-bootstrap-auth_basicReferenceshttps://github.com/sahat/satellizerhttps://github.com/sahat/satellizerhttps://github.com/sahat/satellizer/tree/master/examples/clienthttps://github.com/sahat/satellizer/tree/master/examples/clienthttps://github.com/sahat/satellizer/tree/master/examples/server/javahttps://github.com/sahat/satellizer/tree/master/examples/server/javahttps://hackhands.com/building-instagram-clone-angularjs-satellizer-nodejs-mongodb/https://hackhands.com/building-instagram-clone-angularjs-satellizer-nodejs-mongodb/https://github.com/sahat/instagram-hackhandshttps://github.com/sahat/instagram-hackhandsOriginhttps://damienfremont.com/2015/11/19/javaee-angularjs-bootstrap-how-to-authent-basic/",
        "url": "/2015/11/19/javaee-angularjs-bootstrap-how-to-authent-basic"
      },
    
      "2015-11-08-javaee-angularjs-bootstrap-howto-charts-with-d3js": {
        "title": "Javaee Angularjs Bootstrap Howto Charts With D3js",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "Here simple use cases: a static Bar chart and a dynamic Line chart. It’s build with d3js and nvd3 for angularjs integration and java jersey for backend datas.Note: for more advanced use cases, you’ll need to create your own angularjs directive working directly with d3js.Demohttp://localhost:8080/20151108-javaee-angularjs-bootstrap-charts_d3js/http://localhost:8080/20151108-javaee-angularjs-bootstrap-charts_d3js/Here the two uses cases: bar charts and line charts.There is a tooltip for each datas in charts.There are two instances of Line chart:  static (unique update at loading time)  dynamic (refreshing every second)Caution: for each refresh you’ll ended with a backend request. Pay attention to performance and load (bigger refresh interval, or replace only with new datas)Java Data back-end response (build with Jersey JAX-RS impl).SourceMyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.util.ArrayList;import java.util.List;import java.util.Random; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;  @Path(\"/datas\")public class ServiceJAXRS {   @Path(\"/values\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public List&lt;List&gt; getAll() {    return mockDatas;  }     @Path(\"/values-big\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public List&lt;List&gt; getAllReal() {    // MOCK: UPDATE FOR REAL TIME    mockDatasReal.remove(0);    mockStart = mockStart + mockInterval;    mockDatasReal.add(newValue(mockStart));    return mockDatasReal;  }     // MOCK  // MOCK: INIT  static ArrayList&lt;List&gt; mockDatas = new ArrayList&lt;&gt;();  static {    long mockStart = 1025409600000L;    long mockInterval = 2592000000L;    for (int i = 1; i &lt; 10; i++) {      mockStart = mockStart + mockInterval;      mockDatas.add(newValue(mockStart));    }  }     static ArrayList&lt;List&gt; mockDatasReal = new ArrayList&lt;&gt;();  static long mockStart = 1;  static long mockInterval = 1;  static {    for (int i = 1; i &lt; 50; i++) {      mockStart = mockStart + mockInterval;      mockDatasReal.add(newValue(mockStart));    }  }  private static ArrayList&lt;Long&gt; newValue(long start) {    long randomNum = new Random().nextInt(50) + 1;    ArrayList&lt;Long&gt; value = new ArrayList&lt;&gt;();    value.add(start);    value.add(randomNum);    return value;  } }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;init-param&gt;      &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;      &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module('app', [ 'ngResource', 'nvd3ChartDirectives' ]); // BAR ************* app.factory('Service', function($resource) {  return $resource('api/datas/values');}); app.controller('BarCtrl', function($scope, Service) {   // FORMATTING FUNCTION (OPTIONNAL)  $scope.xAxisTickFormatFunction = function() {    return function(d) {      return d3.time.format('%b')(new Date(d));    }  }     // INIT  Service.query(function(datas) {    $scope.exampleData = [ {      \"key\" : \"Series 1\",      \"values\" : datas    } ];  });}); // LINE IN REAL TIME ****** app.factory('ServiceReal', function($resource) {  return $resource('api/datas/values-big');}); app.controller('RealTimeCtrl', function($scope, Service, ServiceReal) {       // REFRESH VALUE:  0.1 SEC  var refreshInterval = 1 * 1000;     // UPDATE  $scope.fetchData = function() {      ServiceReal    .query(function(datas) {        $scope.exampleData = [ {          key : 'Series 1',          values : datas,          color : '#ff7f0e'        } ];      });  }  $scope.fetchData2 = function() {      ServiceReal        .query(function(datas) {            $scope.exampleData2 = [ {              key : 'Series 1',              values : datas,              color : '#ff7f0e'            } ];          });      }       // EVERY X TIME  setInterval(function() {    $scope.$apply(function() {        $scope.fetchData2();    })  }, refreshInterval);     // INIT  $scope.fetchData();  $scope.fetchData2();});index.html&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;&lt;!-- YOU NEED THIS TAG TO PREVENT D3JS CHARACTER ERROR!!! --&gt;&lt;meta charset=\"utf-8\"&gt; &lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;link rel=\"stylesheet\" href=\"webjars/nvd3/${nvd3.version}/nv.d3.css\"&gt;&lt;/head&gt;&lt;body ng-app=\"app\"&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;Charts&lt;/h1&gt; &lt;!-- BARS --&gt;&lt;h4&gt;Bar Charts&lt;/h4&gt;&lt;div ng-controller=\"BarCtrl\"&gt;&lt;nvd3-discrete-bar-chart        data=\"exampleData\"        showXAxis=\"true\"        showYAxis=\"true\"        xAxisTickFormat=\"xAxisTickFormatFunction()\"&gt;            &lt;svg&gt;&lt;/svg&gt;    &lt;/nvd3-discrete-bar-chart&gt;&lt;/div&gt; &lt;!-- REAL TIME --&gt;&lt;h4&gt;Real Time Charts&lt;/h4&gt;&lt;div ng-controller=\"RealTimeCtrl\"&gt;   &lt;h5&gt;Static&lt;/h5&gt;   &lt;nvd3-line-chart     data=\"exampleData\"     showXAxis=\"true\"     showYAxis=\"true\"     tooltips=\"true\"     interactive=\"true\"&gt;        &lt;svg&gt;&lt;/svg&gt;    &lt;/nvd3-line-chart&gt;      &lt;h5&gt;Real&lt;/h5&gt;    &lt;nvd3-line-chart     data=\"exampleData2\"     showXAxis=\"true\"     showYAxis=\"true\"     tooltips=\"true\"     interactive=\"true\"           objectEquality=\"true\"&gt;        &lt;svg&gt;&lt;/svg&gt;    &lt;/nvd3-line-chart&gt;&lt;/div&gt;&lt;/div&gt; &lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/d3js/${d3js.version}/d3.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/nvd3/${nvd3.version}/nv.d3.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs-nvd3-directives/${angularjs-nvd3-directives.version}/angularjs-nvd3-directives.js\"&gt;&lt;/script&gt; &lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151108-javaee-angularjs-bootstrap-charts_d3jshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151108-javaee-angularjs-bootstrap-charts_d3jsReferenceshttp://cmaurer.github.io/angularjs-nvd3-directives/http://cmaurer.github.io/angularjs-nvd3-directives/http://ngmodules.org/modules/angularjs-nvd3-directiveshttp://ngmodules.org/modules/angularjs-nvd3-directiveshttps://github.com/angularjs-nvd3-directives/angularjs-nvd3-directiveshttps://github.com/angularjs-nvd3-directives/angularjs-nvd3-directiveshttps://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives/blob/master/examples/objectEquality.htmlhttps://github.com/angularjs-nvd3-directives/angularjs-nvd3-directives/blob/master/examples/objectEquality.htmlhttp://busypeoples.github.io/post/promises-in-angular-js/http://busypeoples.github.io/post/promises-in-angular-js/Originhttps://damienfremont.com/2015/11/08/javaee-angularjs-bootstrap-howto-charts-with-d3js/",
        "url": "/2015/11/08/javaee-angularjs-bootstrap-howto-charts-with-d3js"
      },
    
      "2015-11-06-javaee-angularjs-bootstrap-how-to-multilingual-i18n-l10n": {
        "title": "Javaee Angularjs Bootstrap How To Multilingual I18n L10n",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "This is about dynamic Internationalization (i18n), Localization (L10n) , Globalization (i18n* and L10n*) and Cookies storage with angular-translate and agular-dynamic-locale.Demohttp://localhost:8080/20151106-javaee-angularjs-bootstrap-multilingual-i18n-l10n/http://localhost:8080/20151106-javaee-angularjs-bootstrap-multilingual-i18n-l10n/A simple content where language and locale can be change by country.Here are three countries, including two with the same language (i18n) but different currency and date format (l10n).  English (US): lang=en, locale=us  English (GB): lang=en, locale=gb  French (FR): lang=fr, locale=frBy switching from US to GB, only currency and date format has changed (l10n).With FR: language, date and currency change.For each language, there are two files.  An l10n locale file (format of date, currency, calendar,etc)  An i18n language file (text, label translation)By default, your browser language is used. But if the app does not know this language, it fallbacks to ‘English (US)’ …until you choose another with the menu.Because this app use browser locale, cookie and fallback language, there are three scenarios at startup.  1st time : no cookies browser language is supported by the app (English or French)  =&gt; it will be the default language browser language is not supported (Deutch?) =&gt; the app fallbacks to English  2nd time : cookies =&gt; the app use the previous used languageSourcei18n/locale-en.json{“PARAGRAPH”: “This is a paragrah in english.”}i18n/locale-fr.json{“PARAGRAPH”: “C’est un paragraphe en français.”}web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module('app',  [ 'ngCookies',    'pascalprecht.translate',    'tmh.dynamicLocale']); // i18n: LANGUAGEapp.config( function ($translateProvider) {       // ADD LANG  $translateProvider  .useStaticFilesLoader({    prefix: 'i18n/locale-',    suffix: '.json'  })     // REMEMBER  .preferredLanguage('en')  .fallbackLanguage('en')  .useCookieStorage()     // SECURITY  .useSanitizeValueStrategy('escape');}); // l10n: LOCALEapp.config(function(tmhDynamicLocaleProvider) {  const locales = 'webjars/angular-i18n/1.4.7/angular-locale_.js';  tmhDynamicLocaleProvider   // REMEMBER  .localeLocationPattern(locales)  .useCookieStorage();}) app.controller('MainCtrl', function($window, $scope, $translate, $cookieStore, tmhDynamicLocale, tmhDynamicLocaleCache, $rootScope, $locale) {     $scope.availableLocales = {    'en-us': 'English (US)',    'en-gb': 'English (GB)',    'fr-fr': 'French (FR)'  };     // CHANGE LANG  $scope.changeLocale = function(key) {    $rootScope.model = {selectedLocale: key};    // i18n    var langKey = key.substring(0,2);    $translate.use(langKey);    // l10n    tmhDynamicLocale.set(key);  }     // INIT  $rootScope.$locale = $locale;  var lang = $cookieStore.get('tmhDynamicLocale.locale');;  if(!lang) {      lang = $window.navigator.language || $window.navigator.userLanguage;  }  $scope.changeLocale(lang);   });index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/jquery/${jquery.version}/jquery.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/bootstrap/${bootstrap.version}/js/bootstrap.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-cookies.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-translate/${angular-translate.version}/angular-translate.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-translate-storage-cookie/${angular-translate-storage-cookie.version}/angular-translate-storage-cookie.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-translate-loader-static-files/${angular-translate-loader-static-files.version}/angular-translate-loader-static-files.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-dynamic-locale/${angular-dynamic-locale.version}/dist/tmhDynamicLocale.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body ng-controller=\"MainCtrl\"&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;Multilingual&lt;/h1&gt; &lt;!-- CHANGE LANGUAGE --&gt;&lt;div class=\"dropdown\"&gt;  &lt;button class=\"btn btn-default dropdown-toggle\" data-toggle=\"dropdown\"&gt;    &lt;i class=\"glyphicon glyphicon-menu-hamburger\"&gt;&lt;/i&gt;     Language ()     &lt;span class=\"caret\"&gt;&lt;/span&gt;  &lt;/button&gt;  &lt;ul class=\"dropdown-menu\"&gt;    &lt;li ng-repeat=\"(key, value) in availableLocales\"&gt;      &lt;a href=\"#\"        ng-click=\"changeLocale(key)\"&gt;      &lt;img src=\"img/flag_icons/.png\" /&gt;      &lt;/a&gt;&lt;/li&gt;  &lt;/ul&gt;&lt;/div&gt;&lt;br/&gt;&lt;div class=\"alert alert-info col-md-5\"&gt;&lt;p&gt;Current locale id: &lt;/p&gt;&lt;br/&gt;   &lt;!-- i18n: LANGUAGE --&gt;&lt;strong&gt;i18n: LANGUAGE&lt;/strong&gt;&lt;p&gt;PARAGRAPH&lt;/p&gt;   &lt;br/&gt; &lt;!-- l10n: LOCALE --&gt;&lt;strong&gt;l10n: LOCALE&lt;/strong&gt;&lt;p&gt;A big number: 1234567890&lt;/p&gt;&lt;p&gt;The Epoch was on: longDate&lt;/p&gt;&lt;p&gt;The Time was on: shortTime&lt;/p&gt;&lt;p&gt;One million of the local currency: 1000000&lt;/p&gt;&lt;/div&gt; &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151106-javaee-angularjs-bootstrap-multilingual&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-translate.version&gt;2.8.1&lt;/angular-translate.version&gt;    &lt;angular-translate-storage-cookie.version&gt;2.8.0&lt;/angular-translate-storage-cookie.version&gt;    &lt;angular-translate-loader-static-files.version&gt;2.6.1&lt;/angular-translate-loader-static-files.version&gt;    &lt;angular-dynamic-locale.version&gt;0.1.28&lt;/angular-dynamic-locale.version&gt;    &lt;angular-i18n.version&gt;1.4.7&lt;/angular-i18n.version&gt;    &lt;jquery.version&gt;2.1.4&lt;/jquery.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;jquery&lt;/artifactId&gt;      &lt;version&gt;${jquery.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;!-- i18n: LANGUE --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-translate&lt;/artifactId&gt;      &lt;version&gt;${angular-translate.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-translate-storage-cookie&lt;/artifactId&gt;      &lt;version&gt;${angular-translate-storage-cookie.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-translate-loader-static-files&lt;/artifactId&gt;      &lt;version&gt;${angular-translate-loader-static-files.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;!-- l10n: LOCALE --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-dynamic-locale&lt;/artifactId&gt;      &lt;version&gt;${angular-dynamic-locale.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-i18n&lt;/artifactId&gt;      &lt;version&gt;${angular-i18n.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151106-javaee-angularjs-bootstrap-multilingual-i18n-l10nhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151106-javaee-angularjs-bootstrap-multilingual-i18n-l10nReferenceshttps://docs.angularjs.org/guide/i18nhttps://docs.angularjs.org/guide/i18nhttp://www.ng-newsletter.com/posts/angular-translate.htmlhttp://www.ng-newsletter.com/posts/angular-translate.htmlhttps://github.com/SlexAxton/messageformat.jshttps://github.com/SlexAxton/messageformat.jshttps://docs.angularjs.org/api/ngCookies/service/$cookieshttps://docs.angularjs.org/api/ngCookies/service/$cookieshttp://www.famfamfam.com/lab/icons/flags/http://www.famfamfam.com/lab/icons/flags/https://docs.angularjs.org/api/ng/filter/datehttps://docs.angularjs.org/api/ng/filter/datehttps://github.com/lgalfaso/angular-dynamic-localehttps://github.com/lgalfaso/angular-dynamic-localeOriginhttps://damienfremont.com/2015/11/06/javaee-angularjs-bootstrap-how-to-multilingual-i18n-l10n/",
        "url": "/2015/11/06/javaee-angularjs-bootstrap-how-to-multilingual-i18n-l10n"
      },
    
      "2015-11-05-javaee-angularjs-bootstrap-how-to-breadcrumb-and-navbar": {
        "title": "Javaee Angularjs Bootstrap How To Breadcrumb And Navbar",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "A navigation feature: simple responsive navbar, with breadcrumb and home view. Using vanilla AngularJS (because angular-breadcrumb is too complicated: it’s also using ui-router …two frameworks for one feature?).Demohttp://localhost:8080/20151105-javaee-angularjs-bootstrap-breadcrumb/http://localhost:8080/20151105-javaee-angularjs-bootstrap-breadcrumb/After reducing displayed size, navbar’s menu toggle from a bar to a button.A click on ‘Page 1’ button……route to page 1.The URI is also consistant with the route and the view (here #/page1 for page1.html)It’s possible to go further in depth with a third level (here ‘home/page2/subpage’).The URI is consistant ot (here #/page2/subpage for page2subpage.html)All breadcrumb items are clickable (here ‘home’).Sourceindex.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/jquery/${jquery.version}/jquery.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/bootstrap/${bootstrap.version}/js/bootstrap.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body ng-controller=\"MainCtrl\"&gt; &lt;!-- MENU --&gt;&lt;nav class=\"navbar navbar-default\"&gt;&lt;div class=\"container-fluid\"&gt;   &lt;!-- HEADER AND MOBILE BUTTON --&gt;  &lt;div class=\"navbar-header\"&gt;    &lt;button type=\"button\" class=\"navbar-toggle\"      data-toggle=\"collapse\"      data-target=\"#bs-example-navbar-collapse-1\"      aria-expanded=\"true\"&gt;    &lt;span class=\"sr-only\"&gt;Toggle navigation&lt;/span&gt;    &lt;span class=\"icon-bar\"&gt;&lt;/span&gt;    &lt;span class=\"icon-bar\"&gt;&lt;/span&gt;    &lt;span class=\"icon-bar\"&gt;&lt;/span&gt;    &lt;/button&gt;         &lt;!-- LOGO --&gt;    &lt;a class=\"navbar-brand\" href=\"#\"&gt;      Breadcrumb&lt;/a&gt;  &lt;/div&gt;     &lt;!-- MENU ITEMS --&gt;  &lt;div class=\"navbar-collapse collapse\"    id=\"bs-example-navbar-collapse-1\"    aria-expanded=\"true\"&gt;    &lt;ul class=\"nav navbar-nav\"&gt;         &lt;!-- PAGE 1 --&gt;    &lt;li class=\"active\"&gt;      &lt;a href=\"#/page1\"&gt;       Page 1 &lt;span class=\"sr-only\"&gt;         (current)&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;             &lt;!-- PAGE 2 --&gt;    &lt;li class=\"dropdown\"&gt;      &lt;a href=\"#/page2\" class=\"dropdown-toggle\"        data-toggle=\"dropdown\"        role=\"button\"        aria-haspopup=\"true\"        aria-expanded=\"false\"&gt;       Page 2 &lt;span class=\"caret\"&gt;&lt;/span&gt;&lt;/a&gt;       &lt;!-- PAGE 2 SUBMENU --&gt;      &lt;ul class=\"dropdown-menu\"&gt;        &lt;li&gt;&lt;a href=\"#/page2/subpage\"&gt;SubPage&lt;/a&gt;&lt;/li&gt;      &lt;/ul&gt;   &lt;/li&gt;   &lt;/ul&gt;  &lt;/div&gt;&lt;/div&gt;&lt;/nav&gt; &lt;div class=\"container\"&gt; &lt;!-- BREADCRUMB --&gt;&lt;div ng-controller=\"BreadcrumbsController\"&gt;&lt;ol class=\"breadcrumb\"    ng-show=\"route.current.breadcrumbs\"&gt;  &lt;li    ng-class=\"{active: $last}\"    ng-repeat=\"breadcrumb in route.current.breadcrumbs\"&gt;    &lt;a href=\"\"&gt;          &lt;/a&gt;  &lt;/li&gt;&lt;/ol&gt;&lt;/div&gt; &lt;!-- VIEW/PAGE --&gt;&lt;div ng-view&gt;&lt;/div&gt; &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;app.js'use strict'; var app = angular.module('app', [ 'ngRoute' ]); app.config(function($routeProvider) {  $routeProvider //  .when('/page1', {    controller : 'MainCtrl',    templateUrl : 'views/page1.html',    breadcrumbs : [ home, page1 ]  }).when('/page2', {    controller : 'MainCtrl',    templateUrl : 'views/page2.html',    breadcrumbs : [ home, page2 ]  }).when('/page2/subpage', {    controller : 'MainCtrl',    templateUrl : 'views/page2subpage.html',    breadcrumbs : [ home, page2, page2subpage ]  }).otherwise({    templateUrl : 'views/home.html',    breadcrumbs : [ home ]  });}); const home = { href : '#/', label : 'Home' };const page1 = { href : '#/page1', label : 'Page 1' };const page2 = { href : '#/page2', label : 'Page 2' };const page2subpage = { href : '#/page2/subpage', label : 'SubPage' }; app.controller('BreadcrumbsController', function($scope, $route) {  $scope.route = $route;}); app.controller('MainCtrl', function($scope) { });views/home.html&lt;h2&gt;Home&lt;/h2&gt;&lt;p&gt;Lorem ipsum dolor sit amet, consecteturadipiscing elit, sed do eiusmod tempor incididuntut labore et dolore magna aliqua.&lt;/p&gt;views/page1.html&lt;h2&gt;Page 1&lt;/h2&gt;&lt;p&gt;Lorem Ipsum is simply dummy textof the printing and typesetting industry.Lorem Ipsum has been the industry'sstandard dummy text ever since the 1500s&lt;/p&gt;views/page2.html&lt;h2&gt;Page 2&lt;/h2&gt;&lt;p&gt;It is a long established fact that areader will be distracted by the readablecontent of a page when looking at its layout. &lt;/p&gt;views/page2subpage.html&lt;h2&gt;SubPage of Page 2&lt;/h2&gt;&lt;p&gt;Contrary to popular belief, Lorem Ipsum isnot simply random text. It has roots in a pieceof classical Latin literature from 45 BC, makingit over 2000 years old.&lt;/p&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151105-javaee-angularjs-bootstrap-breadcrumb&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;jquery.version&gt;2.1.4&lt;/jquery.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;jquery&lt;/artifactId&gt;      &lt;version&gt;${jquery.version}&lt;/version&gt;    &lt;/dependency&gt;  &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151105-javaee-angularjs-bootstrap-breadcrumbhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151105-javaee-angularjs-bootstrap-breadcrumbReferenceshttp://getbootstrap.com/components/#breadcrumbshttp://getbootstrap.com/components/#breadcrumbsOriginhttps://damienfremont.com/2015/11/05/javaee-angularjs-bootstrap-how-to-breadcrumb-and-navbar/",
        "url": "/2015/11/05/javaee-angularjs-bootstrap-how-to-breadcrumb-and-navbar"
      },
    
      "2015-11-04-javaee-angularjs-bootstrap-how-to-infinite-scroll": {
        "title": "Javaee Angularjs Bootstrap How To Infinite Scroll",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "A simple infinite scroll like Twitter or Facebook’s timelines. You’ll never reach the footer!DemoStart with Tomcat:http://localhost:8080/20151104-javaee-angularjs-bootstrap-infinite_scroll/http://localhost:8080/20151104-javaee-angularjs-bootstrap-infinite_scroll/A simple timeline with Bootstrap components.You can scroll to the end.And there is loading alert and animated progress bar.After loading, the new content is displayed.You can do infinite scroll now.SourceDatasRepository.javapackage com.damienfremont.blog; import java.io.Serializable;import java.util.ArrayList;import java.util.List; import org.springframework.data.domain.Page;import org.springframework.data.domain.PageImpl;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.repository.PagingAndSortingRepository; import com.damienfremont.blog.ServiceJAXRS.Message; public class DatasRepository implements PagingAndSortingRepository&lt;Message, Serializable&gt; {   // MOCK  static List&lt;Message&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; 5000; i++) {      datas.add(new Message(i, \"Shooting star illuminates the Thailand sky\", \"John Doe\", i));    }  }   @Override  public Page&lt;Message&gt; findAll(Pageable arg0) {    int pSize = arg0.getPageSize();    int pNumb = arg0.getPageNumber();    int pFirst = pNumb * pSize;    int pLast = pFirst + pSize;    int total = datas.size();    List&lt;Message&gt; content = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; total; i++) { if (i &gt;= pFirst &amp;&amp; i &lt; pLast) {        Message data = datas.get(i);        content.add(data);      }    }    return new PageImpl&lt;&gt;(content, arg0, total);  }   ...}MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType; import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;  @Path(\"/message\")public class ServiceJAXRS {   DatasRepository datas = new DatasRepository();   @Path(\"/page\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public Page&lt;Message&gt; getAll( //      @QueryParam(\"page\") Integer page, //      @QueryParam(\"size\") Integer size) {    Pageable pageRequest = new PageRequest( //        ((page == null) ? 0 : (page - 1)), //        ((size == null) ? 10 : size));    return datas.findAll(pageRequest);  }   // MODEL  static class Message implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer score;    public String title;    public String author;    public Integer num_comments;     public Message() {    }     public Message(Integer score, String title, String author, Integer num_comments) {      super();      this.score = score;      this.title = title;      this.author = author;      this.num_comments = num_comments;    }  }}web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;init-param&gt;      &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;      &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource',    'infinite-scroll'    ]); app.factory('Service', function($resource) {    return $resource('api/message/page');}); app.controller('MainCtrl', function ($scope, Service) {  const itemsByPage = 10;  var lastStart = 0;  $scope.items = [];  $scope.busy = false;   // GET PAGE  function getAPage(start, number) {    $scope.busy = true;  Service.get({    page : 1+(start/number),    size : number    },    function(pageable) {      $scope.items = $scope.items.concat(pageable.content);        lastStart = start+number;        $scope.busy = false;      });  }     // SCROLL  $scope.addMoreItems = function() {    getAPage(lastStart, itemsByPage);  };     // INIT  getAPage(lastStart, 20);});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/ngInfiniteScroll/${ngInfiniteScroll.version}/build/ng-infinite-scroll.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body ng-controller=\"MainCtrl\"&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;Infinite-Scroll&lt;/h1&gt; &lt;!-- SCROLL --&gt;&lt;div infinite-scroll=\"addMoreItems()\"&gt;     &lt;!-- CONTENT --&gt;&lt;div class=\"list-group\"&gt;&lt;div class=\"list-group-item\" href=\"#\" ng-repeat='i in items'&gt;  &lt;h4 class=\"list-group-item-heading\"&gt;      &lt;/h4&gt;  &lt;p class=\"list-group-item-text\"&gt;    by  - Comments &lt;span class=\"badge\"&gt;&lt;/span&gt;  &lt;/p&gt;  &lt;br&gt;    &lt;a class=\"btn btn-default btn-xs\" href=\"#\"&gt;      &lt;span class=\"glyphicon glyphicon-share-alt\"&gt;&lt;/span&gt; Reply&lt;/a&gt;    &lt;a class=\"btn btn-default btn-xs\" href=\"#\"&gt;      &lt;span class=\"glyphicon glyphicon-retweet\"&gt;&lt;/span&gt; Forward&lt;/a&gt;        &lt;a class=\"btn btn-default btn-xs\" href=\"#\"&gt;      &lt;span class=\"glyphicon glyphicon-star\"&gt;&lt;/span&gt; Like&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt; &lt;!-- LOADING --&gt;&lt;div ng-show='busy'&gt;  Loading data...  &lt;div class=\"progress\"&gt;  &lt;div class=\"progress-bar progress-bar-striped active\" role=\"progressbar\" aria-valuenow=\"45\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 45%\"&gt;    &lt;span class=\"sr-only\"&gt;45% Complete&lt;/span&gt;  &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151104-javaee-angularjs-bootstrap-infinite_scroll&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;ngInfiniteScroll.version&gt;1.2.1&lt;/ngInfiniteScroll.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.springframework.data&lt;/groupId&gt;      &lt;artifactId&gt;spring-data-commons&lt;/artifactId&gt;      &lt;version&gt;1.9.0.RELEASE&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;ngInfiniteScroll&lt;/artifactId&gt;      &lt;version&gt;${ngInfiniteScroll.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151104-javaee-angularjs-bootstrap-infinite_scrollhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151104-javaee-angularjs-bootstrap-infinite_scrollReferenceshttps://github.com/sroze/ngInfiniteScrollhttps://github.com/sroze/ngInfiniteScrollhttp://getbootstrap.com/components/#btn-groups-singlehttp://getbootstrap.com/components/#btn-groups-singleOriginhttps://damienfremont.com/2015/11/04/javaee-angularjs-bootstrap-how-to-infinite-scroll/",
        "url": "/2015/11/04/javaee-angularjs-bootstrap-how-to-infinite-scroll"
      },
    
      "2015-11-03-javaee-angularjs-bootstrap-how-to-sort-with-smart-table": {
        "title": "Javaee Angularjs Bootstrap How To Sort With Smart Table",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "Here is a sortable data-table. Using Twitter Bootstrap,  ng-module SmartTable for front-end. And Spring-Data, Jersey JAXRS for backend.DemoStart with Tomcat:http://localhost:8080/20151103-javaee-angularjs-bootstrap-sort/http://localhost:8080/20151103-javaee-angularjs-bootstrap-sort/A data-table is displayed, with rows and sorter headers.By clicking on row’s header, the row’s data order change and a new icon is displayed.It’s possible to reverse the order.It work with both String and Nubmer type (see Java code).SourceDatasRepository.javapackage com.damienfremont.blog; import static org.springframework.data.domain.Sort.Direction.ASC; import java.io.Serializable;import java.util.ArrayList;import java.util.List; import org.springframework.data.domain.Page;import org.springframework.data.domain.PageImpl;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.domain.Sort.Order;import org.springframework.data.repository.PagingAndSortingRepository; import com.damienfremont.blog.ServiceJAXRS.Person;import com.google.common.base.Function;import com.google.common.collect.Ordering; public class DatasRepository implements PagingAndSortingRepository&lt;Person, Serializable&gt; {   // MOCK  static List&lt;Person&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; 5; i++) {      datas.add(new Person(i + 1, \"John\" + i + 1, \"Doe\"));      i++;      datas.add(new Person(i + 1, \"Mich\" + i + 1, \"Jogger\"));      i++;      datas.add(new Person(i + 1, \"Santa\" + i + 1, \"Close\"));    }  }   @Override  public Page&lt;Person&gt; findAll(Pageable arg0) {    List&lt;Person&gt; content = null;    if (null != arg0.getSort()) {      Order orderById = arg0.getSort().getOrderFor(\"id\");      Order orderByLastName = arg0.getSort().getOrderFor(\"lastName\");      Order orderByFirstName = arg0.getSort().getOrderFor(\"firstName\");      Order order = null;      Function sortBy = null;      if (orderById != null) {        order = orderById;        sortBy = sortById;      } else if (orderByLastName != null) {        order = orderByLastName;        sortBy = sortByLastName;      } else if (orderByFirstName != null) {        order = orderByFirstName;        sortBy = sortByFirstName;      } else {        order = new Order(ASC, \"id\");        sortBy = sortById;      }      Ordering ordering = Ordering //          .natural() //          .onResultOf(sortBy);      boolean isOrderAsc = (order.getDirection() == ASC);      content = isOrderAsc //          ? ordering.sortedCopy(datas) //          : ordering.reverse().sortedCopy(datas);    } else {      content = new ArrayList&lt;&gt;(datas);    }    int total = datas.size();    return new PageImpl&lt;&gt;(content, arg0, total);  }   Function&lt;Person, Integer&gt; sortById = new Function&lt;Person, Integer&gt;() {    public Integer apply(Person foo) {      return foo.id;    }  };   Function&lt;Person, String&gt; sortByFirstName = new Function&lt;Person, String&gt;() {    public String apply(Person foo) {      return foo.firstName;    }  };   Function&lt;Person, String&gt; sortByLastName = new Function&lt;Person, String&gt;() {    public String apply(Person foo) {      return foo.lastName;    }  };...MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import static org.springframework.data.domain.Sort.Direction.ASC;import static org.springframework.data.domain.Sort.Direction.DESC; import java.io.Serializable; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType; import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.domain.Sort.Direction; @Path(\"/person\")public class ServiceJAXRS {   DatasRepository datas = new DatasRepository();   @Path(\"/page\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public Page&lt;Person&gt; getAll( //      @QueryParam(\"sort\") String sortPredicate, //      @QueryParam(\"reverse\") Boolean sortReverse //  ) {    Direction order = sortReverse ? DESC : ASC;    Sort sort = new Sort(order, sortPredicate);    Pageable pageRequest = new PageRequest(0, 100, sort);    Page&lt;Person&gt; page = datas.findAll(pageRequest);    return page;  }   // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer id;    public String firstName;    public String lastName;     public Person() { }     public Person(Integer id, String firstName, String lastName) {      super();      this.id = id;      this.firstName = firstName;      this.lastName = lastName;    }  } }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"    version=\"3.1\"&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;            &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;init-param&gt;            &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;            &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;disableCache&lt;/param-name&gt;            &lt;param-value&gt;true&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource',    'smart-table'    ]); app.factory('Service', function($resource) {    return $resource('api/person/page');}); app.controller('TableCtrl', function ($scope, Service) {       $scope.callServer = function(tableState) {    var sort = tableState.sort;    var predicate = sort.predicate || 'id';    var reverse = sort.reverse || false;    Service.get({        sort : predicate,        reverse : reverse      },      function(pageable) {        $scope.items = pageable.content;    });  };});index.jsp&lt;!DOCTYPE html&gt;&lt;html  ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;link rel=\"stylesheet\" href=\"style.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-smart-table/${angular-smart-table.version}/dist/smart-table.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt; &lt;h1&gt;Sort&lt;/h1&gt;&lt;form  ng-controller=\"TableCtrl\"&gt;&lt;table class=\"table\"  st-table=\"items\"  st-pipe=\"callServer\"&gt;&lt;thead&gt;     &lt;!-- HEADERS --&gt;&lt;tr&gt;  &lt;th st-sort=\"id\"&gt;    &lt;a href=\"#\"&gt;#&lt;/a&gt;&lt;/th&gt;  &lt;th st-sort=\"firstName\"&gt;    &lt;a href=\"#\"&gt;First Name&lt;/a&gt;&lt;/th&gt;  &lt;th st-sort=\"lastName\"&gt;    &lt;a href=\"#\"&gt;Last Name&lt;/a&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;!-- CONTENT --&gt;&lt;tbody&gt;&lt;tr ng-repeat=\"i in items\"&gt;  &lt;td&gt;&lt;/td&gt;  &lt;td&gt;&lt;/td&gt;  &lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;/table&gt;&lt;/form&gt;   &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;style.css.st-sort-ascent:before {  content: '\\25B2';}.st-sort-descent:before {  content: '\\25BC';}Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151103-javaee-angularjs-bootstrap-sorthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151103-javaee-angularjs-bootstrap-sortReferenceshttp://projects.spring.io/spring-data/http://projects.spring.io/spring-data/http://ngmodules.org/modules/Smart-Tablehttp://ngmodules.org/modules/Smart-Tablehttp://lorenzofox3.github.io/smart-table-website/http://lorenzofox3.github.io/smart-table-website/Originhttps://damienfremont.com/2015/11/03/javaee-angularjs-bootstrap-how-to-sort-with-smart-table/",
        "url": "/2015/11/03/javaee-angularjs-bootstrap-how-to-sort-with-smart-table"
      },
    
      "2015-11-02-javaee-angularjs-bootstrap-how-to-pagination-with-smart-table": {
        "title": "Javaee Angularjs Bootstrap How To Pagination With Smart Table",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "A paginated data-table with a back-end inspired by Spring-Data Repository pattern implementation and front-end using Bootstrap pagination and ng-module Smart-Table.Note: there are two famous ng-modules. Ng-Table and SmartTable. Ng-table has a lot of stars on ngmodules.org but I choose Smart-Table instead because it’s latest version is in maven repositories (183 vs 35 stars on ngmodules.org, but 2014 jar vs 2015 on mvnrepository.com).Demohttp://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/http://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/A data-table with page size selector (10, 25, 50) and pagination bar (1,2,3,4,5,&gt;,LAST)Data-table’s page size can be change to 25 or 50.The displayed page can be change to another (2 here).It’s also possible to jump to First or Last page.SourceDatasRepository.javapackage com.damienfremont.blog; import java.io.Serializable;import java.util.ArrayList;import java.util.List;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageImpl;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.repository.PagingAndSortingRepository;import com.damienfremont.blog.ServiceJAXRS.Person; public class DatasRepository implements PagingAndSortingRepository&lt;Person, Serializable&gt; {   // MOCK  static List&lt;Person&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; 5000; i++) {      datas.add(new Person(i + 1, \"John\", \"Doe\"));      i++;      datas.add(new Person(i + 1, \"Mich\", \"Jogger\"));      i++;      datas.add(new Person(i + 1, \"Santa\", \"Close\"));    }  }   @Override  public Page&lt;Person&gt; findAll(Pageable arg0) {    int pSize = arg0.getPageSize();    int pNumb = arg0.getPageNumber();    int pFirst = pNumb * pSize;    int pLast = pFirst + pSize;    int total = datas.size();    List&lt;Person&gt; content = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; total; i++) { if (i &gt;= pFirst &amp;&amp; i &lt; pLast) {        Person data = datas.get(i);        content.add(data);      }    }    return new PageImpl&lt;&gt;(content, arg0, total);  }  ...}MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable;import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable; @Path(\"/person\")public class ServiceJAXRS {   DatasRepository datas = new DatasRepository();   @Path(\"/page\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public Page&lt;Person&gt; getAll( //      @QueryParam(\"sort\") String sort, //      @QueryParam(\"page\") Integer page, //      @QueryParam(\"size\") Integer size) {    Pageable pageRequest = new PageRequest( //        ((page == null) ? 0 : (page-1)), //        ((size == null) ? 10 : size));    return datas.findAll(pageRequest);  }   // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer id;    public String firstName;    public String lastName;     public Person() {     }     public Person(Integer id, String firstName, String lastName) {      super();      this.id = id;      this.firstName = firstName;      this.lastName = lastName;    }  } }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;            &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;init-param&gt;            &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;            &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;disableCache&lt;/param-name&gt;            &lt;param-value&gt;true&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource',    'smart-table'    ]); app.factory('Service', function($resource) {    return $resource('api/person/page');}); app.controller('TableCtrl', function ($scope, Service) {       $scope.itemsByPage = 10;       $scope.callServer = function(tableState) {    $scope.isLoading = true;    var pagination = tableState.pagination;    var start = pagination.start || 0;    var number = pagination.number || $scope.itemsByPage;    Service.get({      page : 1+(start/number),      size : number      },      function(pageable) {        $scope.pageable = pageable;        $scope.items = pageable.content;        tableState.pagination.numberOfPages = pageable.totalPages;        $scope.isLoading = false;    });  };});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-smart-table/${angular-smart-table.version}/dist/smart-table.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;Pagination&lt;/h1&gt;&lt;form ng-controller=\"TableCtrl\"&gt;&lt;table class=\"table\"  st-table=\"items\"  st-pipe=\"callServer\"&gt;&lt;thead&gt; &lt;!-- PAGE SIZE --&gt;&lt;tr&gt;  &lt;td colspan=\"3\"&gt;    &lt;div class=\"btn-group pull-right ng-scope\"&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==10}\"        ng-click=\"itemsByPage=10\"        class=\"btn btn-default\"&gt;10&lt;/button&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==25}\"        ng-click=\"itemsByPage=25\"        class=\"btn btn-default\"&gt;25&lt;/button&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==50}\"        ng-click=\"itemsByPage=59\"        class=\"btn btn-default\"&gt;50&lt;/button&gt;    &lt;/div&gt;  &lt;/td&gt;&lt;/tr&gt;     &lt;!-- HEADERS --&gt;&lt;tr&gt;  &lt;th&gt;#&lt;/th&gt;  &lt;th&gt;First Name&lt;/th&gt;  &lt;th&gt;Last Name&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;!-- CONTENT --&gt;&lt;tbody&gt;&lt;tr ng-repeat=\"i in items\"&gt;  &lt;td&gt;&lt;/td&gt;  &lt;td&gt;&lt;/td&gt;  &lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;!-- PAGINATION --&gt;&lt;tfoot&gt;&lt;tr&gt;  &lt;td colspan=\"3\" class=\"text-center\"&gt;    &lt;div      st-template=\"pagination.html\"      st-pagination=\"\"      st-items-by-page=\"itemsByPage\"&gt;&lt;/div&gt;  &lt;/td&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;/table&gt;&lt;/form&gt;   &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;pagination.html&lt;div class=\"pagination\" ng-if=\"pages.length &gt;= 2\"&gt;  &lt;ul class=\"pagination\"&gt;    &lt;li ng-if=\"currentPage &gt; 1\"&gt;      &lt;a ng-click=\"selectPage(1)\" href=\"#1\"&gt;        FIRST&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &gt; 1\"&gt;      &lt;a ng-click=\"selectPage(currentPage-1)\" href=\"#\"&gt;        &amp;lt;&lt;/a&gt;&lt;/li&gt;    &lt;li ng-repeat=\"page in pages\" ng-class=\"{active: page==currentPage}\"&gt;      &lt;a ng-click=\"selectPage(page)\" href=\"#![alt text](/upload/post-thumbnail-angularjs.png)  A paginated data-table with a back-end inspired by Spring-Data Repository pattern implementation and front-end using Bootstrap pagination and ng-module Smart-Table.Note: there are two famous ng-modules. Ng-Table and SmartTable. Ng-table has a lot of stars on ngmodules.org but I choose Smart-Table instead because it’s latest version is in maven repositories (183 vs 35 stars on ngmodules.org, but 2014 jar vs 2015 on mvnrepository.com). # Demo [http://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/](http://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/)http://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/ A data-table with page size selector (10, 25, 50) and pagination bar (1,2,3,4,5,&gt;,LAST) ![alt text](/upload/160523003531407.png)  Data-table’s page size can be change to 25 or 50. ![alt text](/upload/160523003531930.png)  The displayed page can be change to another (2 here). ![alt text](/upload/160523003531960.png)  It’s also possible to jump to First or Last page. ![alt text](/upload/160523003531986.png)  # Source ![alt text](/upload/160523003532015.png)  DatasRepository.java ```javapackage com.damienfremont.blog; import java.io.Serializable;import java.util.ArrayList;import java.util.List;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageImpl;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.repository.PagingAndSortingRepository;import com.damienfremont.blog.ServiceJAXRS.Person; public class DatasRepository implements PagingAndSortingRepository&lt;Person, Serializable&gt; {   // MOCK  static List&lt;Person&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; 5000; i++) {      datas.add(new Person(i + 1, \"John\", \"Doe\"));      i++;      datas.add(new Person(i + 1, \"Mich\", \"Jogger\"));      i++;      datas.add(new Person(i + 1, \"Santa\", \"Close\"));    }  }   @Override  public Page&lt;Person&gt; findAll(Pageable arg0) {    int pSize = arg0.getPageSize();    int pNumb = arg0.getPageNumber();    int pFirst = pNumb * pSize;    int pLast = pFirst + pSize;    int total = datas.size();    List&lt;Person&gt; content = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; total; i++) { if (i &gt;= pFirst &amp;&amp; i &lt; pLast) {        Person data = datas.get(i);        content.add(data);      }    }    return new PageImpl&lt;&gt;(content, arg0, total);  }  ...}MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable;import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable; @Path(\"/person\")public class ServiceJAXRS {   DatasRepository datas = new DatasRepository();   @Path(\"/page\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public Page&lt;Person&gt; getAll( //      @QueryParam(\"sort\") String sort, //      @QueryParam(\"page\") Integer page, //      @QueryParam(\"size\") Integer size) {    Pageable pageRequest = new PageRequest( //        ((page == null) ? 0 : (page-1)), //        ((size == null) ? 10 : size));    return datas.findAll(pageRequest);  }   // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer id;    public String firstName;    public String lastName;     public Person() {     }     public Person(Integer id, String firstName, String lastName) {      super();      this.id = id;      this.firstName = firstName;      this.lastName = lastName;    }  } }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;            &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;init-param&gt;            &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;            &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;disableCache&lt;/param-name&gt;            &lt;param-value&gt;true&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource',    'smart-table'    ]); app.factory('Service', function($resource) {    return $resource('api/person/page');}); app.controller('TableCtrl', function ($scope, Service) {       $scope.itemsByPage = 10;       $scope.callServer = function(tableState) {    $scope.isLoading = true;    var pagination = tableState.pagination;    var start = pagination.start || 0;    var number = pagination.number || $scope.itemsByPage;    Service.get({      page : 1+(start/number),      size : number      },      function(pageable) {        $scope.pageable = pageable;        $scope.items = pageable.content;        tableState.pagination.numberOfPages = pageable.totalPages;        $scope.isLoading = false;    });  };});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-smart-table/${angular-smart-table.version}/dist/smart-table.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;Pagination&lt;/h1&gt;&lt;form ng-controller=\"TableCtrl\"&gt;&lt;table class=\"table\"  st-table=\"items\"  st-pipe=\"callServer\"&gt;&lt;thead&gt; &lt;!-- PAGE SIZE --&gt;&lt;tr&gt;  &lt;td colspan=\"3\"&gt;    &lt;div class=\"btn-group pull-right ng-scope\"&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==10}\"        ng-click=\"itemsByPage=10\"        class=\"btn btn-default\"&gt;10&lt;/button&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==25}\"        ng-click=\"itemsByPage=25\"        class=\"btn btn-default\"&gt;25&lt;/button&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==50}\"        ng-click=\"itemsByPage=59\"        class=\"btn btn-default\"&gt;50&lt;/button&gt;    &lt;/div&gt;  &lt;/td&gt;&lt;/tr&gt;     &lt;!-- HEADERS --&gt;&lt;tr&gt;  &lt;th&gt;#&lt;/th&gt;  &lt;th&gt;First Name&lt;/th&gt;  &lt;th&gt;Last Name&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;!-- CONTENT --&gt;&lt;tbody&gt;&lt;tr ng-repeat=\"i in items\"&gt;  &lt;td&gt;{{i.id}}&lt;/td&gt;  &lt;td&gt;{{i.firstName}}&lt;/td&gt;  &lt;td&gt;{{i.lastName}}&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;!-- PAGINATION --&gt;&lt;tfoot&gt;&lt;tr&gt;  &lt;td colspan=\"3\" class=\"text-center\"&gt;    &lt;div      st-template=\"pagination.html\"      st-pagination=\"\"      st-items-by-page=\"itemsByPage\"&gt;&lt;/div&gt;  &lt;/td&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;/table&gt;&lt;/form&gt;   &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;pagination.html&lt;div class=\"pagination\" ng-if=\"pages.length &gt;= 2\"&gt;  &lt;ul class=\"pagination\"&gt;    &lt;li ng-if=\"currentPage &gt; 1\"&gt;      &lt;a ng-click=\"selectPage(1)\" href=\"#1\"&gt;        FIRST&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &gt; 1\"&gt;      &lt;a ng-click=\"selectPage(currentPage-1)\" href=\"#\"&gt;        &amp;lt;&lt;/a&gt;&lt;/li&gt;    &lt;li ng-repeat=\"page in pages\" ng-class=\"{active: page==currentPage}\"&gt;      &lt;a ng-click=\"selectPage(page)\" href=\"#{{page}}\"&gt;        {{page}}&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &lt; numPages\"&gt;      &lt;a ng-click=\"selectPage(currentPage+1)\" href=\"#\"&gt;        &amp;gt;&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &lt; numPages\"&gt;      &lt;a ng-click=\"selectPage(numPages)\" href=\"#{{numPages}}\"&gt;        LAST&lt;/a&gt;&lt;/li&gt;  &lt;/ul&gt;&lt;/div&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151102-javaee-angularjs-bootstrap-pagination&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;angular-smart-table.version&gt;2.1.4&lt;/angular-smart-table.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.springframework.data&lt;/groupId&gt;      &lt;artifactId&gt;spring-data-commons&lt;/artifactId&gt;      &lt;version&gt;1.9.0.RELEASE&lt;/version&gt;    &lt;/dependency&gt;      &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-smart-table&lt;/artifactId&gt;      &lt;version&gt;${angular-smart-table.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151102-javaee-angularjs-bootstrap-paginationhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151102-javaee-angularjs-bootstrap-paginationReferenceshttp://projects.spring.io/spring-data/http://projects.spring.io/spring-data/http://ngmodules.org/modules/Smart-Tablehttp://ngmodules.org/modules/Smart-Tablehttp://lorenzofox3.github.io/smart-table-website/http://lorenzofox3.github.io/smart-table-website/http://plnkr.co/edit/e82rdx7R4pjbLvayUHXx?p=previewhttp://plnkr.co/edit/e82rdx7R4pjbLvayUHXx?p=previewOriginhttps://damienfremont.com/2015/11/02/javaee-angularjs-bootstrap-how-to-pagination-with-smart-table/”&gt;        A paginated data-table with a back-end inspired by Spring-Data Repository pattern implementation and front-end using Bootstrap pagination and ng-module Smart-Table.Note: there are two famous ng-modules. Ng-Table and SmartTable. Ng-table has a lot of stars on ngmodules.org but I choose Smart-Table instead because it’s latest version is in maven repositories (183 vs 35 stars on ngmodules.org, but 2014 jar vs 2015 on mvnrepository.com).Demohttp://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/http://localhost:8080/20151102-javaee-angularjs-bootstrap-pagination/A data-table with page size selector (10, 25, 50) and pagination bar (1,2,3,4,5,&gt;,LAST)Data-table’s page size can be change to 25 or 50.The displayed page can be change to another (2 here).It’s also possible to jump to First or Last page.SourceDatasRepository.javapackage com.damienfremont.blog; import java.io.Serializable;import java.util.ArrayList;import java.util.List;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageImpl;import org.springframework.data.domain.Pageable;import org.springframework.data.domain.Sort;import org.springframework.data.repository.PagingAndSortingRepository;import com.damienfremont.blog.ServiceJAXRS.Person; public class DatasRepository implements PagingAndSortingRepository&lt;Person, Serializable&gt; {   // MOCK  static List&lt;Person&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; 5000; i++) {      datas.add(new Person(i + 1, \"John\", \"Doe\"));      i++;      datas.add(new Person(i + 1, \"Mich\", \"Jogger\"));      i++;      datas.add(new Person(i + 1, \"Santa\", \"Close\"));    }  }   @Override  public Page&lt;Person&gt; findAll(Pageable arg0) {    int pSize = arg0.getPageSize();    int pNumb = arg0.getPageNumber();    int pFirst = pNumb * pSize;    int pLast = pFirst + pSize;    int total = datas.size();    List&lt;Person&gt; content = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; total; i++) { if (i &gt;= pFirst &amp;&amp; i &lt; pLast) {        Person data = datas.get(i);        content.add(data);      }    }    return new PageImpl&lt;&gt;(content, arg0, total);  }  ...}MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable;import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.data.domain.Pageable; @Path(\"/person\")public class ServiceJAXRS {   DatasRepository datas = new DatasRepository();   @Path(\"/page\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public Page&lt;Person&gt; getAll( //      @QueryParam(\"sort\") String sort, //      @QueryParam(\"page\") Integer page, //      @QueryParam(\"size\") Integer size) {    Pageable pageRequest = new PageRequest( //        ((page == null) ? 0 : (page-1)), //        ((size == null) ? 10 : size));    return datas.findAll(pageRequest);  }   // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer id;    public String firstName;    public String lastName;     public Person() {     }     public Person(Integer id, String firstName, String lastName) {      super();      this.id = id;      this.firstName = firstName;      this.lastName = lastName;    }  } }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;            &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;init-param&gt;            &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;            &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;REST&lt;/servlet-name&gt;        &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt;     &lt;servlet&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;disableCache&lt;/param-name&gt;            &lt;param-value&gt;true&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;        &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource',    'smart-table'    ]); app.factory('Service', function($resource) {    return $resource('api/person/page');}); app.controller('TableCtrl', function ($scope, Service) {       $scope.itemsByPage = 10;       $scope.callServer = function(tableState) {    $scope.isLoading = true;    var pagination = tableState.pagination;    var start = pagination.start || 0;    var number = pagination.number || $scope.itemsByPage;    Service.get({      page : 1+(start/number),      size : number      },      function(pageable) {        $scope.pageable = pageable;        $scope.items = pageable.content;        tableState.pagination.numberOfPages = pageable.totalPages;        $scope.isLoading = false;    });  };});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-smart-table/${angular-smart-table.version}/dist/smart-table.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;Pagination&lt;/h1&gt;&lt;form ng-controller=\"TableCtrl\"&gt;&lt;table class=\"table\"  st-table=\"items\"  st-pipe=\"callServer\"&gt;&lt;thead&gt; &lt;!-- PAGE SIZE --&gt;&lt;tr&gt;  &lt;td colspan=\"3\"&gt;    &lt;div class=\"btn-group pull-right ng-scope\"&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==10}\"        ng-click=\"itemsByPage=10\"        class=\"btn btn-default\"&gt;10&lt;/button&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==25}\"        ng-click=\"itemsByPage=25\"        class=\"btn btn-default\"&gt;25&lt;/button&gt;      &lt;button type=\"button\"        ng-class=\"{'active':itemsByPage==50}\"        ng-click=\"itemsByPage=59\"        class=\"btn btn-default\"&gt;50&lt;/button&gt;    &lt;/div&gt;  &lt;/td&gt;&lt;/tr&gt;     &lt;!-- HEADERS --&gt;&lt;tr&gt;  &lt;th&gt;#&lt;/th&gt;  &lt;th&gt;First Name&lt;/th&gt;  &lt;th&gt;Last Name&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;!-- CONTENT --&gt;&lt;tbody&gt;&lt;tr ng-repeat=\"i in items\"&gt;  &lt;td&gt;{{i.id}}&lt;/td&gt;  &lt;td&gt;{{i.firstName}}&lt;/td&gt;  &lt;td&gt;{{i.lastName}}&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt; &lt;!-- PAGINATION --&gt;&lt;tfoot&gt;&lt;tr&gt;  &lt;td colspan=\"3\" class=\"text-center\"&gt;    &lt;div      st-template=\"pagination.html\"      st-pagination=\"\"      st-items-by-page=\"itemsByPage\"&gt;&lt;/div&gt;  &lt;/td&gt;&lt;/tr&gt;&lt;/tfoot&gt;&lt;/table&gt;&lt;/form&gt;   &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;pagination.html&lt;div class=\"pagination\" ng-if=\"pages.length &gt;= 2\"&gt;  &lt;ul class=\"pagination\"&gt;    &lt;li ng-if=\"currentPage &gt; 1\"&gt;      &lt;a ng-click=\"selectPage(1)\" href=\"#1\"&gt;        FIRST&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &gt; 1\"&gt;      &lt;a ng-click=\"selectPage(currentPage-1)\" href=\"#\"&gt;        &amp;lt;&lt;/a&gt;&lt;/li&gt;    &lt;li ng-repeat=\"page in pages\" ng-class=\"{active: page==currentPage}\"&gt;      &lt;a ng-click=\"selectPage(page)\" href=\"#{{page}}\"&gt;        {{page}}&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &lt; numPages\"&gt;      &lt;a ng-click=\"selectPage(currentPage+1)\" href=\"#\"&gt;        &amp;gt;&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &lt; numPages\"&gt;      &lt;a ng-click=\"selectPage(numPages)\" href=\"#{{numPages}}\"&gt;        LAST&lt;/a&gt;&lt;/li&gt;  &lt;/ul&gt;&lt;/div&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151102-javaee-angularjs-bootstrap-pagination&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;angular-smart-table.version&gt;2.1.4&lt;/angular-smart-table.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.springframework.data&lt;/groupId&gt;      &lt;artifactId&gt;spring-data-commons&lt;/artifactId&gt;      &lt;version&gt;1.9.0.RELEASE&lt;/version&gt;    &lt;/dependency&gt;      &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-smart-table&lt;/artifactId&gt;      &lt;version&gt;${angular-smart-table.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151102-javaee-angularjs-bootstrap-paginationhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151102-javaee-angularjs-bootstrap-paginationReferenceshttp://projects.spring.io/spring-data/http://projects.spring.io/spring-data/http://ngmodules.org/modules/Smart-Tablehttp://ngmodules.org/modules/Smart-Tablehttp://lorenzofox3.github.io/smart-table-website/http://lorenzofox3.github.io/smart-table-website/http://plnkr.co/edit/e82rdx7R4pjbLvayUHXx?p=previewhttp://plnkr.co/edit/e82rdx7R4pjbLvayUHXx?p=previewOriginhttps://damienfremont.com/2015/11/02/javaee-angularjs-bootstrap-how-to-pagination-with-smart-table/&lt;/a&gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &lt; numPages\"&gt;              &gt;&lt;/li&gt;    &lt;li ng-if=\"currentPage &lt; numPages\"&gt;              LAST&lt;/li&gt;  &lt;/ul&gt;&lt;/div&gt; pom.xml ```xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151102-javaee-angularjs-bootstrap-pagination&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;!-- JAVAEE --&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;!-- WEB --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;angular-smart-table.version&gt;2.1.4&lt;/angular-smart-table.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;${javaee.version}&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.springframework.data&lt;/groupId&gt;      &lt;artifactId&gt;spring-data-commons&lt;/artifactId&gt;      &lt;version&gt;1.9.0.RELEASE&lt;/version&gt;    &lt;/dependency&gt;      &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars.bower&lt;/groupId&gt;      &lt;artifactId&gt;angular-smart-table&lt;/artifactId&gt;      &lt;version&gt;${angular-smart-table.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;  &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151102-javaee-angularjs-bootstrap-paginationhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151102-javaee-angularjs-bootstrap-paginationReferenceshttp://projects.spring.io/spring-data/http://projects.spring.io/spring-data/http://ngmodules.org/modules/Smart-Tablehttp://ngmodules.org/modules/Smart-Tablehttp://lorenzofox3.github.io/smart-table-website/http://lorenzofox3.github.io/smart-table-website/http://plnkr.co/edit/e82rdx7R4pjbLvayUHXx?p=previewhttp://plnkr.co/edit/e82rdx7R4pjbLvayUHXx?p=previewOriginhttps://damienfremont.com/2015/11/02/javaee-angularjs-bootstrap-how-to-pagination-with-smart-table/",
        "url": "/2015/11/02/javaee-angularjs-bootstrap-how-to-pagination-with-smart-table"
      },
    
      "2015-10-31-javaee-angularjs-bootstrap-how-to-filtering": {
        "title": "Javaee Angularjs Bootstrap How To Filtering",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "This tutorial is about a simple field that will filter datas. Using Bootstrap’s Data-Table and AngularJS ng-change event.Demohttp://localhost:8080/20151031-javaee-angularjs-bootstrap-filter/http://localhost:8080/20151031-javaee-angularjs-bootstrap-filter/A simple table with datas from backend.You can type text to search field. Data is filtered in real time.With empty result, datatable is replaced by a warning alert.You can also reset the search filed with the clear button.SourceMyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable;import java.util.ArrayList;import java.util.List; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.QueryParam;import javax.ws.rs.core.MediaType; @Path(\"/person\")public class ServiceJAXRS {   @Path(\"/all\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public List&lt;Person&gt; getAll(      @QueryParam(\"like\") final String like) {  List&lt;Person&gt; res = filter(like);    return res;  }     private List&lt;Person&gt; filter(final String like) {  List&lt;Person&gt; res = new ArrayList&lt;&gt;();  for (Person i : datas) {    boolean isSkipped = false;    for (String likePart : like.split(\" \")) {      String dataLike = (i.id+i.firstName+i.lastName).toLowerCase();      String argLike = likePart.toLowerCase();      if(!dataLike.contains(argLike)) {        isSkipped = true;      }    }    if(!isSkipped) {      res.add(i);    }   }  return res;  }       // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer id;    public String firstName;    public String lastName;    public Person() {     }    public Person(Integer id, String firstName, String lastName) {      super();      this.id = id;      this.firstName = firstName;      this.lastName = lastName;    }  }   // MOCK  static List&lt;Person&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    for (int i = 0; i &lt; 100; i++) {        datas.add(new Person(i+1, \"John\", \"Doe\"));        i++;        datas.add(new Person(i+1, \"Mich\", \"Jogger\"));        i++;        datas.add(new Person(i+1, \"Santa\", \"Close\"));    }  }}web.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;  &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;init-param&gt;      &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;      &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;  &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;&lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource' ]); app.factory('Person', function($resource) {      return $resource('api/person/all');}); app.controller('PersonSearchCtrl', function ($scope, Person) {     $scope.like = '';   $scope.doFilter = function(like) {      $scope.like = like;      Person.query({            like : $scope.like          }, function(datas) {          $scope.items = datas;      });  }   $scope.doClear = function() {      $scope.like = '';      $scope.doFilter($scope.like);  }   $scope.doClear();});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt; &lt;h1&gt;List Filter&lt;/h1&gt; &lt;form ng-controller=\"PersonSearchCtrl\"&gt; &lt;!-- SEARCH INPUT --&gt;&lt;div class=\"row\"&gt;&lt;div class=\"col-lg-6 col-lg-offset-3\"&gt;&lt;div class=\"input-group\"&gt;  &lt;span class=\"input-group-addon\"&gt;    &lt;span class=\"glyphicon glyphicon-search\"&gt;&lt;/span&gt;  &lt;/span&gt;  &lt;input class=\"form-control\" placeholder=\"type anything here to filter the table...\" ng-model=\"like\" ng-change=\"doFilter(like)\"&gt;  &lt;span class=\"input-group-btn\"&gt;    &lt;button class=\"btn btn-primary\" type=\"button\" ng-click=\"doClear()\"&gt;      &lt;span class=\"glyphicon glyphicon-remove\"&gt;&lt;/span&gt; Clear    &lt;/button&gt;  &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt; &lt;!-- RESULTS --&gt;&lt;table ng-show=\"items.length\" id=\"table\" class=\"table table-striped\"&gt;&lt;tr&gt;  &lt;th&gt;#&lt;/th&gt;  &lt;th&gt;First Name&lt;/th&gt;  &lt;th&gt;Last Name&lt;/th&gt;&lt;/tr&gt;&lt;tr ng-repeat=\"i in items\"&gt;  &lt;td&gt;&lt;/td&gt;  &lt;td&gt;&lt;/td&gt;  &lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;   &lt;!-- EMPTY RESULT ALERT --&gt;&lt;strong&gt;Not found!&lt;/strong&gt; Maybe change your criteria filter.   &lt;/form&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;     &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20151031-javaee-angularjs-bootstrap-filter&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;war&lt;/packaging&gt;     &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;!-- JAVAEE --&gt;        &lt;java.version&gt;7&lt;/java.version&gt;        &lt;javaee.version&gt;7.0&lt;/javaee.version&gt;        &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;        &lt;!-- WEB --&gt;        &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;        &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;        &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;/properties&gt;     &lt;dependencies&gt;         &lt;!-- JAVA --&gt;         &lt;dependency&gt;            &lt;groupId&gt;javax&lt;/groupId&gt;            &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;            &lt;version&gt;${javaee.version}&lt;/version&gt;            &lt;scope&gt;provided&lt;/scope&gt;        &lt;/dependency&gt;         &lt;dependency&gt;            &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;            &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;            &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;         &lt;!-- WEB --&gt;         &lt;dependency&gt;            &lt;groupId&gt;org.webjars&lt;/groupId&gt;            &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;            &lt;version&gt;1.1&lt;/version&gt;        &lt;/dependency&gt;         &lt;dependency&gt;            &lt;groupId&gt;org.webjars&lt;/groupId&gt;            &lt;artifactId&gt;angularjs&lt;/artifactId&gt;            &lt;version&gt;${angularjs.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.webjars&lt;/groupId&gt;            &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;            &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;        &lt;/dependency&gt;         &lt;dependency&gt;            &lt;groupId&gt;org.webjars&lt;/groupId&gt;            &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;            &lt;version&gt;${bootstrap.version}&lt;/version&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;resources&gt;            &lt;resource&gt;                &lt;directory&gt;src/main/webapp&lt;/directory&gt;                &lt;filtering&gt;true&lt;/filtering&gt;                &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;                &lt;includes&gt;                    &lt;include&gt;*.jsp&lt;/include&gt;                &lt;/includes&gt;            &lt;/resource&gt;        &lt;/resources&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;                &lt;version&gt;2.6&lt;/version&gt;                &lt;configuration&gt;                    &lt;webResources&gt;                        &lt;resource&gt;                            &lt;directory&gt;src/main/webapp&lt;/directory&gt;                            &lt;filtering&gt;true&lt;/filtering&gt;                            &lt;includes&gt;                                &lt;include&gt;*.jsp&lt;/include&gt;                            &lt;/includes&gt;                        &lt;/resource&gt;                    &lt;/webResources&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.1&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;1.${java.version}&lt;/source&gt;                    &lt;target&gt;1.${java.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151031-javaee-angularjs-bootstrap-filterhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151031-javaee-angularjs-bootstrap-filterReferenceshttp://ng-table.com/#/http://ng-table.com/#/Originhttps://damienfremont.com/2015/10/31/javaee-angularjs-bootstrap-how-to-filtering/",
        "url": "/2015/10/31/javaee-angularjs-bootstrap-how-to-filtering"
      },
    
      "2015-10-27-how-to-cucumber-java-wants-to-quit": {
        "title": "How To Cucumber Java Wants To Quit",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, test",
        "content": "Ruby ExampleAfter do |s|  # Tell Cucumber to quit after this scenario is done - if it failed.  Cucumber.wants_to_quit = true if s.failed?endJava Example@Afterpublic void after(Scenario s) throws Exception {  // Tell Cucumber to quit after this scenario is done - if it failed.  CucumberHooks.wantsToQuit = true == s.isFailed();}Example 1: Wants ot QuitBeforeAfterExample 2: Quit After Tagged Scenario failsBeforeAfterSourceExample 1: Wants ot QuitCucumberHooks .javapackage com.damienfremont.blog.example1; import cucumber.api.Scenario;import cucumber.api.java.Before; public final class CucumberHooks {   public static boolean wantsToQuit = false;   @Before  public void quitIfRequested(Scenario scenario) {    if (wantsToQuit)      throw new RuntimeException(\"Cucumber wants to quit.\");  }}example1.featureFeature: Example Quit   Scenario: success    Given something    When something    Then something   Scenario: failure...    Given something    When something    Then something bad   Scenario: error, because wants to quit    Given something    When something    Then somethingStepDefinitions.javapackage com.damienfremont.blog.example1; import cucumber.api.Scenario;import cucumber.api.java.After;import cucumber.api.java.en.Then;import cucumber.api.java.en.When; public class StepDefinitions {   @When(\"^something$\")  public void do_something() throws Throwable {    // something  }   @Then(\"^something bad$\")  public void quit() throws Throwable {    throw new RuntimeException(\"Fail!\");  }     @After  public void after(Scenario s) throws Exception {    // Tell Cucumber to quit after this scenario is done - if it failed.    CucumberHooks.wantsToQuit = true == s.isFailed();  }}RunTest.javapackage com.damienfremont.blog.example1; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions;import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class)@CucumberOptions(strict = true, features = \"features/example1.feature\")public class RunTest { }Example 2: Quit After Tagged Scenario failsCucumberHooks.javapackage com.damienfremont.blog.example2; import java.util.Collection; import cucumber.api.Scenario;import cucumber.api.java.After;import cucumber.api.java.Before; public final class CucumberHooks {   private static final String TAG = \"@important\";  private static boolean prevScenarioFailed = false;   @After  public void watch_this_tagged_scenario(Scenario scenario) throws Exception {    if (isTagged(scenario)) {      boolean isFailed = scenario.isFailed();      if (isFailed)        prevScenarioFailed = isFailed;    }  }   @Before  public void quit_if_tagged_scenario_failed(Scenario scenario) {    if (!isTagged(scenario) &amp;&amp; prevScenarioFailed)      throw new IllegalStateException(\"An important scenario has failed! Cucumber wants to quit.\");  }   private boolean isTagged(Scenario scenario) {    Collection&lt;String&gt; tags = scenario.getSourceTagNames();    return tags.contains(TAG);  }}example2.featureFeature: Example Quit after tag   @important  Scenario: important 1, and fails    Given something    When fail    Then something   @important  Scenario: important 2, but run it anyway    Given something    When something    Then something   Scenario: optionnal, error because wants to quit    Given something    When something    Then somethingStepDefinitions.javapackage com.damienfremont.blog.example2; import cucumber.api.java.en.Then;import cucumber.api.java.en.When; public class StepDefinitions {   @When(\"^something$\")  public void do_something() throws Throwable {    // something  }   @Then(\"^fail$\")  public void fail() throws Throwable {    throw new RuntimeException(\"Fail!\");  }}RunTest .javapackage com.damienfremont.blog.example2; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions;import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class)@CucumberOptions(strict = true, features = \"features/example2.feature\")public class RunTest { }ConclusionNow, you have faster feedback:  small execution time when all your tests fail (good for Continuous Integration).  much readable results with multiple failures, instead of semi-skipped/failed state for each scenario (reporting)Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151027-test-cucumber-wants_to_quitReferenceshttps://github.com/cucumber/cucumber/wiki/Hookshttps://github.com/cucumber/cucumber-java-skeletonhttp://stackoverflow.com/questions/15272523/what-is-the-cucumber-jvm-equivalent-of-cucumber-wants-to-quitOriginhttps://damienfremont.com/2015/10/27/how-to-cucumber-java-wants-to-quit/",
        "url": "/2015/10/27/how-to-cucumber-java-wants-to-quit"
      },
    
      "2015-10-20-javaee-angularjs-bootstrap-datatable-and-excel-export": {
        "title": "Javaee Angularjs Bootstrap Datatable And Excel Export",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "This is a read-only table with a CSV export button, then an editable table form like Excel tab (DataTable) with add, remove, undo and update buttons. There is also a default focus on last editable row.Demohttp://localhost:8080/20151020-javaee-angularjs-bootstrap-table_export/http://localhost:8080/20151020-javaee-angularjs-bootstrap-table_export/Here is a read-only table with CSV Export Button, from REST API @GET /person/allA CSV file is send by REST API @GET /person/all/csv.Here is a DataTable, editable like an Excel Window, with focus set on the last row’s cell.You can add or remove table’s row with buttons, then update.And send to REST API @POST /person/all.SourceGenerateCSV.javapackage com.damienfremont.blog; import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.util.List; import com.damienfremont.blog.ServiceJAXRS.Person; public class GenerateCSV {   public static File generateCsvFile(List&lt;Person&gt; datas) {    try {      File file = new File(\"temp\");      FileWriter writer = new FileWriter(file);      char separator = ';';      for (Person i : datas) {        writer.append(i.id.toString());        writer.append(separator);        writer.append(i.firstName);        writer.append(separator);        writer.append(i.lastName);        writer.append('\\n');      }      writer.flush();      writer.close();      return file;    } catch (IOException e) {      throw new RuntimeException();    }  } }MyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.File;import java.io.Serializable;import java.util.ArrayList;import java.util.List; import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response;import javax.ws.rs.core.Response.ResponseBuilder; @Path(\"/person\")public class ServiceJAXRS {   @Path(\"/all\")  @GET  @Produces(MediaType.APPLICATION_JSON)  public List&lt;Person&gt; getAll() {    return datas;  }     @Path(\"/all\")  @POST  @Consumes(MediaType.APPLICATION_JSON)  public void saveAll(List&lt;Person&gt;  datas) {    this.datas = datas;  }     @GET  @Path(\"/all/csv\")  @Produces(\"application/pdf\")  public Response getFile() {    File file = GenerateCSV.generateCsvFile(datas);    ResponseBuilder response = Response.ok((Object) file);    String filename = \"export.csv\";    response.header(\"Content-Disposition\", \"attachment; filename=\"+filename);    return response.build();  }   // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public Integer id;    public String firstName;    public String lastName;    public Person() {     }    public Person(Integer id, String firstName, String lastName) {      this.id = id;      this.firstName = firstName;      this.lastName = lastName;    }     }   // MOCK  static List&lt;Person&gt; datas;  static {    datas = new ArrayList&lt;&gt;();    datas.add(new Person(1, \"Albert\", \"Einstein\"));    datas.add(new Person(2, \"Isaac\", \"Newton\"));    datas.add(new Person(3, \"Marie\", \"Curie\"));  }}web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;init-param&gt;      &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;      &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngResource' ]); app.factory('Person', function($resource) {      return $resource('api/person/all');}); //TABLE app.factory('PersonCSV', function($resource) {      return 'api/person/all/csv';}); app.controller('TableCtrl', function ($scope, Person, PersonCSV, $window) {   Person.query(function(datas) {      $scope.items = datas;  });     $scope.downloadCSV = function() {      var url = PersonCSV;      $window.open(url);  }}); // DATATABLE app.controller('DataTableCtrl', function ($scope, Person) {   Person.query(function(datas) {    $scope.items = datas;  });         $scope.add = function() {    var nextId = $scope.items[$scope.items.length - 1].id + 1;    $scope.items.push({        id: nextId    })  };         $scope.remove = function(data) {    var i = $scope.items.indexOf(data);    $scope.items.splice(i, 1);  }     $scope.update = function() {    Person.save($scope.items ,function() {      alert('updated!');    }, function() {      alert('error!');    });  };     $scope.undo = function() {    Person.query(function(datas) {      $scope.items = datas;    });  }   }); app.directive('focus', function($timeout) {  return {    scope : {      trigger : '@focus'    },    link : function(scope, element) {      scope.$watch('trigger', function(value) {        if (value === \"true\") {          $timeout(function() {            element[0].focus();          });        }      });    }  };}); app.directive('contenteditable', function() {  return {    require: 'ngModel',    link: function(scope, elm, attrs, ctrl) {      // view -&gt; model       elm.bind('blur', function() {         scope.$apply(function() {           ctrl.$setViewValue(elm.html());         });       });       // model -&gt; view       ctrl.render = function(value) {         elm.html(value);       };       elm.bind('keydown', function(event) {         var esc = event.which == 27,         el = event.target;         if (esc) {           ctrl.$setViewValue(elm.html());           el.blur();           event.preventDefault();         }       });    }  };});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt;&lt;h1&gt;DataTable&lt;/h1&gt;     &lt;!-- SIMPLE TABLE --&gt;&lt;form name=\"readForm\" ng-controller=\"TableCtrl\"&gt;  &lt;h2&gt;Read-Only, Export&lt;/h2&gt;  &lt;!-- TABLE --&gt;  &lt;table id=\"table\"  class=\"table table-bordered table-striped\"&gt;    &lt;tr&gt;      &lt;th&gt;#&lt;/th&gt;      &lt;th&gt;First Name&lt;/th&gt;      &lt;th&gt;Last Name&lt;/th&gt;    &lt;/tr&gt;    &lt;tr ng-repeat=\"i in items\"&gt;      &lt;td&gt;&lt;/td&gt;      &lt;td&gt;&lt;/td&gt;      &lt;td&gt;&lt;/td&gt;    &lt;/tr&gt;  &lt;/table&gt;  &lt;!-- EXPORT --&gt;  &lt;button class=\"btn btn-success\"    ng-click=\"downloadCSV()\"&gt;    &lt;i class=\"glyphicon glyphicon-export\"&gt;&lt;/i&gt; Export to Excel  &lt;/button&gt;&lt;/form&gt; &lt;!-- DATATABLE --&gt;     &lt;form name=\"editForm\" ng-controller=\"DataTableCtrl\"&gt;  &lt;h2&gt;Editable, Excel-like&lt;/h2&gt;  &lt;!-- TABLE --&gt;  &lt;table id=\"datatable\" class=\"table table-bordered table-hover\"&gt;    &lt;tr&gt;      &lt;th&gt;#&lt;/th&gt;      &lt;th&gt;First Name&lt;/th&gt;      &lt;th&gt;Last Name&lt;/th&gt;      &lt;th&gt;&lt;/th&gt;    &lt;/tr&gt;    &lt;tr ng-repeat=\"i in items\"&gt;      &lt;td&gt;&lt;/td&gt;      &lt;td contentEditable='true'        focus=\"true\"        ng-model=\"i.firstName\"&gt;&lt;/td&gt;      &lt;td contentEditable='true'        ng-model=\"i.lastName\"&gt;&lt;/td&gt;      &lt;td&gt;        &lt;!-- REMOVE --&gt;        &lt;button class=\"btn btn-danger btn-xs\"          ng-click=\"remove(i)\"&gt;          &lt;i class=\"glyphicon glyphicon-minus\"&gt;&lt;/i&gt;         &lt;/button&gt;      &lt;/td&gt;    &lt;/tr&gt;    &lt;!-- ADD --&gt;    &lt;tr&gt;      &lt;td colspan=\"4\"&gt;        &lt;button class=\"btn btn-primary btn-xs\"          ng-click=\"add()\"&gt;          &lt;i class=\"glyphicon glyphicon-plus\"&gt;&lt;/i&gt; Add row         &lt;/button&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/table&gt;  &lt;!-- UPDATE --&gt;  &lt;button class=\"btn btn-success\"    ng-click=\"update()\" ng&gt;    &lt;i class=\"glyphicon glyphicon-save\"&gt;&lt;/i&gt; Update  &lt;/button&gt;  &lt;!-- UNDO --&gt;  &lt;button class=\"btn btn-warning\"    ng-click=\"undo()\"&gt;    &lt;i class=\"glyphicon glyphicon-remove\"&gt;&lt;/i&gt; Undo Changes  &lt;/button&gt;&lt;/form&gt;     &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151020-javaee-angularjs-bootstrap-table_exporthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151020-javaee-angularjs-bootstrap-table_exportReferenceshttps://docs.angularjs.org/api/ng/directive/ngRepeathttps://docs.angularjs.org/api/ng/directive/ngRepeathttp://getbootstrap.com/css/#tableshttp://getbootstrap.com/css/#tableshttp://www.mkyong.com/java/how-to-export-data-to-csv-file-java/http://www.mkyong.com/java/how-to-export-data-to-csv-file-java/http://www.mkyong.com/webservices/jax-rs/download-pdf-file-from-jax-rs/http://www.mkyong.com/webservices/jax-rs/download-pdf-file-from-jax-rs/http://www.angulartutorial.net/2014/04/angular-js-auto-focus-for-input-box.htmlhttp://www.angulartutorial.net/2014/04/angular-js-auto-focus-for-input-box.htmlhttp://jsfiddle.net/bonamico/cahz7/http://jsfiddle.net/bonamico/cahz7/Originhttps://damienfremont.com/2015/10/20/javaee-angularjs-bootstrap-datatable-and-excel-export/",
        "url": "/2015/10/20/javaee-angularjs-bootstrap-datatable-and-excel-export"
      },
    
      "2015-10-19-javaee-angularjs-bootstrap-file-upload": {
        "title": "Javaee Angularjs Bootstrap File Upload",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "A simple picture upload with preview with alert messages for avatar and a multiple files upload with progress bar.Demohttp://localhost:8080/20151019-javaee-angularjs-bootstrap-upload_file/http://localhost:8080/20151019-javaee-angularjs-bootstrap-upload_file/Here is Picture upload.Here is multiple files upload.SourceMyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream; import javax.ws.rs.Consumes;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.WebApplicationException;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;import org.glassfish.jersey.media.multipart.FormDataParam; @Path(\"/upload\")public class ServiceJAXRS {     @POST    @Path(\"/file\")    @Consumes({MediaType.MULTIPART_FORM_DATA})    public Response uploadFile(            @FormDataParam(\"file\") InputStream fileInputStream,            @FormDataParam(\"file\") FormDataContentDisposition fileMetaData) throws Exception {        try {            int read = 0;            byte[] bytes = new byte[1024];            File file = new File(fileMetaData.getFileName());            System.out.println(\"Upload File Path : \"+file.getAbsolutePath());            OutputStream out = new FileOutputStream(file);            while ((read = fileInputStream.read(bytes)) != -1) {                out.write(bytes, 0, read);            }            out.flush();            out.close();        } catch (IOException e) {            throw new WebApplicationException(\"Error while uploading file. Please try again !!\");        }        return Response.ok(\"Data uploaded successfully !!\").build();    }     }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;init-param&gt;      &lt;param-name&gt;jersey.config.server.provider.classnames&lt;/param-name&gt;      &lt;param-value&gt;org.glassfish.jersey.media.multipart.MultiPartFeature&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var app = angular.module(  'app',  [ 'ngAnimate',    'ui.bootstrap',    'ngResource',    'ngFileUpload' ]); app.factory('Model', function($resource) {  return $resource('api/upload');}); app.controller('SubmitFileCtrl', function ($scope, Upload, $timeout) {  $scope.uploadPic = function(file) {  file.upload = Upload.upload({    url: 'api/upload/file',    data: {file: file },  });  file.upload.then(function (response) {    $timeout(function () {    file.result = response.data;    });  }, function (response) {    if (response.status &gt; 0)    $scope.errorMsg = \"Server Error! (\"+response.data+\")\";  }, function (evt) {    // Math.min is to fix IE which reports 200% sometimes    file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));  });  }}); app.controller('FilesCtrl', function ($scope, Upload, $timeout) {  $scope.uploadFiles = function(files, errFiles) {    $scope.files = files;    $scope.errFiles = errFiles;    angular.forEach(files, function(file) {      file.upload = Upload.upload({        url: 'api/upload/file',        data: {file: file}      });       file.upload.then(function (response) {        $timeout(function () {          file.result = response.data;        });      }, function (response) {        if (response.status &gt; 0)          $scope.errorMsg = response.status + ': ' + response.data;      }, function (evt) {        file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));      });    });  }});index.jsp&lt;!DOCTYPE html&gt;&lt;html ng-app=\"app\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;link rel=\"stylesheet\" href=\"styles.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/ng-file-upload/${ng-file-upload.version}/ng-file-upload.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;  &lt;div class=\"container\"&gt;        &lt;!-- PICTURE FILE --&gt;        &lt;form name=\"myForm\" ng-controller=\"SubmitFileCtrl\"&gt;     &lt;h1&gt;Picture&lt;/h1&gt;     &lt;p&gt;Upload Picture on form submit, Alerts&lt;/p&gt;     &lt;!-- BROWSE --&gt;     &lt;div class=\"form-group\"&gt;       &lt;input type=\"file\"         ngf-select         ng-model=\"picFile\" name=\"file\"            accept=\"image/*\"         ngf-max-size=\"2MB\"         required&gt;         &lt;i ng-show=\"myForm.file.$error.maxSize\"&gt;File too large MB: max 2M&lt;/i&gt;     &lt;/div&gt;     &lt;!-- PREVIEW --&gt;     &lt;div class=\"form-group\"&gt;       &lt;img class=\"thumb\"         ng-show=\"myForm.file.$valid\"         ngf-thumbnail=\"picFile\"&gt;       &lt;button class=\"btn btn-danger btn-xs\"         ng-click=\"picFile = null\"         ng-show=\"picFile\"&gt;         &lt;i class=\"glyphicon glyphicon-remove\"&gt;&lt;/i&gt; Remove       &lt;/button&gt;     &lt;/div&gt;     &lt;!-- SUBMIT --&gt;     &lt;button class=\"btn btn-success\"       ng-disabled=\"!myForm.$valid\"       ng-click=\"uploadPic(picFile)\"&gt;       &lt;i class=\"glyphicon glyphicon-ok\"&gt;&lt;/i&gt; Submit     &lt;/button&gt;     &lt;!-- ALERT --&gt;     &lt;p&gt;       &lt;div class=\"alert alert-danger\" ng-show=\"errorMsg\"&gt;Upload Error!&lt;/div&gt;       &lt;div class=\"alert alert-success\" ng-show=\"picFile.result\"&gt;Upload Successful.&lt;/div&gt;     &lt;/p&gt;    &lt;/form&gt;         &lt;!-- FILES --&gt;         &lt;form ng-controller=\"FilesCtrl\"&gt;      &lt;h1&gt;Files&lt;/h1&gt;      &lt;p&gt;Multiples Files, Progress Bars&lt;/p&gt;     &lt;!-- BROWSE --&gt;      &lt;div class=\"form-group\"&gt;        &lt;button class=\"btn btn-primary\"          ngf-select=\"uploadFiles($files)\"          multiple          accept=\"*\"&gt;          &lt;i class=\"glyphicon glyphicon-folder-open\"&gt;&lt;/i&gt;&amp;nbsp;&amp;nbsp;Browse Files        &lt;/button&gt;      &lt;/div&gt;      Files:      &lt;div class=\"uploadedfile\" ng-repeat=\"f in files\" style=\"font:smaller\"&gt;        &lt;!-- FILE --&gt;        &lt;i class=\"glyphicon glyphicon-file\"&gt;&lt;/i&gt;&lt;span ng-class=\"{removed: f.removed}\"&gt; &lt;/span&gt;        &lt;!-- PROGRESS --&gt;        &lt;div class=\"progress\" ng-show=\"f.progress &gt;= 0\"&gt;          &lt;div class=\"progress-bar progress-bar-success\" role=\"progressbar\"            aria-valuenow=\"\" aria-valuemin=\"0\" aria-valuemax=\"100\"            style=\"width: %\"&gt;            &lt;span class=\"sr-only\"&gt;% Complete&lt;/span&gt; %          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;          &lt;/form&gt;       &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;styles.css.thumb {    width: 24px;    height: 24px;    float: none;    position: relative;}Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151019-javaee-angularjs-bootstrap-upload_filehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151019-javaee-angularjs-bootstrap-upload_fileReferenceshttps://github.com/danialfarid/ng-file-uploadhttps://github.com/danialfarid/ng-file-uploadhttps://angular-file-upload.appspot.com/https://angular-file-upload.appspot.com/http://howtodoinjava.com/2015/08/05/jersey-file-upload-example/http://howtodoinjava.com/2015/08/05/jersey-file-upload-example/Originhttps://damienfremont.com/2015/10/19/javaee-angularjs-bootstrap-file-upload/",
        "url": "/2015/10/19/javaee-angularjs-bootstrap-file-upload"
      },
    
      "2015-10-17-javaee-angularjs-bootstrap-form-bean-validation-front-and-back": {
        "title": "Javaee Angularjs Bootstrap Form Bean Validation Front And Back",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "Dual Validation, on Web side and Server side (UI and API), using AngularJs Validation directives and JavaEE BeanValidation API.DemoA simple User form, with REST HTTP Get then Post.Disable submit button with tag (if form is $invalid).ng-valid and ng-invalid will automatically determine if a field is valid based on the tags placed in your form.Her we are testing the back end validation, which is more extended than UI ValidationValidation: Birth Year &lt; 2015This message is from the Java Server.Here the HTTP Request.and Response from Java Server (Bad Request).Sourcehttp://localhost:8080/20151017-javaee-angularjs-bootstrap-form-bean_validation/#/personhttp://localhost:8080/20151017-javaee-angularjs-bootstrap-form-bean_validation/#/personMyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(PersonJAXRS.class);    return s;  }}PersonJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable; import javax.validation.Valid;import javax.validation.constraints.DecimalMax;import javax.validation.constraints.NotNull;import javax.validation.executable.ValidateOnExecution;import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType; import org.hibernate.validator.constraints.Email;  @Path(\"/person\")public class PersonJAXRS {   // READ  @GET  @Produces(MediaType.APPLICATION_JSON)  public Person get() {    return data;  }     // UPDATE  @POST  @Consumes(MediaType.APPLICATION_JSON)  @ValidateOnExecution  public void post(@Valid Person data) {    this.data = data;  }     // MODEL  static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    @NotNull    public String firstName;    @NotNull    public String lastName;    @NotNull    @DecimalMax(\"2015\")    public Integer birthYear;    @Email    public String email;  }     // MOCK  static Person data;  static {    data = new Person();    data.firstName = \"Albert\";    data.lastName = \"Einstein\";    data.birthYear= 1909;    data.email= \"aeinstein@lycos.com\";  } }web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var myApp = angular.module(  'myApp',  [ 'ngAnimate',    'ui.bootstrap',    'ngRoute',    'ngResource']); myApp.controller('AlertCtrl', function($scope) {  $scope.alerts = [ ];  $scope.closeAlert = function(index) {    $scope.alerts.splice(index, 1);  };}); myApp.factory('Person', function($resource) {    return $resource('api/person');}); myApp.controller('PersonCtrl', function($scope, Person, $location) {       // READ  Person.get(function(obj) {     $scope.person = obj;  });     // SAVE  $scope.update = function() {    Person.save($scope.person ,function(obj) {      // this callback will be called asynchronously      // when the response is available      $scope.person = obj;      $location.path( \"/person\" );      $scope.$parent.alerts.push({type: 'success', msg: 'Updated!'});    }, function(error) {      // called asynchronously if an error occurs      // or server returns response with an error status.      $scope.$parent.alerts.push({type: 'danger', msg: 'Server: '+error.statusText});    });  }});index.jsp&lt;html ng-app=\"myApp\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;link rel=\"stylesheet\" href=\"styles.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;  &lt;div class=\"container\" ng-controller=\"AlertCtrl\"&gt;    &lt;h1&gt;Person&lt;/h1&gt;     &lt;!-- ALERT --&gt;    &lt;uib-alert ng-repeat=\"alert in alerts\" type=\"\" close=\"closeAlert($index)\"&gt;&lt;/uib-alert&gt;     &lt;!-- FORM --&gt;    &lt;form class=\"form-horizontal\" ng-controller=\"PersonCtrl\" name=\"userForm\"&gt;      &lt;div class=\"form-group\"&gt;        &lt;label class=\"col-sm-2 control-label\"&gt;First Name&lt;/label&gt;        &lt;div class=\"col-sm-10\"&gt;          &lt;input class=\"form-control\" placeholder=\"FirstName...\" ng-model=\"person.firstName\"          required&gt; &lt;!-- VALIDATION HERE --&gt;        &lt;/div&gt;      &lt;/div&gt;      &lt;div class=\"form-group\"&gt;        &lt;label class=\"col-sm-2 control-label\"&gt;Last Name&lt;/label&gt;        &lt;div class=\"col-sm-10\"&gt;          &lt;input class=\"form-control\" placeholder=\"Last Name...\" ng-model=\"person.lastName\"          required&gt; &lt;!-- VALIDATION HERE --&gt;        &lt;/div&gt;      &lt;/div&gt;      &lt;div class=\"form-group\"&gt;        &lt;label class=\"col-sm-2 control-label\"&gt;Birth Year&lt;/label&gt;        &lt;div class=\"col-sm-10\"&gt;          &lt;input class=\"form-control\" placeholder=\"Birth Year...\" ng-model=\"person.birthYear\" type=\"number\"          required&gt; &lt;!-- VALIDATION HERE --&gt;        &lt;/div&gt;      &lt;/div&gt;      &lt;div class=\"form-group\"&gt;        &lt;label class=\"col-sm-2 control-label\"&gt;E-Mail&lt;/label&gt;        &lt;div class=\"col-sm-10\"&gt;          &lt;input class=\"form-control\" placeholder=\"E-Mail...\" ng-model=\"person.email\" type=\"email\"          required&gt; &lt;!-- VALIDATION HERE --&gt;        &lt;/div&gt;      &lt;/div&gt;      &lt;!-- BUTTON --&gt;      &lt;div class=\"form-group\"&gt;        &lt;div class=\"col-sm-offset-2 col-sm-10\"&gt;          &lt;button type=\"submit\" class=\"btn btn-primary\" ng-click=\"update()\"            ng-disabled=\"userForm.$invalid\"&gt; &lt;!-- VALIDATION HERE --&gt;            Update&lt;/button&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/form&gt;&lt;/body&gt;&lt;/html&gt;styles.cssform input.ng-invalid.ng-touched {  background-color: #f2dede;}pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151017-javaee-angularjs-bootstrap-form-bean_validation&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;7.0&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.ext&lt;/groupId&gt;      &lt;artifactId&gt;jersey-bean-validation&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;    &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;     &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151017-javaee-angularjs-bootstrap-validationhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151017-javaee-angularjs-bootstrap-validationReferenceshttp://blog.xebia.fr/2010/07/15/bean-validation/http://blog.xebia.fr/2010/07/15/bean-validation/https://docs.angularjs.org/guide/formshttps://docs.angularjs.org/guide/formsOriginhttps://damienfremont.com/2015/10/17/javaee-angularjs-bootstrap-form-bean-validation-front-and-back/",
        "url": "/2015/10/17/javaee-angularjs-bootstrap-form-bean-validation-front-and-back"
      },
    
      "2015-10-17-javaee-angularjs-bootstrap-date-picker": {
        "title": "Javaee Angularjs Bootstrap Date Picker",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "Build a DatePicker with AngularUI Widget from Bootstrap and post it to a REST Java server with Jersey and Bean Validation.Demohttp://localhost:8080/20151018-javaee-angularjs-bootstrap-datepicker/http://localhost:8080/20151018-javaee-angularjs-bootstrap-datepicker/A responsive layout switching from large to small screen.A post to Java Server with transformation from Javascript Date to JSON String.A DatePicker widget.And back end validation on futur Date.SourceMyAppCONFIG.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyAppCONFIG extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(ServiceJAXRS.class);    return s;  }}ServiceJAXRS.javapackage com.damienfremont.blog; import java.io.Serializable;import java.util.Date; import javax.validation.Valid;import javax.validation.constraints.NotNull;import javax.validation.constraints.Past;import javax.validation.executable.ValidateOnExecution;import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;  @Path(\"/\")public class ServiceJAXRS {     // READ  @GET  @Produces(MediaType.APPLICATION_JSON)  public Model get() {    return data;  }     // UPDATE  @POST  @Consumes(MediaType.APPLICATION_JSON)  @ValidateOnExecution  public void post(@Valid Model data) {    this.data = data;  }     // MODEL  static class Model implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    @Past    public Date testDateInput;    @Past    public Date testDatePicker;  }     // MOCK  static Model data;  static {    data = new Model();    data.testDateInput= new Date();    data.testDatePicker= new Date();  }}web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyAppCONFIG&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;app.js'use strict'; var myApp = angular.module(  'myApp',  [ 'ngAnimate',    'ui.bootstrap',    'ngResource']); myApp.controller('AlertCtrl', function($scope) {  $scope.alerts = [ ];  $scope.closeAlert = function(index) {    $scope.alerts.splice(index, 1);  };}); myApp.factory('Model', function($resource) {  return $resource('api', {}, {    get: {      transformResponse: function(data, headers) {        // MAP DATES        var data = angular.fromJson(data);        data.testDateInput  = data.testDateInput  === null ? null : new Date(data.testDateInput);        data.testDatePicker = data.testDatePicker === null ? null : new Date(data.testDatePicker);        return data;      }    }  });}); myApp.controller('DatepickerCtrl', function($scope, Model, $location) {       // READ  Model.get(function(obj) {    $scope.model = obj;  });     // UPDATE  $scope.update = function() {    Model.save($scope.model, function(obj) {      $scope.$parent.alerts.push({type: 'success', msg: 'Updated!'});    }, function(error) {      $scope.$parent.alerts.push({type: 'danger', msg: 'Server: '+error.statusText});    });  }     // DATEPICKER BUTTON  $scope.status = { opened: false };  $scope.open = function($event) {    $scope.status.opened = true;  };  });index.jsp&lt;!DOCTYPE html&gt; &lt;!-- DON'T FORGET DOCTYPE OR THERE WILL BE .btn CLASS HEIGHT BUGS! https://github.com/twbs/bootstrap/issues/10482 --&gt;&lt;html ng-app=\"myApp\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"app.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;  &lt;div class=\"container\" ng-controller=\"AlertCtrl\"&gt;    &lt;h1&gt;Date&lt;/h1&gt;     &lt;!-- ALERT --&gt;    &lt;uib-alert ng-repeat=\"alert in alerts\" type=\"\" close=\"closeAlert($index)\"&gt;&lt;/uib-alert&gt;     &lt;!-- FORM --&gt;    &lt;form class=\"form-horizontal\" ng-controller=\"DatepickerCtrl\"&gt;        &lt;!-- DATE INPUT --&gt;       &lt;div class=\"form-group\"&gt;        &lt;label class=\"col-sm-3 control-label\"&gt;Input to Java String&lt;/label&gt;        &lt;div class=\"col-sm-6\"&gt;          &lt;input class=\"form-control\" ng-model=\"model.testDateInput\"            type=\"date\"&gt;        &lt;/div&gt;      &lt;/div&gt;             &lt;!-- DATEPICKER --&gt;             &lt;div class=\"form-group\"&gt;        &lt;label class=\"col-sm-3 control-label\"&gt;Widget to Java String&lt;/label&gt;        &lt;div class=\"col-sm-6\"&gt;            &lt;p class=\"input-group\"&gt;              &lt;input class=\"form-control\" ng-model=\"model.testDatePicker\"                type=\"date\"                uib-datepicker-popup                is-open=\"status.opened\"                datepicker-options=\"dateOptions\"                date-disabled=\"disabled(date, mode)\"                close-text=\"Close\" /&gt;              &lt;span class=\"input-group-btn\"&gt;                &lt;button type=\"button\" class=\"btn btn-default\"                  ng-click=\"open($event)\"&gt;&lt;i class=\"glyphicon glyphicon-calendar\"&gt;&lt;/i&gt;                &lt;/button&gt;              &lt;/span&gt;            &lt;/p&gt;        &lt;/div&gt;      &lt;/div&gt;             &lt;!-- UPDATE --&gt;      &lt;div class=\"form-group\"&gt;        &lt;div class=\"col-sm-offset-3 col-sm-9\"&gt;          &lt;button type=\"submit\" class=\"btn btn-primary\" ng-click=\"update()\"&gt;Update&lt;/button&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/form&gt;&lt;/body&gt;&lt;/html&gt;pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151018-javaee-angularjs-bootstrap-datepicker&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;7.0&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.ext&lt;/groupId&gt;      &lt;artifactId&gt;jersey-bean-validation&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;    &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;     &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;BUG: DatePicker Button HeightDon’t forget &lt;!DOCTYPE html&gt; or there will be .btn CLass height bugs!https://github.com/twbs/bootstrap/issues/10482https://github.com/twbs/bootstrap/issues/10482Projecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151018-javaee-angularjs-bootstrap-datepickerhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151018-javaee-angularjs-bootstrap-datepickerReferenceshttps://angular-ui.github.io/bootstrap/https://angular-ui.github.io/bootstrap/https://docs.angularjs.org/api/ng/filter/datehttps://docs.angularjs.org/api/ng/filter/datehttps://docs.angularjs.org/api/ng/input/input%5Bdate%5Dhttps://docs.angularjs.org/api/ng/input/input%5Bdate%5Dhttps://docs.angularjs.org/api/ngResource/service/$resourcehttps://docs.angularjs.org/api/ngResource/service/$resourceOriginhttps://damienfremont.com/2015/10/17/javaee-angularjs-bootstrap-date-picker/",
        "url": "/2015/10/17/javaee-angularjs-bootstrap-date-picker"
      },
    
      "2015-10-16-javaee-angularjs-bootstrap-form-basic-read-post": {
        "title": "Javaee Angularjs Bootstrap Form Basic Read Post",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "A tutorial about form with AngularJS and a rest server. Featuring most current usecases like read only, post and placeholder.How to?By using:  Build Maven to manage java dependencies WebJars to manage web dependencies  Front Bootstrap for UI AngularJS for MVC ng-route ng-resource ng-animateAngularUIBootstrap for Bootstrap Javascript support in AngularJS  Back JavaEE to provide REST web services Jersey for REST Server BeanValidation for API validation Tomcat to contain the webappDemoRun this project on your webapp server (Tomcat for example), and test on:http://localhost:8080/20151016-javaee-angularjs-bootstrap-form-basichttp://localhost:8080/20151016-javaee-angularjs-bootstrap-form-basicFirst a read-only view.It’s animated with angular’s animate lib and animation.css style (fade-in effect here).An then an edit view.You can post the form then receive an alert (success here).Or post wrong datas and get another type of alert (error here for year format).It’s responsive too!SourcesThe Config Partpom.xml: maven config&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151016-javaee-angularjs-bootstrap-form-basic&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.14.0&lt;/angular-ui-bootstrap.version&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;7.0&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;    &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;     &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;web.xml&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\"         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"         xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\"         version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyApplication&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;The Java PartMyApplication.javapackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyApplication extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(PersonResource.class);    return s;  }}PersonResource.javapackage com.damienfremont.blog; import java.io.Serializable; import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType; @Path(\"/person\")public class PersonResource {   @GET  @Produces(MediaType.APPLICATION_JSON)  public Person get() {    return data;  }     @POST  @Consumes(MediaType.APPLICATION_JSON)  public void post(Person data) {    this.data = data;  }     // MODEL     static class Person implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;    public String firstName;    public String lastName;    public Integer birthYear;    public Boolean active;  }     // MOCK   static Person data;  static {    data = new Person();    data.firstName = \"Albert\";    data.lastName = \"Einstein\";    data.birthYear = 1909;    data.active = Boolean.FALSE;  } }The Web PartPersonSrv.js'use strict'; myApp.factory('Person', function($resource) {    return $resource('api/person');});PersonCtrl.js'use strict'; myApp.controller('PersonCtrl', function($scope, Person, $location) {  Person.get(function(obj) {     $scope.person = obj;  });         // READ FORM  $scope.edit = function() {    $location.path( \"/person/edit\" );     }     // EDIT FORM  $scope.update = function() {    Person.save($scope.person ,function(obj) {      // this callback will be called asynchronously      // when the response is available      $scope.person = obj;      $location.path( \"/person\" );      $scope.$parent.alerts.push({type: 'success', msg: 'Updated!'});    }, function() {      // called asynchronously if an error occurs      // or server returns response with an error status.      $scope.$parent.alerts.push({type: 'danger', msg: 'Update Error!'});    });  }  $scope.cancel = function() {      $location.path( \"/person\" );     }});person.html&lt;div class=\"form-horizontal\"&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;First Name&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;p class=\"form-control-static\"&gt;&lt;/p&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;Last Name&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;p class=\"form-control-static\"&gt;&lt;/p&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;Birth Year&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;p class=\"form-control-static\"&gt;&lt;/p&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;Active&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;p class=\"form-control-static\"&gt;&lt;/p&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;div class=\"col-sm-offset-2 col-sm-10\"&gt;      &lt;button type=\"submit\" class=\"btn btn-primary\" ng-click=\"edit()\"&gt;        &lt;span class=\"glyphicon glyphicon-edit\"&gt;&lt;/span&gt; Edit      &lt;/button&gt;    &lt;/div&gt;  &lt;/div&gt;&lt;/div&gt;personEdit.html&lt;div class=\"form-horizontal\"&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;First Name&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;input class=\"form-control\" placeholder=\"FirstName\" ng-model=\"person.firstName\"&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;Last Name&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;input class=\"form-control\" placeholder=\"Last Name\" ng-model=\"person.lastName\"&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;Birth Year&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;input class=\"form-control\" placeholder=\"Birth Year\" ng-model=\"person.birthYear\"&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;label class=\"col-sm-2 control-label\"&gt;Active&lt;/label&gt;    &lt;div class=\"col-sm-10\"&gt;      &lt;div class=\"checkbox\"&gt;        &lt;label&gt;          &lt;input type=\"checkbox\" ng-model=\"person.active\"&gt;        &lt;/label&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;div class=\"form-group\"&gt;    &lt;div class=\"col-sm-offset-2 col-sm-10\"&gt;      &lt;button type=\"submit\" class=\"btn btn-primary\" ng-click=\"update()\"&gt;        &lt;span class=\"glyphicon glyphicon-ok\"&gt;&lt;/span&gt; Update      &lt;/button&gt;      &lt;button type=\"submit\" class=\"btn btn-default\" ng-click=\"cancel()\"&gt;        &lt;span class=\"glyphicon glyphicon-remove\"&gt;&lt;/span&gt; Cancel      &lt;/button&gt;    &lt;/div&gt;  &lt;/div&gt;&lt;/div&gt;app.js'use strict'; var myApp = angular.module(  'myApp',  [ 'ngAnimate',    'ui.bootstrap',    'ngRoute',    'ngResource']); myApp.config(function($routeProvider) {  $routeProvider  // ROUTE FOR THE READ PAGE  .when('/person', {    templateUrl : 'views/person.html',    controller  : 'PersonCtrl'  })  // ROUTE FOR THE EDIT PAGE  .when('/person/edit', {    templateUrl : 'views/personEdit.html',    controller  : 'PersonCtrl'  })  // DEFAULT  .otherwise({    redirectTo: '/person'  });}); myApp.controller('AlertCtrl', function($scope) {  $scope.alerts = [ ];  $scope.closeAlert = function(index) {    $scope.alerts.splice(index, 1);  };});index.jsp&lt;html ng-app=\"myApp\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;link rel=\"stylesheet\" href=\"styles/animation.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"js/app.js\"&gt;&lt;/script&gt;&lt;script src=\"js/controllers/PersonCtrl.js\"&gt;&lt;/script&gt;&lt;script src=\"js/services/PersonSrv.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;  &lt;div class=\"container\" ng-controller=\"AlertCtrl\"&gt;    &lt;h1&gt;Person&lt;/h1&gt;    &lt;div ng-view class=\"view-animate\"&gt;&lt;/div&gt;    &lt;uib-alert ng-repeat=\"alert in alerts\" type=\"\" close=\"closeAlert($index)\"&gt;&lt;/uib-alert&gt;  &lt;/div&gt;&lt;/body&gt;&lt;/html&gt;animation.css/* 1: ENTER */.view-animate.ng-enter {  transition: 1s linear all;  opacity: 0;} /* 2: ACTIVE */.view-animate.ng-enter.ng-enter-active {  opacity: 1;} /* 3: LEAVE */.view-animate.ng-leave {  opacity: 1;}Project StructureProjecthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151016-javaee-angularjs-bootstrap-form-basichttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151016-javaee-angularjs-bootstrap-form-basicReferenceshttp://getbootstrap.com/css/http://getbootstrap.com/css/https://docs.angularjs.org/guide/formshttps://docs.angularjs.org/guide/formshttps://docs.angularjs.org/api/ngResource/service/$resourcehttps://docs.angularjs.org/api/ngResource/service/$resourcehttps://angular-ui.github.io/bootstrap/https://angular-ui.github.io/bootstrap/https://scotch.io/tutorials/single-page-apps-with-angularjs-routing-and-templatinghttps://scotch.io/tutorials/single-page-apps-with-angularjs-routing-and-templatingOriginhttps://damienfremont.com/2015/10/16/javaee-angularjs-bootstrap-form-basic-read-post/",
        "url": "/2015/10/16/javaee-angularjs-bootstrap-form-basic-read-post"
      },
    
      "2015-10-15-javaee-angularjs-bootstrap-routes-templates-redirection-and-params": {
        "title": "Javaee Angularjs Bootstrap Routes Templates Redirection And Params",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "A simple example about navigation inside a web application, using native AngularJS components.Why ?Using Templates provides a more reusable View and less duplicate code.Using Route provide a better decoupling between View and Controller.Using Redirection inside Controller allows View to not contains compelx logic, but only datas and states.Using Animation to Enhance User Experience with more transitions.How to ?By using AngularJs’ rout, location and animation components.TemplateThe template contains ng-view.index.jsp&lt;html ng-app=\"myApp\"&gt;&lt;head&gt;&lt;!-- LIBS CSS --&gt;&lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;link rel=\"stylesheet\" href=\"styles/main.css\"&gt;&lt;!-- LIBS JS --&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-route.js\"&gt;&lt;/script&gt;&lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;&lt;!-- YOUR JS --&gt;&lt;script src=\"js/app.js\"&gt;&lt;/script&gt;&lt;script src=\"js/controllers/homeCtrl.js\"&gt;&lt;/script&gt;&lt;script src=\"js/controllers/testRouteCtrl.js\"&gt;&lt;/script&gt;&lt;script src=\"js/controllers/testParamsCtrl.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;&lt;div class=\"container\"&gt;  &lt;!-- MAIN CONTENT AND INJECTED VIEWS --&gt;  &lt;div id=\"main\"&gt;    &lt;!-- angular templating --&gt;    &lt;!-- this is where content will be injected --&gt;    &lt;div ng-view class=\"view-animate\"&gt;&lt;/div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;home.html&lt;h1&gt;Home&lt;/h1&gt;&lt;div&gt;  &lt;button class=\"btn btn-default\" ng-click=\"goToTestRoute()\"&gt;    Test Route &lt;span class=\"glyphicon glyphicon-chevron-right\"&gt;&lt;/span&gt;  &lt;/button&gt;&lt;/div&gt;&lt;div class=\"btn-group-vertical\" role=\"group\"&gt;  &lt;button class=\"btn btn-default\" ng-click=\"goToTestParams(1)\"&gt;    Test Params 1 &lt;span class=\"glyphicon glyphicon-chevron-right\"&gt;&lt;/span&gt;  &lt;/button&gt;  &lt;button class=\"btn btn-default\" ng-click=\"goToTestParams(2)\"&gt;    Test Params 2 &lt;span class=\"glyphicon glyphicon-chevron-right\"&gt;&lt;/span&gt;  &lt;/button&gt;  &lt;button class=\"btn btn-default\" ng-click=\"goToTestParams(3)\"&gt;    Test Params 3 &lt;span class=\"glyphicon glyphicon-chevron-right\"&gt;&lt;/span&gt;  &lt;/button&gt;&lt;/div&gt;RouterApp file contains the main router for app’s paths, providding a View/Controller assocation for each route.app.jsvar myApp = angular.module(  'myApp',  [ 'ngAnimate', 'ngRoute']); myApp.config(function($routeProvider) {  $routeProvider  // route for the home page  .when('/', {    templateUrl : 'views/home.html',    controller  : 'homeCtrl'  })  // route for the testRoute page  .when('/testroute', {    templateUrl : 'views/testRoute.html',    controller  : 'testRouteCtrl'  })  // route for the testParams page   .when('/testparams/:id', {    templateUrl : 'views/testParams.html',    controller  : 'testParamsCtrl'  })  // default redirection  .otherwise({    redirectTo: '/'  });});Test RouteController contains redirection, triggered by a View click event.homeCtrl.jsmyApp.controller('homeCtrl', function($scope, $location) {       $scope.goToTestRoute = function() {    $location.path( \"/testroute\" );     }     $scope.goToPageB = function() {    $location.path( \"/pageb\" );     }     $scope.goToTestParams= function(id) {    $location.path( \"/testparams/\"+id );     }});testRouteCtrl.jsmyApp.controller('testRouteCtrl', function($scope, $location) {       $scope.goBack = function() {    $location.path( \"/\" );     }});testRoute.html&lt;h1&gt;Test Route&lt;/h1&gt;&lt;button class=\"btn btn-default\" ng-click=\"goBack()\"&gt;  &lt;span class=\"glyphicon glyphicon-chevron-left\"&gt;&lt;/span&gt; Home&lt;/button&gt;Test paramsA route can be parameterized, like in API’s path.testParamsCtrl.jsmyApp.controller('testParamsCtrl', function($scope, $route, $routeParams, $location) {       $scope.goBack = function() {    $location.path( \"/\" );     }     $scope.$route = $route;  $scope.$location = $location;  $scope.$routeParams = $routeParams;});testParams.html&lt;h1&gt;Test Params&lt;/h1&gt;&lt;p&gt;This is page  !&lt;/p&gt;&lt;pre&gt;  $location.path() =   $route.current.templateUrl =   $route.current.params =   $route.current.scope.name =   $routeParams = &lt;/pre&gt;&lt;button class=\"btn btn-default\" ng-click=\"goBack()\"&gt;  &lt;span class=\"glyphicon glyphicon-chevron-left\"&gt;&lt;/span&gt; Home&lt;/button&gt;AnimationCSS is linked to view-animate AngularJs’ class.main.css.view-animate-container {  position:relative;  height:100px!important;  background:white;  border:1px solid black;  height:40px;  overflow:hidden;} .view-animate {  padding:10px;} .view-animate.ng-enter, .view-animate.ng-leave {  transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;   display:block;  width:100%;  border-left:1px solid black;   position:absolute;  top:0;  left:0;  right:0;  bottom:0;  padding:10px;} .view-animate.ng-enter {  left:100%;}.view-animate.ng-enter.ng-enter-active {  left:0;}.view-animate.ng-leave.ng-leave-active {  left:-100%;}DemoDeploy on your local Tomcat and test at:http://localhost:8080/20151015-javaee-angularjs-bootstrap-route-templatehttp://localhost:8080/20151015-javaee-angularjs-bootstrap-route-templateHere is home View (home.html + homeCtr.js) rendered inside the main Template (index.jsp).Here is animation when Viewchanges (from home Viewto testroute View).Here is route of Test Route View. The Route is ‘/testroute’.http://localhost:8080/20151015-javaee-angularjs-bootstrap-route-template/#/testroutehttp://localhost:8080/20151015-javaee-angularjs-bootstrap-route-template/#/testrouteHere is routeParams for Test Params View.The Route is ‘/testparams/:id’.http://localhost:8080/20151015-javaee-angularjs-bootstrap-route-template/#/testparams/1http://localhost:8080/20151015-javaee-angularjs-bootstrap-route-template/#/testparams/1http://localhost:8080/20151015-javaee-angularjs-bootstrap-route-template/#/testparams/2http://localhost:8080/20151015-javaee-angularjs-bootstrap-route-template/#/testparams/2ConclusionNever put a raw url in your html for the sake of maintenability. It’s controllers’ job!Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151015-javaee-angularjs-bootstrap-route-templatehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151015-javaee-angularjs-bootstrap-route-templateReferenceshttps://docs.angularjs.org/api/ngRoute/service/$routehttps://docs.angularjs.org/api/ngRoute/service/$routehttps://docs.angularjs.org/api/ngRoute/directive/ngView#animationshttps://docs.angularjs.org/api/ngRoute/directive/ngView#animationshttps://docs.angularjs.org/tutorial/step_07https://docs.angularjs.org/tutorial/step_07https://docs.angularjs.org/api/ng/directive/ngDisabledhttps://docs.angularjs.org/api/ng/directive/ngDisabledOriginhttps://damienfremont.com/2015/10/15/javaee-angularjs-bootstrap-routes-templates-redirection-and-params/",
        "url": "/2015/10/15/javaee-angularjs-bootstrap-routes-templates-redirection-and-params"
      },
    
      "2015-10-13-javaee-angularjs-bootstrap-integration": {
        "title": "Javaee Angularjs Bootstrap Integration",
        "author": "",
        "category": "",
        "tags": "angularjs, java, javascript, bootstrap",
        "content": "This tutorial is a basic integration of AngularJS, Bootstrap3, JavaEE JAX-RS, Maven and WebJars. Usefull for replacing your old JSF or GWT application from intranet.Why?Because AngularJs is not a web framework anymore and tends to replace GWT in intranet web applications. And because most of these team have a Java legacy, it’s sometimes more productive to build on top of a well known Java Server instead of jumping in a new system like NodeJs in addition to migrating to a new MVC framework (like from JSF to AngularJs).How?By using:  Bootstrap for UI  AngularJS for MVC  AngularUIBootstrap for Bootstrap Javascript support in AngularJS  WebJars to manage web dependencies  Maven to manage java dependencies  JavaEE to provide REST web services  Tomcat to contain the webapppom.xml: maven config&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151013-javaee-angularjs-bootstrap&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;properties&gt;    &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;    &lt;java.version&gt;7&lt;/java.version&gt;    &lt;jersey.version&gt;2.22.1&lt;/jersey.version&gt;    &lt;angularjs.version&gt;1.4.7&lt;/angularjs.version&gt;    &lt;angular-ui-bootstrap.version&gt;0.13.4&lt;/angular-ui-bootstrap.version&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;  &lt;/properties&gt;   &lt;dependencies&gt;     &lt;!-- JAVA --&gt;     &lt;dependency&gt;      &lt;groupId&gt;javax&lt;/groupId&gt;      &lt;artifactId&gt;javaee-api&lt;/artifactId&gt;      &lt;version&gt;7.0&lt;/version&gt;      &lt;scope&gt;provided&lt;/scope&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.containers&lt;/groupId&gt;      &lt;artifactId&gt;jersey-container-servlet&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.glassfish.jersey.media&lt;/groupId&gt;      &lt;artifactId&gt;jersey-media-json-jackson&lt;/artifactId&gt;      &lt;version&gt;${jersey.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB --&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angularjs&lt;/artifactId&gt;      &lt;version&gt;${angularjs.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;angular-ui-bootstrap&lt;/artifactId&gt;      &lt;version&gt;${angular-ui-bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;     &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;    &lt;build&gt;    &lt;resources&gt;      &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;            &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;       &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;        &lt;version&gt;3.1&lt;/version&gt;        &lt;configuration&gt;          &lt;source&gt;1.${java.version}&lt;/source&gt;          &lt;target&gt;1.${java.version}&lt;/target&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;     &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;StatusService.java: javaEE REST servicepackage com.damienfremont.blog; import static javax.ws.rs.core.Response.status;import static javax.ws.rs.core.Response.Status.OK; import java.io.Serializable;import java.text.SimpleDateFormat;import java.util.Date; import javax.ws.rs.GET;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response; @Path(\"/status\")public class StatusService {   @GET  public Response ping() {    return status(OK).build();  }   @GET  @Path(\"details\")  @Produces(MediaType.APPLICATION_JSON)  public StatusModel details() {    String pattern = \"yyyy-MM-dd hh:mm:ss\";    SimpleDateFormat sdf = new SimpleDateFormat(pattern);    String date = sdf.format(new Date());    return new StatusModel(\"OK\", date);  }   class StatusModel implements Serializable {    private static final long serialVersionUID = 9167120287441116359L;         public String value;     public StatusModel(String value, String date) {      super();      this.value = value;      this.date = date;    }     public String date;  } }MyApplication.java: javaEE Configurationpackage com.damienfremont.blog; import java.util.HashSet;import java.util.Set;import javax.ws.rs.core.Application; public class MyApplication extends Application {   @Override  public Set&lt;Class&lt;?&gt;&gt; getClasses() {    Set&lt;Class&lt;?&gt;&gt; s = new HashSet&lt;Class&lt;?&gt;&gt;();    s.add(StatusService.class);    return s;  }}web.xml: webapp config&lt;web-app xmlns=\"http://xmlns.jcp.org/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd\" version=\"3.1\"&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.glassfish.jersey.servlet.ServletContainer&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;javax.ws.rs.Application&lt;/param-name&gt;      &lt;param-value&gt;com.damienfremont.blog.MyApplication&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;REST&lt;/servlet-name&gt;    &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt;   &lt;servlet&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;      &lt;param-name&gt;disableCache&lt;/param-name&gt;      &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WEBJARS&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;index.jsp: web component integration&lt;!DOCTYPE html &gt;&lt;head&gt;  &lt;link rel=\"icon\" href=\"favicon.ico\"&gt;         &lt;!-- LIBS CSS --&gt;  &lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;  &lt;link rel=\"stylesheet\" href=\"styles/main.css\"&gt;  &lt;!-- LIBS JS --&gt;  &lt;script src=\"webjars/angularjs/${angularjs.version}/angular.js\"&gt;&lt;/script&gt;  &lt;script src=\"webjars/angularjs/${angularjs.version}/angular-resource.js\"&gt;&lt;/script&gt;  &lt;script src=\"webjars/angularjs/${angularjs.version}/angular-animate.js\"&gt;&lt;/script&gt;  &lt;script src=\"webjars/angular-ui-bootstrap/${angular-ui-bootstrap.version}/ui-bootstrap-tpls.js\"&gt;&lt;/script&gt;  &lt;!-- YOUR JS --&gt;  &lt;script src=\"js/app.js\"&gt;&lt;/script&gt;  &lt;script src=\"js/controllers/ModalCtrl.js\"&gt;&lt;/script&gt;  &lt;script src=\"js/controllers/StatusCtrl.js\"&gt;&lt;/script&gt;  &lt;script src=\"js/services/StatusResource.js\"&gt;&lt;/script&gt;&lt;/head&gt;&lt;body&gt;  &lt;div class=\"container\" ng-app=\"ui.bootstrap.demo\"&gt;       &lt;!-- BOOTSTRAP --&gt;       &lt;div&gt;        &lt;h1&gt;Bootstrap Test&lt;/h1&gt;        &lt;p&gt;CSS button here...&lt;/p&gt;        &lt;div class=\"bs-example\" data-example-id=\"btn-variants\"&gt;          &lt;button type=\"button\" class=\"btn btn-default\"&gt;Default&lt;/button&gt;          &lt;button type=\"button\" class=\"btn btn-primary\"&gt;Primary&lt;/button&gt;          &lt;button type=\"button\" class=\"btn btn-success\"&gt;Success&lt;/button&gt;          &lt;button type=\"button\" class=\"btn btn-info\"&gt;Info&lt;/button&gt;          &lt;button type=\"button\" class=\"btn btn-warning\"&gt;Warning&lt;/button&gt;          &lt;button type=\"button\" class=\"btn btn-danger\"&gt;Danger&lt;/button&gt;          &lt;button type=\"button\" class=\"btn btn-link\"&gt;Link&lt;/button&gt;        &lt;/div&gt;    &lt;/div&gt;         &lt;!-- ANGULARJS --&gt;         &lt;div&gt;        &lt;h1&gt;AngularJs Test&lt;/h1&gt;        &lt;p&gt;Basic MVC here...&lt;/p&gt;        &lt;p&gt;Name : &lt;input type=\"text\" ng-model=\"name\" placeholder=\"type your name here...\"&gt;&lt;/p&gt;        &lt;h3&gt;Hello &lt;/h3&gt;    &lt;/div&gt;         &lt;!-- ANGULARJS + UIBOOTSTRAP --&gt;          &lt;div ng-controller=\"ModalDemoCtrl\"&gt;      &lt;h1&gt;AngularUI + Bootstrap JS Test&lt;/h1&gt;      &lt;p&gt;Bootstrap JS integration here...&lt;/p&gt;      &lt;script type=\"text/ng-template\" id=\"myModalContent.html\"&gt;        &lt;div class=\"modal-header\"&gt;            &lt;h3 class=\"modal-title\"&gt;I'm a modal!&lt;/h3&gt;        &lt;/div&gt;        &lt;div class=\"modal-body\"&gt;            &lt;ul&gt;                &lt;li ng-repeat=\"item in items\"&gt;                    &lt;a href=\"#\" ng-click=\"$event.preventDefault(); selected.item = item\"&gt;&lt;/a&gt;                &lt;/li&gt;            &lt;/ul&gt;            Selected: &lt;b&gt;&lt;/b&gt;        &lt;/div&gt;        &lt;div class=\"modal-footer\"&gt;            &lt;button class=\"btn btn-primary\" type=\"button\" ng-click=\"ok()\"&gt;OK&lt;/button&gt;            &lt;button class=\"btn btn-warning\" type=\"button\" ng-click=\"cancel()\"&gt;Cancel&lt;/button&gt;        &lt;/div&gt;      &lt;/script&gt;      &lt;button type=\"button\" class=\"btn btn-default\" ng-click=\"open()\"&gt;Open me!&lt;/button&gt;      &lt;button type=\"button\" class=\"btn btn-default\" ng-click=\"open('lg')\"&gt;Large modal&lt;/button&gt;      &lt;button type=\"button\" class=\"btn btn-default\" ng-click=\"open('sm')\"&gt;Small modal&lt;/button&gt;      &lt;button type=\"button\" class=\"btn btn-default\" ng-click=\"toggleAnimation()\"&gt;Toggle Animation ()&lt;/button&gt;      &lt;div ng-show=\"selected\"&gt;Selection from a modal: &lt;/div&gt;    &lt;/div&gt;         &lt;!-- ANGULARJS + JAVAEE REST SERVER --&gt;     &lt;div ng-controller=\"StatusCtrl\"&gt;        &lt;h1&gt;JavaEE + AngularJs Rest client Test&lt;/h1&gt;        &lt;p&gt;REST call here...&lt;/p&gt;        &lt;p&gt;Response from /api/status is          &lt;span class=\"label label-default\"&gt;&lt;/span&gt;&lt;/p&gt;        &lt;p&gt;Response from /api/status/details is          &lt;span class=\"label label-default\"&gt;&lt;/span&gt; at  (JSON object mapped to )&lt;/p&gt;    &lt;/div&gt;   &lt;/body&gt;&lt;/html&gt;app.js: main'use strict'; var myApp = angular.module(        'ui.bootstrap.demo',        [          'ngAnimate',          'ui.bootstrap',          'ngResource']);ModalCtrl.js: test UI Bootstrap'use strict'; myApp.controller('ModalDemoCtrl', function ($scope, $modal, $log) {   $scope.items = ['item1', 'item2', 'item3'];   $scope.animationsEnabled = true;   $scope.open = function (size) {     var modalInstance = $modal.open({      animation: $scope.animationsEnabled,      templateUrl: 'myModalContent.html',      controller: 'ModalInstanceCtrl',      size: size,      resolve: {        items: function () {          return $scope.items;        }      }    });     modalInstance.result.then(function (selectedItem) {      $scope.selected = selectedItem;    }, function () {      $log.info('Modal dismissed at: ' + new Date());    });  };   $scope.toggleAnimation = function () {    $scope.animationsEnabled = !$scope.animationsEnabled;  }; }); // Please note that $modalInstance represents a modal window (instance) dependency.// It is not the same as the $modal service used above. angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {   $scope.items = items;  $scope.selected = {    item: $scope.items[0]  };   $scope.ok = function () {    $modalInstance.close($scope.selected.item);  };   $scope.cancel = function () {    $modalInstance.dismiss('cancel');  };});StatusCtrl.js: test Angular REST Client'use strict'; myApp.controller('StatusCtrl', ['$scope', 'Status', 'StatusDetails', function($scope, Status, StatusDetails) {    Status.get(function(s) {         $scope.status = s;    });    StatusDetails.get(function(d) {         $scope.details = d;    });}]);StatusResource.js: test Angular REST Client'use strict'; myApp.factory('Status', function($resource) {    return $resource('api/status', {}, {});}); myApp.factory('StatusDetails', function($resource) {    return $resource('api/status/details', {}, {});});main.css: styleh1 {    padding-bottom: 9px;    margin: 40px 0 20px;    border-bottom: 1px solid #eee;}And you’ll have a simple project like this:#DemoRun this project on your webapp server (Tomcat for example), and test on:http://localhost:8080/20151013-javaee-angularjs-bootstrap/http://localhost:8080/20151013-javaee-angularjs-bootstrap/The main page test all frameworks.Here is AngularJS MVCHere is UI Bootstrap for AngularJSHere is AngularJS REST Client and JavaEE REST Serverhttp://localhost:8080/20151013-javaee-angularjs-bootstrap/api/statushttp://localhost:8080/20151013-javaee-angularjs-bootstrap/api/statushttp://localhost:8080/20151013-javaee-angularjs-bootstrap/api/status/detailshttp://localhost:8080/20151013-javaee-angularjs-bootstrap/api/status/detailsConclusionIt’s a step by step approach. Maybe later you will have some NodeJS backend and a team full of webdeveloper.Pros: simple approach for Java developer (productivity)Cons: not so shiny from a web developer point of view (legacy, performance)Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151013-javaee-angularjs-bootstraphttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151013-javaee-angularjs-bootstrapReferenceshttp://www.webjars.org/http://www.webjars.org/https://github.com/webjars/webjars-servlet-2.xhttps://github.com/webjars/webjars-servlet-2.xhttp://getbootstrap.com/http://getbootstrap.com/http://www.w3schools.com/angular/http://www.w3schools.com/angular/https://angular-ui.github.io/https://angular-ui.github.io/https://docs.angularjs.org/tutorial/step_11https://docs.angularjs.org/tutorial/step_11https://jersey.java.net/nonav/documentation/2.0/deployment.htmlhttps://jersey.java.net/nonav/documentation/2.0/deployment.htmlhttps://scotch.io/tutorials/how-to-correctly-use-bootstrapjs-and-angularjs-togetherhttps://scotch.io/tutorials/how-to-correctly-use-bootstrapjs-and-angularjs-togetherOriginhttps://damienfremont.com/2015/10/13/javaee-angularjs-bootstrap-integration/",
        "url": "/2015/10/13/javaee-angularjs-bootstrap-integration"
      },
    
      "2015-10-08-webjars-use-dynamic-urls-for-your-dependencies-vs-versionning-hell": {
        "title": "Webjars Use Dynamic Urls For Your Dependencies Vs Versionning Hell",
        "author": "",
        "category": "",
        "tags": "java, javascript",
        "content": "WebJars is a useful tool. It’s a client-side web libraries (e.g. jQuery &amp; Bootstrap) packaged into JAR (Java Archive) files. But a static URL for your dependency is painfull to maintain. This tutorial provides a simpler way of managing version and URL in only one location.How?By using Maven filtering to provide a dynamic jar version value.  use a jsp file instead of html to avoid filtering conflicts with html templating engine from webapp folder (like in angularjs) *.jsp  put a filtering properties into your index.jsp webjars url version src=”webjars/jquery/1.2/…” to src=”webjars/jquery/${jquery.version}/…”  extract your webjars versions into a maven properties ‘1.2’ to ‘1.2&lt;/version&gt;’  configure war plugin to also include fitlering for final packaging (avoid conflict with eclipse wtp plugin)index.jsp (custom example, use webjars paths)&lt;!DOCTYPE html&gt;&lt;head&gt;  &lt;!-- PUT YOUR STYLE LIBS HERE --&gt;  &lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/${bootstrap.version}/css/bootstrap.css\"&gt;&lt;/head&gt;&lt;body&gt;   &lt;!-- DO YOUR STUFF HERE... --&gt;  Hello!    &lt;!-- PUT YOUR JS LIBS HERE --&gt;  &lt;script src=\"webjars/jquery/${jquery.version}/jquery.js\"&gt;&lt;/script&gt;  &lt;script src=\"webjars/bootstrap/${bootstrap.version}/js/bootstrap.js\"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;webapp web.xml (declare webjars servlet)&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:web=\"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\" id=\"WebApp_ID\" version=\"2.5\"&gt;   &lt;!--Webjars Servlet --&gt;  &lt;servlet&gt;    &lt;servlet-name&gt;WebjarsServlet&lt;/servlet-name&gt;    &lt;servlet-class&gt;org.webjars.servlet.WebjarsServlet&lt;/servlet-class&gt;    &lt;init-param&gt;        &lt;param-name&gt;disableCache&lt;/param-name&gt;        &lt;param-value&gt;true&lt;/param-value&gt;    &lt;/init-param&gt;    &lt;load-on-startup&gt;2&lt;/load-on-startup&gt;  &lt;/servlet&gt;  &lt;servlet-mapping&gt;    &lt;servlet-name&gt;WebjarsServlet&lt;/servlet-name&gt;    &lt;url-pattern&gt;/webjars/*&lt;/url-pattern&gt;  &lt;/servlet-mapping&gt; &lt;/web-app&gt;maven pom.xml (manage web dependencies)&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;  &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151008-javaee-webjars-versions&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;  &lt;properties&gt;     &lt;!-- WEB DEPENDENCIES VERSIONS (USED FOR FILTERING AND URL RESOLUTION) --&gt;    &lt;bootstrap.version&gt;3.3.5&lt;/bootstrap.version&gt;    &lt;jquery.version&gt;2.1.4&lt;/jquery.version&gt;   &lt;/properties&gt;  &lt;dependencies&gt;     &lt;!-- WEB DEPENDENCIES --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;${bootstrap.version}&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;jquery&lt;/artifactId&gt;      &lt;version&gt;${jquery.version}&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;   &lt;!-- RESOURCES FILTERING ONLY ON JSP FILES TO AVOID HTML TEMPLATES MODIFICATION --&gt;   &lt;build&gt;    &lt;resources&gt;       &lt;!-- FILTERING FOR WTP PLUGIN --&gt;       &lt;resource&gt;        &lt;directory&gt;src/main/webapp&lt;/directory&gt;        &lt;filtering&gt;true&lt;/filtering&gt;        &lt;targetPath&gt;${project.basedir}/target/m2e-wtp/web-resources&lt;/targetPath&gt;        &lt;includes&gt;          &lt;include&gt;*.jsp&lt;/include&gt;        &lt;/includes&gt;      &lt;/resource&gt;    &lt;/resources&gt;    &lt;plugins&gt;      &lt;plugin&gt;        &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;        &lt;artifactId&gt;maven-war-plugin&lt;/artifactId&gt;        &lt;version&gt;2.6&lt;/version&gt;        &lt;configuration&gt;          &lt;webResources&gt;             &lt;!-- FILTERING FOR PACKAGING --&gt;             &lt;resource&gt;              &lt;directory&gt;src/main/webapp&lt;/directory&gt;              &lt;filtering&gt;true&lt;/filtering&gt;              &lt;includes&gt;                &lt;include&gt;*.jsp&lt;/include&gt;              &lt;/includes&gt;            &lt;/resource&gt;          &lt;/webResources&gt;        &lt;/configuration&gt;      &lt;/plugin&gt;    &lt;/plugins&gt;  &lt;/build&gt;&lt;/project&gt;Eclipse Java Maven Project StructureDemoRun this project on your webapp server (Tomcat for example), and test on:http://localhost:8080/20151008-javaee-webjars-versions/http://localhost:8080/20151008-javaee-webjars-versions/ConclusionA more productive way to maintain your project (no more static lib url).Pros:  productivity  maven properties usage for lib versionsCons:  unstable filtering (conflict on tags ${} pattern between Maven and other third party tools like AngularJs)Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151008-javaee-webjars-versionshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151008-javaee-webjars-versionsReferenceshttp://www.webjars.org/http://www.webjars.org/https://github.com/webjars/webjars-servlet-2.xhttps://github.com/webjars/webjars-servlet-2.xhttp://mvnrepository.com/artifact/org.webjarshttp://mvnrepository.com/artifact/org.webjarsOriginhttps://damienfremont.com/2015/10/08/webjars-use-dynamic-urls-for-your-dependencies-vs-versionning-hell/",
        "url": "/2015/10/08/webjars-use-dynamic-urls-for-your-dependencies-vs-versionning-hell"
      },
    
      "2015-10-07-webjars-manage-your-web-dependencies-with-maven": {
        "title": "Webjars Manage Your Web Dependencies With Maven",
        "author": "",
        "category": "",
        "tags": "java, javascript",
        "content": "No more /src/main/webapp/vendor/jquery.min.js, or /styles/bootstrap.css! Just a Maven dependency like the other libraries. WebJars are client-side web libraries (e.g. jQuery &amp; Bootstrap) packaged into JAR (Java Archive) files.Why?Maven is great on managing jars, but not so good for static web dependencies like CSS or JS files packaged in a zip. With Webjars you can have AngularJS or Bootstrap in your pom.xml, like you did with Bower on a web project.How?maven pom.xml (manage web dependencies)&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;  &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;   &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;  &lt;artifactId&gt;20151007-javaee-webjars&lt;/artifactId&gt;  &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;  &lt;packaging&gt;war&lt;/packaging&gt;   &lt;dependencies&gt;         &lt;!-- WEB DEPENDENCIES --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;bootstrap&lt;/artifactId&gt;      &lt;version&gt;3.3.5&lt;/version&gt;    &lt;/dependency&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;jquery&lt;/artifactId&gt;      &lt;version&gt;2.1.4&lt;/version&gt;    &lt;/dependency&gt;     &lt;!-- WEB DEPENDENCIES SERVLET --&gt;    &lt;dependency&gt;      &lt;groupId&gt;org.webjars&lt;/groupId&gt;      &lt;artifactId&gt;webjars-servlet-2.x&lt;/artifactId&gt;      &lt;version&gt;1.1&lt;/version&gt;    &lt;/dependency&gt;   &lt;/dependencies&gt;&lt;/project&gt;webapp web.xml (declare webjars servlet) index.html (standard example, use webjars paths)&lt;!DOCTYPE html&gt;&lt;head&gt;  &lt;!-- ADD ALL YOUR CSS DEPENDENCIES HERE... --&gt;  &lt;link rel=\"stylesheet\" href=\"webjars/bootstrap/3.3.5/css/bootstrap.css\"&gt;&lt;/head&gt;&lt;body&gt;   &lt;!-- DO YOUR THING HERE... --&gt;  Hello world!   &lt;!-- ADD ALL YOUR JS DEPENDENCIES HERE... --&gt;  &lt;script src=\"webjars/jquery/2.1.4/jquery.js\"&gt;&lt;/script&gt;  &lt;script src=\"webjars/bootstrap/3.3.5/js/bootstrap.js\"&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;Only pom.xml and web.xml are required to manage web depencies. And you’ll see your web dependencies like the others.DemoRun this project on your webapp server (Tomcat for example), and test on:http://localhost:8080/20151007-javaee-webjars/http://localhost:8080/20151007-javaee-webjars/ConclusionA good tool, and a big maven repository behind it (org.webjars).Pro:  faster: less work adding a web library  safe: no copy/paste error on web libs  clean: no more binaries in your source repositories!Con:  perf: a servlet is serving the static files (be sure to put a cache server in front of your app)You will find a lot more libs at mvnrepository or webjars.org !Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151007-javaee-webjarshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20151007-javaee-webjarsReferenceshttp://www.webjars.org/http://www.webjars.org/https://github.com/webjars/webjars-servlet-2.xhttps://github.com/webjars/webjars-servlet-2.xhttp://mvnrepository.com/artifact/org.webjarshttp://mvnrepository.com/artifact/org.webjarsOriginhttps://damienfremont.com/2015/10/07/webjars-manage-your-web-dependencies-with-maven/",
        "url": "/2015/10/07/webjars-manage-your-web-dependencies-with-maven"
      },
    
      "2015-09-01-git-the-simple-guide": {
        "title": "Git The Simple Guide",
        "author": "",
        "category": "",
        "tags": "git, quicktip",
        "content": "git – the simple guideBecause I always forget git commands… source here: git – the simple guide (it’s better)just a simple guide for getting started with git. no deep shit.Setup  Download git for OSX  Download git for Windows  Download git for LinuxCreate a new repositorycreate a new directory, open it and perform agit initto create a new git repository.Checkout a repositorycreate a working copy of a local repository by running the commandgit clone /path/to/repositorywhen using a remote server, your command will begit clone username@host:/path/to/repositoryWorkflowyour local repository consists of three “trees” maintained by git. the first one is your Working Directory which holds the actual files. the second one is the Index which acts as a staging area and finally the HEAD which points to the last commit you’ve made.Add &amp; commitYou can propose changes (add it to the Index) usinggit addgit add *This is the first step in the basic git workflow. To actually commit these changes usegit commit -m \"Commit message\"Now the file is committed to the HEAD, but not in your remote repository yet.Pushing changesYour changes are now in the HEAD of your local working copy. To send those changes to your remote repository, executegit push origin masterChange master to whatever branch you want to push your changes to.If you have not cloned an existing repository and want to connect your repository to a remote server, you need to add it withgit remote add originNow you are able to push your changes to the selected remote serverBranchingBranches are used to develop features isolated from each other. The master branch is the “default” branch when you create a repository. Use other branches for development and merge them back to the master branch upon completion.create a new branch named “feature_x” and switch to it usinggit checkout -b feature_xswitch back to mastergit checkout masterand delete the branch againgit branch -d feature_xa branch is not available to others unless you push the branch to your remote repositorygit push originUpdate &amp; mergeto update your local repository to the newest commit, executegit pullin your working directory to fetch and merge remote changes.to merge another branch into your active branch (e.g. master), usegit mergein both cases git tries to auto-merge changes. Unfortunately, this is not always possible and results in conflicts. You are responsible to merge those conflicts manually by editing the files shown by git. After changing, you need to mark them as merged withgit addbefore merging changes, you can also preview them by usinggit diffTaggingit’s recommended to create tags for software releases. this is a known concept, which also exists in SVN. You can create a new tag named 1.0.0 by executinggit tag 1.0.0 1b2e1d63ffthe 1b2e1d63ff stands for the first 10 characters of the commit id you want to reference with your tag. You can get the commit id by looking at the…Login its simplest form, you can study repository history using..git logYou can add a lot of parameters to make the log look like what you want. To see only the commits of a certain author:git log --author=bobTo see a very compressed log where each commit is one line:git log --pretty=onelineOr maybe you want to see an ASCII art tree of all the branches, decorated with the names of tags and branches:git log --graph --oneline --decorate --allSee only which files have changed:git log --name-statusThese are just a few of the possible parameters you can use.For more, see git log --helpReplace local changesIn case you did something wrong, which for sure never happens, you can replace local changes using the commandgit checkout --this replaces the changes in your working tree with the last content in HEAD. Changes already added to the index, as well as new files, will be kept.If you instead want to drop all your local changes and commits, fetch the latest history from the server and point your local master branch at it like thisgit fetch origingit reset --hard origin/masterUseful hintsbuilt-in git GUIgitkuse colorful git outputgit config color.ui trueshow log on just one line per commitgit config format.pretty onelineuse interactive addinggit add -iLinks &amp; resourcesgraphical clients  GitX (L) (OSX, open source)  Tower (OSX)  Source Tree (OSX &amp; Windows, free)  GitHub for Mac (OSX, free)  GitBox (OSX, App Store)guides  Git Community Book  Pro Git  Think like a git  GitHub Help  A Visual Git Guideget help  Git User Mailing List  #git on irc.freenode.netReferenceshttp://rogerdudler.github.io/git-guide/http://rogerdudler.github.io/git-guide/Post on Wordpresshttps://damienfremont.com/2015/09/01/git-the-simple-guide/",
        "url": "/2015/09/01/git-the-simple-guide"
      },
    
      "2015-08-07-migrating-from-simple-junit-test-to-cucumber-java": {
        "title": "Migrating From Simple Junit Test To Cucumber Java",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, test",
        "content": "This post explains how to migrate source code from simple JUnit test to Cucumber Java Test. It’s a not so simple task, because in older JUnit test the behaviour is not always implemetend.Step A – Simple JUnit TestIt’s the shortest source code ever. But it lacks stability, behaviour and documentation.A_SimpleJunitTest.javapublic class A_SimpleJunitTest {     @Test    public void test() {        ClassToTest classToTest = new ClassToTest();        String receipt = classToTest.buy(\"microwave\", 100);        assertThat(receipt).isNotNull();        assertThat(classToTest.returns(\"microwave\", receipt)).contains(\"100\");    }}Step B – Better JUnit TestIt’s stable and behaviour-oriented code. But functions reuse is not possible, and Javadoc is not an open collaboration format for other people like Product-Owner.B_BetterJunitTest.java/** * Feature: Refund item */public class B_BetterJunitTest {     ClassToTest classToTest;     @Before    public void beforeScenario() {        classToTest = new ClassToTest();    }     /**     * Scenario: Jeff returns a faulty microwave     * - Given Jeff has bought a microwave for $100     * -- And he has a receipt     * - When he returns the microwave     * - Then Jeff should be refunded $100     */    @Test    public void test_jeff_returns_a_faulty_microwave() {        // Given        int amount = 100;        String receipt = classToTest.buy(\"microwave\", amount);        // When        assertThat(receipt)            .isNotNull();        // Then        String refund = classToTest.returns(\"microwave\", receipt);        assertThat(refund)            .isNotNull()            .contains(\"100\");    } }Step C – Cucumber Java6It’s modular code and functions reuse is possible. But it’s not very productive because of the duplicate annotation/function syntax.C_CucumberJava6Test.java@RunWith(Cucumber.class)@CucumberOptions(strict = true, features = \"features\")public class C_CucumberJava6Test implements En {     ClassToTest classToTest;    String receipt;    String refund;     @Before    public void beforeScenario() {        classToTest = new ClassToTest();    }     @Given(\"^Jeff has bought a microwave for \\\\$(\\\\d+) - C$\")    public void jeff_has_bought_a_microwave_for(Integer amount) {        receipt = classToTest.buy(\"microwave\", amount);    }     @Given(\"^he has a receipt - C$\")    public void he_has_a_receipt() {        assertThat(receipt).isNotNull();    }     @When(\"^he returns the microwave - C$\")    public void he_returns_the_microwave() {        refund = classToTest.returns(\"microwave\", receipt);    }     @Then(\"^Jeff should be refunded \\\\$(\\\\d+) - C$\")    public void jeff_should_be_refunded(Integer amount) {        assertThat(refund).isNotNull().contains(amount.toString());    }}C_CucumberJava6.featureFeature: Refund item - C   Scenario: Jeff returns a faulty microwave - C    Given Jeff has bought a microwave for $100 - C    And he has a receipt - C    When he returns the microwave - C    Then Jeff should be refunded $100 - CStep D – Cucumber Java8D_CucumberJava8Test.java@RunWith(Cucumber.class)@CucumberOptions(strict = true, features = \"features\")public class D_CucumberJava8Test implements En {         ClassToTest classToTest;    String receipt;    String refund;     public D_CucumberJava8Test() {                 Before(()-&gt;{            classToTest = new ClassToTest();        });                 Given(\"^Jeff has bought a microwave for \\\\$(\\\\d+) - D$\", (Integer amount) -&gt; {            receipt = classToTest.buy(\"microwave\", amount);        });         Given(\"^he has a receipt - D$\", () -&gt; {            assertThat(receipt)                .isNotNull();        });         When(\"^he returns the microwave - D$\", () -&gt; {            refund = classToTest.returns(\"microwave\", receipt);        });         Then(\"^Jeff should be refunded \\\\$(\\\\d+) - D$\", (Integer amount) -&gt; {            assertThat(refund)                .isNotNull()                .contains(amount.toString());        });    }  }DemoThis project runs the four test classes, targeting the same implementation.Maven config pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150807-test-cucumber_migrating_from_junit&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;dependencies&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.assertj&lt;/groupId&gt;            &lt;artifactId&gt;assertj-core&lt;/artifactId&gt;            &lt;version&gt;3.1.0&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;            &lt;version&gt;1.2.4&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;            &lt;version&gt;1.2.4&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;    &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;configuration&gt;                    &lt;source&gt;1.8&lt;/source&gt;                    &lt;target&gt;1.8&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;Run ti with JUnit.Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150807-test-cucumber_migrating_from_junithttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150807-test-cucumber_migrating_from_junitReferenceshttps://cucumber.io/docs/referencehttps://cucumber.io/docs/referencehttps://rmannibucau.wordpress.com/2015/01/26/cukespace-or-bdd-arquillian-and-java-8/https://rmannibucau.wordpress.com/2015/01/26/cukespace-or-bdd-arquillian-and-java-8/Originhttps://damienfremont.com/2015/08/07/migrating-from-simple-junit-test-to-cucumber-java/",
        "url": "/2015/08/07/migrating-from-simple-junit-test-to-cucumber-java"
      },
    
      "2015-08-06-migrating-from-java4-commonslang-to-java6-guava-to-java8": {
        "title": "Migrating From Java4 Commonslang To Java6 Guava To Java8",
        "author": "",
        "category": "",
        "tags": "java",
        "content": "This tutorial cover code migration from different historical technical stacks. It goes from Java 1.4 with Commons-Lang (2005, Apache), to Java 1.6 with Guava (2009, Google) then to Java 8 (2015). These technical stacks are knowned to be Java language extension (Jakarta and Guava). Most basic usecases will be covered:  condition  check  filter  map  error handling  load file  load resourceby implementing this Interface:public interface IJavaUseCases {     boolean condition(String arg);    void check(String arg);     List&lt;String&gt; filter(List&lt;String&gt; input);    List&lt;String&gt; map(List&lt;String&gt; input);     void errorHandling(Exception e);     String loadFile(String path) throws Exception;    String loadResource(String name) throws Exception; }Java 1.4 (vanilla)This source code is pure old Java, with a lot of boilerplate and very unsafe (missing generics, for each). For historical purpose only.// UNSTABLE: UNSAFE COLLECTIONS, BOILERPLATESpublic class Java4AVanillaImpl implements IJavaUseCases {     public boolean condition(String arg) {        return arg != null &amp;&amp; arg.trim().length() &gt; 0;    }     public void check(String arg) {        if (!condition(arg)) {            throw new IllegalArgumentException();        }    }     public List filter(List input) {        List output = new ArrayList();        for (int i = 0; i &lt; input.size(); i++) {            String current = (String) input.get(i);            if (condition(current)) {                output.add(current);            }        }        return output;    }     public List map(List input) {        List output = new ArrayList();        for (int i = 0; i &lt; input.size(); i++) {            String current = (String) input.get(i);            String transformed = current.toUpperCase();            output.add(transformed);        }        return output;    }     public void errorHandling(Exception e) {        throw new RuntimeException(e.getMessage(), e);    }     public String loadFile(String path) throws Exception {        FileInputStream stream = new FileInputStream(path);        try {            Reader br = new BufferedReader(new InputStreamReader(stream));            StringBuffer sb = new StringBuffer();            for (int c = br.read(); c != -1; c = br.read())                sb.append((char) c);            return sb.toString();        } finally {            stream.close();        }    }     public String loadResource(String name) throws Exception {        InputStream stream = getClass().getClassLoader().getResourceAsStream(                name);        try {            Reader br = new BufferedReader(new InputStreamReader(stream));            StringBuffer sb = new StringBuffer();            for (int c = br.read(); c != -1; c = br.read())                sb.append((char) c);            return sb.toString();        } finally {            stream.close();        }    } }Java 1.4 with Commons-Lang (2005)This is typical old Java 1.4 source code using Apache Commons-Lang. There is less boilerplate, but it’s still very unsafe (missing generics, for each).// STABLE: COMMONS-LANGpublic class Java4CommonsLangImpl implements IJavaUseCases {     public boolean condition(String arg) {        return StringUtils.isNotBlank(arg);    }     public void check(String arg) {        if (!condition(arg)) {            throw new IllegalArgumentException();        }    }     public List filter(List input) {        ...    }     public List map(List input) {        ...    }     public void errorHandling(Exception e) {        ...    }     public String loadFile(String path) throws Exception {        File file = new File(path);        return FileUtils.readFileToString(file);    }     public String loadResource(String name) throws Exception {        ClassLoader classLoader = this.getClass().getClassLoader();        return IOUtils.toString(classLoader.getResourceAsStream(name));    }}Java 1.6 with Commons-Lang (2007)This is lazy old Java 1.6 source code, still using outdated Commons-lang instead of more modern library like Spring or Guava. Not very different, but saffer (generics, foreach).// STABLE: COMMONS-LANG, JAVA GENERICSpublic class Java6CommonsLangImpl implements IJavaUseCases {     public boolean condition(String arg) {        ...    }     public void check(String arg) {        ...    }     public List&lt;String&gt; filter(List&lt;String&gt; input) {        List&lt;String&gt; output = new ArrayList&lt;String&gt;();        for (String current : input) {            if (condition(current)) {                output.add(current);            }        }        return output;    }     public List&lt;String&gt; map(List&lt;String&gt; input) {        List&lt;String&gt; output = new ArrayList&lt;String&gt;();        for (String current : input) {            String transformed = current.toUpperCase();            output.add(transformed);        }        return output;    }     public void errorHandling(Exception e) {        ...    }     public String loadFile(String path) throws Exception {        ...    }     public String loadResource(String name) throws Exception {        ...    }}Java 1.6 with Guava (2011)This is actual Java 1.6 source code. Using modern library like Guava. This version is practilly bug-free and comprehensive because of the removing of boilerplate (using guava API and Impl instead).// STABLE: GUAVA UTILS// FAST: GUAVA IMPLpublic class Java6GuavaImpl implements IJavaUseCases {     public boolean condition(String arg) {        return !Strings.nullToEmpty(arg).trim().isEmpty();    }     public void check(String arg) {        Preconditions.checkArgument(condition(arg));    }     public List&lt;String&gt; filter(List&lt;String&gt; input) {        return new ArrayList(Collections2.filter(input,                new Predicate&lt;String&gt;() {                    public boolean apply(String input) {                        return condition(input);                    }                }));    }     public List&lt;String&gt; map(List&lt;String&gt; input) {        return Lists.transform(input, new Function&lt;String, String&gt;() {            public String apply(String input) {                return input.toUpperCase();            }        });    }     public void errorHandling(Exception e) {        throw Throwables.propagate(e);    }     public String loadFile(String path) throws IOException {        File file = new File(path);        return Files.toString(file, Charsets.UTF_8);    }     public String loadResource(String name) throws IOException {        URL url = Resources.getResource(name);        return Resources.toString(url, Charsets.UTF_8);    }}Java 8 (2015)This is actual “state of the art” Java 8. Using new Java API instead of Guava. The source code is a lot smaller, comprehensive, and faster because of the implementation delegation. Good functions like check() and isBlanck() are still missing. Maybe relying on JavaEE with BeanValidation annotation like @NotNull, @NotEmpty.// STABLE: GUAVA UTILS, JAVA 8 UTILS// FAST: JAVA 8 IMPLpublic class Java8GuavaImpl implements IJavaUseCases {     public boolean condition(String arg) {        ...    }     public void check(String arg) {        ...    }     public List&lt;String&gt; filter(List&lt;String&gt; input) {        return input.stream() //                .filter(i -&gt; condition(i)) //                .collect(Collectors.toList());    }     public List&lt;String&gt; map(List&lt;String&gt; input) {        return input.stream() //                .map(i -&gt; i.toUpperCase()) //                .collect(Collectors.toList());    }     public void errorHandling(Exception e) {        ...    }     public String loadFile(String path) throws IOException {        return new String(Files.readAllBytes(Paths.get(path)));    }     public String loadResource(String name) throws Exception {        URI uri = ClassLoader.getSystemResource(name).toURI();        return new String(Files.readAllBytes(Paths.get(uri)));    }}DemoThe same test suite will be played for each technical stacks, by using JUnit Parameterized. JavaUseCasesTest.java@RunWith(value = Parameterized.class)public class JavaUseCasesTest {     private IJavaUseCases classToTest;     public JavaUseCasesTest(IJavaUseCases classToTest) {        this.classToTest = classToTest;    }     @Parameters(name = \"test of class {0}\")    public static Iterable&lt;Object[]&gt; data() {        return asList(new Object[][] { //        //                { new Java4AVanillaImpl() }, //                { new Java4CommonsLangImpl() }, //                { new Java6CommonsLangImpl() }, //                { new Java6GuavaImpl() }, //                { new Java8GuavaImpl() } });    }     @Test    public void test_Condition() {        assertTrue(classToTest.condition(\"Valid\"));        assertFalse(classToTest.condition(null));        assertFalse(classToTest.condition(\"\"));        assertFalse(classToTest.condition(\" \"));    }     @Test    public void test_Check() {        classToTest.check(\"Valid\");        try {            classToTest.check(null);            fail(\"EXPECTED ERROR!\");        } catch (Exception e) {            assertTrue(e instanceof IllegalArgumentException);        }        try {            classToTest.check(\"\");            fail(\"EXPECTED ERROR!\");        } catch (Exception e) {            assertTrue(e instanceof IllegalArgumentException);        }    }     @Test    public void test_Transform() {        List&lt;String&gt; args = asList(new String[] { \"a\", \"b\", \"c\" });        List&lt;String&gt; expected = asList(new String[] { \"A\", \"B\", \"C\" });        List&lt;String&gt; result = classToTest.map(args);        assertNotNull(result);        assertEquals(expected.size(), result.size());        for (int i = 0; i &lt; result.size(); i++) {            assertEquals(expected.get(i), result.get(i));        }    }     @Test    public void test_Filter() {        List&lt;String&gt; args = asList(new String[] { \"a\", \"\", \"c\" });        List&lt;String&gt; expected = asList(new String[] { \"a\", \"c\" });        List&lt;String&gt; result = classToTest.filter(args);        assertNotNull(result);        assertEquals(expected.size(), result.size());        for (int i = 0; i &lt; result.size(); i++) {            assertEquals(expected.get(i), result.get(i));        }    }     @Test    public void test_Error_Handling() {        IllegalStateException arg = new IllegalStateException(\"AAhhh!\");        try {            classToTest.errorHandling(arg);            fail(\"EXPECTED ERROR!\");        } catch (Exception e) {            assertTrue(e instanceof RuntimeException);            assertEquals(arg.getMessage(), e.getMessage());        }    }     @Test    public void test_Load_File() throws Exception {        String result = classToTest.loadFile(\"src/main/resources/file.txt\");        assertEquals(\"file content\", result);    }     @Test    public void test_Load_Resource() throws Exception {        String result = classToTest.loadResource(\"resource.txt\");        assertEquals(\"resource content\", result);    }}pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150806-java-commonslang_guava_java8&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;dependencies&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;!-- APACHE LANGUAGE EXTENSION --&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.commons&lt;/groupId&gt;            &lt;artifactId&gt;commons-lang3&lt;/artifactId&gt;            &lt;version&gt;3.4&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;commons-io&lt;/groupId&gt;            &lt;artifactId&gt;commons-io&lt;/artifactId&gt;            &lt;version&gt;2.4&lt;/version&gt;        &lt;/dependency&gt;        &lt;!-- GOOGLE LANGUAGE EXTENSION --&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.google.guava&lt;/groupId&gt;            &lt;artifactId&gt;guava&lt;/artifactId&gt;            &lt;version&gt;18.0&lt;/version&gt;        &lt;/dependency&gt;    &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.3&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;1.8&lt;/source&gt;                    &lt;target&gt;1.8&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;##ConclusionThere is no going back, for the purpose of quality and productivity. The only reason not to use this last source code is if Java8 is not allowed on your project. Same for Java6 with Guava, or Java4 with Commons-Lang. On the opposite, vanilla Java 1.4 or Java 1.6 with Commons-Lang are no longer relevant.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150806-java-commonslang_guava_java8https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150806-java-commonslang_guava_java8Referenceshttps://commons.apache.org/proper/commons-lang/javadocs/api-release/index.htmlhttps://commons.apache.org/proper/commons-lang/javadocs/api-release/index.htmlhttps://code.google.com/p/guava-libraries/wiki/GuavaExplainedhttps://code.google.com/p/guava-libraries/wiki/GuavaExplainedhttp://tutorials.jenkov.com/java-collections/streams.htmlhttp://tutorials.jenkov.com/java-collections/streams.htmlhttp://www.mkyong.com/unittest/junit-4-tutorial-6-parameterized-test/http://www.mkyong.com/unittest/junit-4-tutorial-6-parameterized-test/Originhttps://damienfremont.com/2015/08/06/migrating-from-java4-commonslang-to-java6-guava-to-java8/",
        "url": "/2015/08/06/migrating-from-java4-commonslang-to-java6-guava-to-java8"
      },
    
      "2015-07-31-responsive-button-with-bootstrap-toggable-text": {
        "title": "Responsive Button With Bootstrap Toggable Text",
        "author": "",
        "category": "",
        "tags": "bootstrap, css",
        "content": "The default Bootstrap buttons is not responsive. When the device is too small, the grid is responsive and change the layout, but the buttons stay the same. This tutorial show how to toggle the text from a button when the device required it.The solution will be tested on different devices/resolutions: mobile, tablet, laptop, desktopwith this behaviour:#Default ButtonsThe default buttons Text is not responsive. On smaller device, it will break the layout because of the buttons size.DemoSourcehtml&lt;div class=\"btn-toolbar\" role=\"toolbar\"&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-lg\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Large  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Default  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-sm\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Medium  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-xs\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Small  &lt;/button&gt;&lt;/div&gt;Responsive ButtonsResponsive buttons needs to repond the same way as the grid. On smaller device, text is expected to disappeared on targeted buttons. Button icon must stay the same.Demo##JSFiddle herehttp://jsfiddle.net/damien_fremont/nLxcws7q/http://jsfiddle.net/damien_fremont/nLxcws7q/SourceThe hack is just a little more CSS with a new set of Class named like those of the Grid system : btn-xs-text, btn-lg-text, etc.index.html&lt;h2&gt;Large&lt;/h2&gt; &lt;div class=\"btn-toolbar\" role=\"toolbar\"&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-lg btn-lg-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Large  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default        btn-lg-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Default  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-sm btn-lg-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Medium  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-xs btn-lg-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Small  &lt;/button&gt;&lt;/div&gt; &lt;h2&gt;Medium&lt;/h2&gt; &lt;div class=\"btn-toolbar\" role=\"toolbar\"&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-lg btn-md-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Large  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default        btn-md-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Default  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-sm btn-md-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Medium  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-xs btn-md-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Small  &lt;/button&gt;&lt;/div&gt; &lt;h2&gt;Small&lt;/h2&gt; &lt;div class=\"btn-toolbar\" role=\"toolbar\"&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-lg btn-xs-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Large  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default        btn-xs-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Default  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-sm btn-xs-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Medium  &lt;/button&gt;  &lt;button type=\"button\" class=\"btn btn-default btn-xs btn-xs-text\"&gt;    &lt;span class=\"glyphicon glyphicon-ok\" aria-hidden=\"true\"&gt;&lt;/span&gt;    Small  &lt;/button&gt;&lt;/div&gt;css/* Small devices (tablets, 768px and up) */@media ( max-width : 768px ) {  .btn-xs-text.btn-default:not(span) {    font-size: 0pt !important;  }  .btn-xs-text.btn-default.btn-lg .glyphicon {    font-size: 18pt !important;  }  .btn-xs-text.btn-default .glyphicon {    font-size: 14pt !important;  }  .btn-xs-text.btn-default.btn-sm .glyphicon {    font-size: 12pt !important;  }  .btn-xs-text.btn-default.btn-xs .glyphicon {    font-size: 12pt !important;  }}/* Medium devices (desktops, 992px and up) */@media ( max-width : 992px ) {  .btn-md-text.btn-default:not(span) {    font-size: 0pt !important;  }  .btn-md-text.btn-default.btn-lg .glyphicon {    font-size: 18pt !important;  }  .btn-md-text.btn-default .glyphicon {    font-size: 14pt !important;  }  .btn-md-text.btn-default.btn-sm .glyphicon {    font-size: 12pt !important;  }  .btn-md-text.btn-default.btn-xs .glyphicon {    font-size: 12pt !important;  }}/* Large devices (large desktops, 1200px and up) */@media ( max-width : 1200px ) {  .btn-lg-text.btn-default:not(span) {    font-size: 0pt !important;  }  .btn-lg-text.btn-default.btn-lg .glyphicon {    font-size: 18pt !important;  }  .btn-lg-text.btn-default .glyphicon {    font-size: 14pt !important;  }  .btn-lg-text.btn-default.btn-sm .glyphicon {    font-size: 12pt !important;  }  .btn-lg-text.btn-default.btn-xs .glyphicon {    font-size: 12pt !important;  }}#ConclusionDefault Buttons:Responsive ButtonsSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150731-bootstrap-responsive_buttonhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150731-bootstrap-responsive_buttonReferenceshttp://getbootstrap.com/css/#buttonshttp://getbootstrap.com/css/#buttonshttp://getbootstrap.com/components/#glyphicons-exampleshttp://getbootstrap.com/components/#glyphicons-exampleshttp://getbootstrap.com/css/#gridhttp://getbootstrap.com/css/#gridOriginhttps://damienfremont.com/2015/07/31/responsive-button-with-bootstrap-toggable-text/",
        "url": "/2015/07/31/responsive-button-with-bootstrap-toggable-text"
      },
    
      "2015-07-30-how-to-cucumber-test-reporting-plugin-with-maven-and-java": {
        "title": "How To Cucumber Test Reporting Plugin With Maven And Java",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, junit, test",
        "content": "It is often useful to show the results of our tests to others people who are not developers, like managers or executive. This tutorial shows how to integrate a Cucumber reporting a Java plugin in Maven project. The result is a simple web page, which does not require a special tool to be read.How to Cucumber : Test Report Plugin 2 with Maven and JavaEDIT: this post is deprecated. There is a better version of Cucumber Report plugin. Please read the new post here:How to Cucumber : Test Report Plugin 2 with Maven and JavaThis tutorial will cover 3 reports plugins : JSON, HTML Pretty and HTML Reports.Native JSON ResultHow to:pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150730-test-cucumber_plugin_reporting&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;dependencies&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;    &lt;/dependencies&gt;&lt;/project&gt;RunBDDTest.java@RunWith(Cucumber.class)@CucumberOptions(strict = false, features = &amp;quot;features&amp;quot;, format = { &amp;quot;pretty&amp;quot;,        &amp;quot;json:target/cucumber.json&amp;quot; }, tags = { &amp;quot;~@ignore&amp;quot; })public class RunBDDTest { }Demo:Launch with JUnit or&amp;gt;mvn testThe result is at /target/cucumber.jsonNative HTML PluginHow to:RunBDDTest.java@RunWith(Cucumber.class)@CucumberOptions(strict = false, features = &amp;quot;features&amp;quot;, format = { &amp;quot;pretty&amp;quot;,        &amp;quot;html:target/site/cucumber-pretty&amp;quot;,        &amp;quot;json:target/cucumber.json&amp;quot; }, tags = { &amp;quot;~@ignore&amp;quot; })public class RunBDDTest { }Demo:Launch with JUnit or&amp;gt;mvn testThe result is at /target/site/cucumber-pretty/index.htmlCucumber-Reports HTML PluginHow to:pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150730-test-cucumber_plugin_reporting&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;dependencies&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;          &lt;!-- REPORTING --&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.googlecode.totallylazy&lt;/groupId&gt;            &lt;artifactId&gt;totallylazy&lt;/artifactId&gt;            &lt;version&gt;1.20&lt;/version&gt;            &lt;scope&gt;system&lt;/scope&gt;            &lt;systemPath&gt;${project.basedir}/lib/totallylazy-1.20.jar&lt;/systemPath&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;net.masterthought&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-reporting&lt;/artifactId&gt;            &lt;version&gt;0.0.24&lt;/version&gt;        &lt;/dependency&gt;      &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.3&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;1.8&lt;/source&gt;                    &lt;target&gt;1.8&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-surefire-plugin&lt;/artifactId&gt;                &lt;version&gt;2.18.1&lt;/version&gt;                &lt;configuration&gt;                    &lt;testFailureIgnore&gt;true&lt;/testFailureIgnore&gt;                    &lt;includes&gt;                        &lt;exclude&gt;**/*BDDTest.java&lt;/exclude&gt;                    &lt;/includes&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;            &lt;plugin&gt;                &lt;groupId&gt;net.masterthought&lt;/groupId&gt;                &lt;artifactId&gt;maven-cucumber-reporting&lt;/artifactId&gt;                &lt;version&gt;0.0.5&lt;/version&gt;                &lt;dependencies&gt;                    &lt;dependency&gt;                        &lt;groupId&gt;com.googlecode.totallylazy&lt;/groupId&gt;                        &lt;artifactId&gt;totallylazy&lt;/artifactId&gt;                        &lt;version&gt;991&lt;/version&gt;                        &lt;scope&gt;system&lt;/scope&gt;                        &lt;systemPath&gt;${project.basedir}/lib/totallylazy-991.jar&lt;/systemPath&gt;                    &lt;/dependency&gt;                &lt;/dependencies&gt;                &lt;executions&gt;                    &lt;execution&gt;                        &lt;id&gt;execution&lt;/id&gt;                        &lt;phase&gt;verify&lt;/phase&gt;                        &lt;goals&gt;                            &lt;goal&gt;generate&lt;/goal&gt;                        &lt;/goals&gt;                        &lt;configuration&gt;                            &lt;projectName&gt;cucumber-jvm-example&lt;/projectName&gt;                            &lt;outputDirectory&gt;${project.build.directory}/site/cucumber-reports&lt;/outputDirectory&gt;                            &lt;cucumberOutput&gt;${project.build.directory}/cucumber.json&lt;/cucumberOutput&gt;                            &lt;enableFlashCharts&gt;false&lt;/enableFlashCharts&gt;                            &lt;skippedFails&gt;true&lt;/skippedFails&gt;                        &lt;/configuration&gt;                    &lt;/execution&gt;                &lt;/executions&gt;            &lt;/plugin&gt;          &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;And two libs (external to Maven repositories)https://code.google.com/p/totallylazy/downloads/listhttps://code.google.com/p/totallylazy/downloads/listRunBDDTest.java@RunWith(Cucumber.class)@CucumberOptions(strict = false, features = &amp;quot;features&amp;quot;, format = { &amp;quot;pretty&amp;quot;,        &amp;quot;html:target/site/cucumber-pretty&amp;quot;,        &amp;quot;json:target/cucumber.json&amp;quot; }, tags = { &amp;quot;~@ignore&amp;quot; })public class RunBDDTest { }Demo:Launch withmvn clean installThe result is at /target/site/cucumber-reports/feature-overview.htmlConclusionJSON is OK for integration with other tools (jenkins plugin, reports, etc).Pretty HTML is OK during development phase (like a JUnit or Surefire report for versionning).Cucumber-Reports is good for reporting outside of the dev team (like managers).Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150730-test-cucumber_plugin_reportinghttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150730-test-cucumber_plugin_reportingReferenceshttps://cucumber.io/docs/reference/jvmhttps://cucumber.io/docs/reference/jvmhttps://github.com/masterthought/cucumber-reportinghttps://github.com/masterthought/cucumber-reportinghttp://www.masterthought.net/section/cucumber-reportinghttp://www.masterthought.net/section/cucumber-reportingOriginhttps://damienfremont.com/2015/07/30/how-to-cucumber-test-reporting-plugin-with-maven-and-java/",
        "url": "/2015/07/30/how-to-cucumber-test-reporting-plugin-with-maven-and-java"
      },
    
      "2015-07-28-comment-agrandir-reduire-les-lignes-dun-tableau-avec-bootstrap": {
        "title": "Comment Agrandir Reduire Les Lignes Dun Tableau Avec Bootstrap",
        "author": "",
        "category": "",
        "tags": "bootstrap, css",
        "content": "Comment faire des accordéons dans des lignes de tableau en Twitter Bootstrap ? Nous verrons qu’utiliser une table pour faire un tableau …n’est pas une si bonne idée !ObjectifFaire un tableau dont chaque ligne est cliquable pour afficher un sous-contenu masqué (partie gauche) et/ou pour naviguer avec des boutons cliquables (partie droite).composant collapse de bootstrapboutons stylésIl faut donc intégrer le composant collapse de bootstrap  et des boutons stylés.Approche 1 avec tableEtape 1 : tablebootstrap nous propose pour un simple tableauRien à dire, c’est la solution la plus logique, car c’est celle que bootstrap nous propose pour un simple tableau&lt;tr&gt;    &lt;td&gt;1&lt;/td&gt;    &lt;td&gt;Mark&lt;/td&gt;    &lt;td&gt;Otto&lt;/td&gt;    &lt;td&gt;@mdo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;2&lt;/td&gt;    &lt;td&gt;Jacob&lt;/td&gt;    &lt;td&gt;Thornton&lt;/td&gt;    &lt;td&gt;@fat&lt;/td&gt;&lt;/tr&gt;Etape 2 : table + collapsevariante sans accordion de la doc bootstraIl faut utiliser la variante sans accordion de la doc bootstrap avec seulement data-target et collapse.Problème : le collapse ne fonctionne pas pour une balise TR en target.Solution : créer un DIV dans un sous-TR (facultatif : ajouter du CSS pour cacher le résidu permanent de margin/padding de la ligne cachée/collapsed) .&lt;tr class=\"accordion-toggle\"  data-toggle=\"collapse\" data-target=\"#collapseOne\"&gt;    &lt;td&gt;1&lt;/td&gt;    &lt;td&gt;Mark&lt;/td&gt;    &lt;td&gt;Otto&lt;/td&gt;    &lt;td&gt;@mdo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td colspan=\"3\"&gt;        &lt;div id=\"collapseOne\" class=\"collapse in\"&gt;            Details 1 &lt;br/&gt;            Details 2 &lt;br/&gt;            Details 3 &lt;br/&gt;        &lt;/div&gt;    &lt;/td&gt;&lt;/tr&gt;Etape 3 : table + collapse + buttonsProblème : un clique sur un bouton provoque un effet de bord d’expand/collapse de la ligne le contenant. C’est gênant quand on fait nouvel onglet sur un bouton car le détails s’affiche.Solution : il faut empêcher l’expand/collapse de se déclencher en cas d’appui sur un bouton. Il faut donc assigner le click expand à chaque cellule td plutot que sur le tr.Ça fonctionne, MAIS le Javascript rame au expand/collapse quand il y a plusieurs dizaines de lignes et sous-lignes sur la page ET il y a du code dupliqué.&lt;tr class=\"accordion-toggle\"  &gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;1&lt;/td&gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;Mark&lt;/td&gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;Otto&lt;/td&gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;@mdo&lt;/td&gt;    &lt;td&gt;&lt;a class=\"btn btn-primary\" href=\"https://www.google.com/\"&gt;&lt;i class=\"icon-search icon-white\"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td colspan=\"4\"&gt;        &lt;div id=\"collapseTwo\" class=\"collapse in\"&gt;            - Details 1 &lt;br/&gt;            - Details 2 &lt;br/&gt;            - Details 3 &lt;br/&gt;        &lt;/div&gt;    &lt;/td&gt;&lt;/tr&gt;Approche 2 avec divEtape 1 : divsystème de grille sur lequel repose bootstrapOn utilise le système de grille sur lequel repose bootstrap.Problème : les styles de table sont perdus.Solution : (facultatif) Il faut refaire du CSS si l’on veut obtenir le même rendu que précédemment (row top border, cell width, header bold).&lt;div class=\"row-fluid\" &gt;    &lt;div class=\"span2\"&gt;1&lt;/div&gt;    &lt;div class=\"span2\"&gt;Mark&lt;/div&gt;    &lt;div class=\"span2\"&gt;Otto&lt;/div&gt;    &lt;div class=\"span2\"&gt;@mdo&lt;/div&gt;&lt;/div&gt;Etape 2 : div + collapse(idem solution table+collapse)Problème : le curseur ne change pas de forme lors du survole de la ligne cliquable (icone “main”).Solution : (facultatif) utiliser un style perso ou re-utiliser la class accordion-toggle sur la div collapsable.Solution&lt;div class=\"row-fluid\" data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;    &lt;div class=\"span1\"&gt;1&lt;/div&gt;    &lt;div class=\"span3\"&gt;Mark&lt;/div&gt;    &lt;div class=\"span3\"&gt;Otto&lt;/div&gt;    &lt;div class=\"span3\"&gt;@mdo&lt;/div&gt;&lt;/div&gt;&lt;div id=\"collapseTwo\" class=\"row-fluid collapse in\"&gt;    &lt;div class=\"span1\"&gt;&lt;/div&gt;    &lt;div class=\"span9\"&gt;        Details 1 &lt;br/&gt;        Details 2 &lt;br/&gt;        Details 3 &lt;br/&gt;    &lt;/div&gt;&lt;/div&gt;Etape 3 : div + collapse + buttons(idem solution table+collapse+buttons)Problème : L’ajout de boutons entre également en conflit avec le collapse/expand.Solution : sortir le bouton de la div toggler.&lt;div class=\"row-fluid\" &gt;    &lt;div class=\"accordion-toggle\" data-toggle=\"collapse\" data-target=\"#collapseThree\"&gt;        &lt;div class=\"span1\"&gt;1&lt;/div&gt;        &lt;div class=\"span3\"&gt;Mark&lt;/div&gt;        &lt;div class=\"span3\"&gt;Otto&lt;/div&gt;        &lt;div class=\"span3\"&gt;@mdo&lt;/div&gt;    &lt;/div&gt;    &lt;div class=\"span1\"&gt;        &lt;button type=\"button\" class=\"btn btn-primary\"&gt;&lt;i class=\"icon-search icon-white\"&gt;&lt;/i&gt;&lt;/button&gt;    &lt;/div&gt;&lt;/div&gt;&lt;div id=\"collapseThree\" class=\"row-fluid collapse in\"&gt;    &lt;div class=\"span1\"&gt;&lt;/div&gt;    &lt;div class=\"span9\"&gt;        Details 1 &lt;br/&gt;        Details 2 &lt;br/&gt;        Details 3 &lt;br/&gt;    &lt;/div&gt;&lt;/div&gt;#ConclusionJ’utilise actuellement la version avec DIV après avoir utilisé TABLE. Au final la page n’était plus assez réactive, le code dupliqué était source de bugs/maintenance et la solution technique avec TABLE n’était pas toujours compréhensible, même avec la doc de bootstrap à coté.COLLAPSABLE TABLE  Pro : style par defaut dans bootstrap, aimer les tables ?  Con : solution de contournement, performances, duplication de codeCOLLAPSABLE  DIV  Pro : responsive, performant  Con : styles curseur et tableau à redéfinirSourceshttp://github.com/damienfremont/blog/tree/master/20141216-bootstrap-collapsable_tablehttp://github.com/damienfremont/blog/tree/master/20141216-bootstrap-collapsable_tableReferenceshttp://getbootstrap.com/2.3.2/http://getbootstrap.com/2.3.2/http://getbootstrap.com/2.3.2/base-css.htmlhttp://getbootstrap.com/2.3.2/base-css.htmlhttp://getbootstrap.com/2.3.2/javascript.htmlhttp://getbootstrap.com/2.3.2/javascript.htmlhttp://getbootstrap.com/2.3.2/scaffolding.htmlhttp://getbootstrap.com/2.3.2/scaffolding.htmlhttp://getbootstrap.com/2.3.2/components.htmlhttp://getbootstrap.com/2.3.2/components.htmlOriginhttps://damienfremont.com/2015/07/28/comment-agrandir-reduire-les-lignes-dun-tableau-avec-bootstrap/ ",
        "url": "/2015/07/28/comment-agrandir-reduire-les-lignes-dun-tableau-avec-bootstrap"
      },
    
      "2015-07-23-how-to-cucumber-java-reuse-same-scenario-for-core-service-and-web-ui-tests": {
        "title": "How-To Cucumber: Re-use Same Scenario For Core Service And Web UI Tests",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, junit, test, selenium",
        "content": "An example of unified code to reuse the same functional test scenario. Over unit tests of the core component code, or exposed API and services, and finally the web application UI.It’s useful for quality: non-regression test, continous integration, fast feedback, short loop, cost reduction, etc.Step 1 : Write a Generic Cucumber Scenarioperson-repository.featureFeature: Person Repository   Scenario: Person Creation    Given an empty repository    When I create a new Person named 'George' with the system    Then I should have Person named 'George' in the repositoryAnd give it to developers.Step 2 : Code a Unit Test for Core ComponentRunBDDTest.javapackage com.damienfremont.blog; import org.junit.runner.RunWith; import cucumber.api.CucumberOptions;import cucumber.api.junit.Cucumber; @RunWith(Cucumber.class)@CucumberOptions(strict = true, features = \"../features\")public class RunBDDTest { }StepDefinitions.javapackage com.damienfremont.blog; import static org.assertj.core.api.StrictAssertions.assertThat;import cucumber.api.java8.En; public class StepDefinitions implements En {     static PersonRepository SYSTEM = new PersonRepository();     public StepDefinitions() {         Given(\"an empty repository\",            () -&gt;                assertThat( SYSTEM.count()).isEqualTo( 0 ));         When(\"I create a new Person named '(.*)' with the system\",            (String name) -&gt;                SYSTEM.create( new PersonModel(name)));         Then(\"I should have Person named '(.*)' in the repository\",            (String name) -&gt;                assertThat(SYSTEM.read(name)).isNotNull());             }}Step 3 : Code API Test with REST clientRunBDDTest.java(the same as before)EmbeddedServer.java(see previous post)StepDefinitions.javapackage com.damienfremont.blog; import static com.jayway.restassured.RestAssured.expect;import static org.hamcrest.Matchers.hasItems;import static org.hamcrest.Matchers.hasSize;import com.google.common.base.Throwables;import cucumber.api.java8.En; public class StepDefinitions implements En {     private static EmbeddedServer SYSTEM;         public StepDefinitions() {         Given(\"an empty repository\",            () -&gt;                expect()                    .statusCode(200)                    .body(\"results\", hasSize(0))                .when()                    .get(\"/server/api/person\"));         When(\"I create a new Person named '(.*)' with the system\",            (String name) -&gt;                expect()                    .statusCode(200)                .given()                    .contentType(\"text/plain\")                    .content(name)                .when()                    .post(\"/server/api/person\"));         Then(\"I should have Person named '(.*)' in the repository\",            (String name) -&gt;                expect()                    .statusCode(200)                    .body(\"name\", hasItems(name))                .when()                    .get(\"/server/api/person\"));                 Before(            ()-&gt; {                try {                    SYSTEM = new EmbeddedServer(8080, \"/server\");                    SYSTEM.start();                } catch (Exception e) {                    throw Throwables.propagate(e);                }        });                 After(            ()-&gt; {                SYSTEM.stop();            });    }}Step 4 : Code a Web UI Test with SeleniumRunBDDTest.java(the same as before)StepDefinitions.javapackage com.damienfremont.blog; import static java.util.concurrent.TimeUnit.SECONDS;import static org.junit.Assert.assertTrue;import static org.openqa.selenium.phantomjs.PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY;import org.openqa.selenium.By;import org.openqa.selenium.WebDriver;import org.openqa.selenium.phantomjs.PhantomJSDriver;import org.openqa.selenium.remote.DesiredCapabilities;import com.google.common.base.Throwables;import com.google.common.collect.ImmutableMap; import cucumber.api.java8.En; public class StepDefinitions implements En {     private static EmbeddedServer server;    private static WebDriver driver;         public StepDefinitions() {         Given(\"an empty repository\",            () -&gt; {                driver.get(\"http://localhost:8080/server\");                assertTrue(driver.findElement(By.cssSelector(                    \"#message\"))                        .getText().contains(\"0 items\"));                assertTrue(driver.findElement(By.cssSelector(                    \"#items\"))                        .getText().isEmpty());            });         When(\"I create a new Person named '(.*)' with the system\",            (String name) -&gt;{                driver.get(\"http://localhost:8080/server\");                driver.findElement(By.cssSelector(                    \"#newItem\"))                        .sendKeys(name);                               driver.findElement(By.cssSelector(                    \"#newButton\"))                        .click();            });         Then(\"I should have Person named '(.*)' in the repository\",            (String name) -&gt;{                driver.get(\"http://localhost:8080/server\");                assertTrue(driver.findElement(By.cssSelector(                    \"#message\"))                        .getText().contains(\"1 items\"));                assertTrue(driver.findElement(By.cssSelector(                    \"#items\"))                        .getText().contains(name));            });                 Before(            ()-&gt; {                // INIT WEB SERVER (TOMCAT)                try {                    server = new EmbeddedServer(8080, \"/server\");                    server.start();                } catch (Exception e) {                    throw Throwables.propagate(e);                }                // INIT WEB BROWSER (SELENIUM + PHANTOMJS)                driver = new PhantomJSDriver(                new DesiredCapabilities(ImmutableMap.of( //                        PHANTOMJS_EXECUTABLE_PATH_PROPERTY, //                        new PhantomJsDownloader().downloadAndExtract()                                .getAbsolutePath())));                driver.manage().timeouts().implicitlyWait(5, SECONDS);        });                 After(            ()-&gt; {                server.stop();            });    }}DemoTest Core LayerTesting that core component:class PersonRepository {    PersonModel create(PersonModel entity) ...    List&lt;PersonModel&gt; readAll() ...}with this project:And launching RunBDDTest.java with JUnit:0.026 sec (test) + 0.2 sec (startup)Test Service LayerTesting that service API:with this project:And launching RunBDDTest.java with JUnit:0.210 sec (test) + 3 sec (startup)Test WebApp LayerTesting that web UI:with this project:And launching RunBDDTest.java with JUnit:0.628 sec (test) + 7 sec (startup)Project Layout ExampleA common feature file and maven sub-projectsMaven pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150722-test-cucumber_scenario_reuse&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;pom&lt;/packaging&gt;    &lt;modules&gt;        &lt;module&gt;project-core&lt;/module&gt;        &lt;module&gt;project-service&lt;/module&gt;        &lt;module&gt;project-webapp&lt;/module&gt;    &lt;/modules&gt;    &lt;dependencies&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.google.guava&lt;/groupId&gt;            &lt;artifactId&gt;guava&lt;/artifactId&gt;            &lt;version&gt;18.0&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.assertj&lt;/groupId&gt;            &lt;artifactId&gt;assertj-core&lt;/artifactId&gt;            &lt;version&gt;3.1.0&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;    &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;configuration&gt;                    &lt;source&gt;1.8&lt;/source&gt;                    &lt;target&gt;1.8&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;And launching all tests with Maven:17 secSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150722-test-cucumber_scenario_reusehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150722-test-cucumber_scenario_reuseReferenceshttp://jlunaquiroga.blogspot.fr/2014/01/restful-web-services-with-jetty-and.htmlhttp://jlunaquiroga.blogspot.fr/2014/01/restful-web-services-with-jetty-and.htmlhttp://zsoltfabok.com/blog/2012/08/embedded-web-services-for-testing/http://zsoltfabok.com/blog/2012/08/embedded-web-services-for-testing/https://github.com/tastejs/todomvc/tree/gh-pages/examples/vanillajshttps://github.com/tastejs/todomvc/tree/gh-pages/examples/vanillajsOriginhttps://damienfremont.com/2015/07/23/how-to-cucumber-java-reuse-same-scenario-for-core-service-and-web-ui-tests/ ",
        "url": "/2015/07/23/how-to-cucumber-java-reuse-same-scenario-for-core-service-and-web-ui-tests"
      },
    
      "2015-06-25-simple-gnu-c-compiler-with-nix-shell-on-windows": {
        "title": "Simple Gnu C Compiler With Nix Shell On Windows",
        "author": "",
        "category": "",
        "tags": "c, quicktip",
        "content": "This tutorial is intended for developers who want to start developing in C on Windows, without having to use a heavy software like VisualStudio. And having a Linux like shell of course.How toDownload MinGW for Windows at:http://sourceforge.net/projects/mingw/files/latest/download?source=fileshttp://sourceforge.net/projects/mingw/files/latest/download?source=filesExecute the MinGW installerin admin modeFollow the installer stepsThen close the windowA new winows appears : the installerselect packages to install :  dev-tools  base (c compiler)  g++ (c++ compiler)  msys (NIX shell)Then click on Installation menu, update catalogueA new window appears with some gibberish text. Click on ReviewClick on ApplyThen wait for the end of the download (30 secondes)After, close the installerExplorer your C: harddrive. A new MinGW folder appearsClick on C:\\MinGW\\msys\\1.0\\msys.batA new NIX shell appears.Create a .profile file inside (on Windows it’s not possible to create a file starting with “.”, so copy a file from my github or create it with touch command with the NIX shell)touch .profileClose it. It’s just for the creation of the default user home folder.A new home folder appears at C:\\MinGW\\msys\\1.0\\home\\Open it. It contains your home folder (in my case: C:\\MinGW\\msys\\1.0\\home\\Damien)Open .profile with your text editor and add this :.profile# Cd to my windows home:cd /c/Users/DamienSave it. And start msys.bat againAt NIX shell, type the ls command. The result is the content of your Windows user folder, instead of the NIX C:\\MinGW\\msys\\1.0\\home***Close this windows.Then create a shortcut of msys.bat to your desktop or set it in your Windows path env.Your environnement is ready!DemoCreate a c source code file in your user folder with your text editortest.c#include &lt;stdio.h&gt; int main(){    printf(\"Hello World!\");    return(0);}Launch msys.batA new NIX shell appears. Type the compile command gcc on your new source file.gcc test.cExecute the generated executable with :a NIX command :./a.exeor a Windows click on the .exeor a windows command linea.exeConclusionMinGW is a simple and friendly tool for those who seek to program on a Linux like shell on Windows.…BUT the MinGW documentation is very harsh with newbies, installer steps are very strange for a Windows user and the downloading package part required a lot of time (not easy in offline mode).It’s not a turnkey solution, but it does the job.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150625-c_compiler_win_shellhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150625-c_compiler_win_shellReferenceshttps://assos.centrale-marseille.fr/ginfo/tutoriels/ma%C3%AEtrisez-la-compilation-cc-sous-windowshttps://assos.centrale-marseille.fr/ginfo/tutoriels/ma%C3%AEtrisez-la-compilation-cc-sous-windowshttp://stackoverflow.com/questions/7000524/changing-mingw-startup-directory-or-creating-mingw-symlinkshttp://stackoverflow.com/questions/7000524/changing-mingw-startup-directory-or-creating-mingw-symlinkshttp://stackoverflow.com/questions/7000524/changing-mingw-startup-directory-or-creating-mingw-symlinkshttp://stackoverflow.com/questions/7000524/changing-mingw-startup-directory-or-creating-mingw-symlinksOriginhttps://damienfremont.com/2015/06/25/simple-gnu-c-compiler-with-nix-shell-on-windows/",
        "url": "/2015/06/25/simple-gnu-c-compiler-with-nix-shell-on-windows"
      },
    
      "2015-06-25-how-to-unity3d-command-build-without-build-pipeline": {
        "title": "How To Unity3d Command Build Without Build Pipeline",
        "author": "",
        "category": "",
        "tags": "unity3d",
        "content": "This tuturial explains how to build application without using the pro edition of Unity3d editor, wich integrates buildpipeline functionalities. Simply by using command line script.Warning : This tutorial is not useful if you own the Pro Edition of Unity3d, wich already contains a buildpipeline system using Unity3d scriptting (Javascript or CSharp). In this case, go see :http://docs.unity3d.com/Manual/BuildPlayerPipeline.htmlhttp://docs.unity3d.com/Manual/BuildPlayerPipeline.htmlStep 1 : Create ProjectSo create a new project.Save your project !Step 2 : Close Unity3d !This an important step because Unity3d only allows a single running instance of Unity3d.Step 2 : Create ScriptCreate a new file named build.bat at the project root folder, next to Assets folder.build.bat\"C:\\Program Files\\Unity\\Editor\\Unity.exe\" -quit -batchmode  -logFile stdout.log -buildWindowsPlayer \"builds\\build.exe\"Details :execute unity3d in batchmode / command line :\"C:\\Program Files\\Unity\\Editor\\Unity.exe\" -quit -batchmodecreate a log file containning build console output :-logFile stdout.logbuild the gameproject for windows plateforme :-buildWindowsPlayer \"builds\\build.exe\"DemoLaunch build.bat via command line for console output result, or just click on build.bat.A new window pops.After a while (30 sec), the window closes itself. The build is finished !Go open the newly created build folder.It contains your game executable.Click on build.exeThe game launcher appears. Click on Play!Then your game launchs.(it’s an empty scene here)Build console output is in stdout.log file, next to build.bat file.Error (first use only)Unity3d needs to link your project folder.Then you need to open your project with Unity3d a first time before building it by command line. For duplicate or moved project folder, you’ll need to reopen the folder with unity3d.ConclusionThis approach is more developper friendly than the unity3d IDE. You can use your own text editor like SublimeText and build with an automatic task.Unity3d web site is poorly documented on this usage.Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150625-unity3d-build_commandhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150625-unity3d-build_commandReferenceshttp://docs.unity3d.com/Manual/CommandLineArguments.htmlhttp://docs.unity3d.com/Manual/CommandLineArguments.htmlOriginhttps://damienfremont.com/2015/06/25/how-to-unity3d-command-build-without-build-pipeline/",
        "url": "/2015/06/25/how-to-unity3d-command-build-without-build-pipeline"
      },
    
      "2015-06-24-how-to-unity3d-start-with-javascript-scripting-only": {
        "title": "How To Unity3d Start With Javascript Scripting Only",
        "author": "",
        "category": "",
        "tags": "unity3d",
        "content": "This tutorial is for those who choose to program rather than using the Unity3d IDE.It covers multiple stages, from project creation to basic scripting.Step 1 : Prepare EnvironnementYou’ll need Unity3d. Get the free version here :https://unity3d.com/get-unity/https://unity3d.com/get-unity/Step 2 : Create ProjectSo create a new project.Choose a name for it.Step 3 : Create Main Scene and Game ObjectUnity3d needs at least one scene and a game object, to attach scripts on. And because it’s binary file, this can only be made only by using Unity3d SDK.At this point, unity3d is launched with an empty scene.So create an empty game object.Step 4 : Link Script to SceneJavaScript file needs to be attached to a game object.So select the new game object.Add a new component to it by clicking on component menu then add…At this point, Inspector view displays a new component form. Choose new script.Then type a name and choose a scripting language (Javascript here).Then click on create.Here is a new script ! When script is selected, the Inspector view display script content (source code).Step 5 : Start ScriptingRight click on the script file in the Asset view. Choose Open.Then the MonoDevelop editor starts…By default, a script has two function : start() and update(). Start function starts with the object, and so with the scene.Add a little code to your script.MainScript.js#pragma strict function Start () {     // SAY HELLO    print( \"Hello, world\" );     // GET SCENE OBJECTS    var cam = GameObject.Find(\"Main Camera\");    var mainObject = GameObject.Find(\"GameObject\");     // CENTER CAMERA ON OBJECT    cam.transform.LookAt(mainObject.transform);     // PAUSE    yield WaitForSeconds (1);     // ADD OBJECTS TO THE SCENE     var sphere : GameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);    sphere.transform.position = Vector3(0, 1.5, 0);     var sphere2 : GameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);    sphere2.transform.position = Vector3(2, 1, 0);     var sphere3 : GameObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);    sphere3.transform.position = Vector3(0, 0, 0); } function Update () { }Save your Javascript file.Save your ScriptDemoOpen your Unity3d SDK and click on Play button.And wait for the demo to start…Then wait 1 seconde.The demo add three new spheres to the scene.Then the demo print “Hello world” to the console.(and don’t forget to save your scene for later!)ConclusionFrom there, you can start to script an entire project, without even open Unity3d (only for building). It’s an easier way for building game were programming is a core aspect of the project. Like with procedural generation level or reusable components. Or for those who are not familiar with a 3d software like Unity3d IDE.Tips : for a full scripting, remove default camera and light from the scene, and add them by scripting.Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150624-unity3d-start_scriptinghttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150624-unity3d-start_scriptingReferenceshttp://docs.unity3d.com/Manual/CreatingAndUsingScripts.htmlhttp://docs.unity3d.com/Manual/CreatingAndUsingScripts.htmlhttps://unity3d.com/learn/tutorials/modules/beginner/scripting/classeshttps://unity3d.com/learn/tutorials/modules/beginner/scripting/classesOriginhttps://damienfremont.com/2015/06/24/how-to-unity3d-start-with-javascript-scripting-only/",
        "url": "/2015/06/24/how-to-unity3d-start-with-javascript-scripting-only"
      },
    
      "2015-04-19-tests-bdd-cucumber-simplifies-avec-les-lambdas-java8": {
        "title": "Tests Bdd Cucumber Simplifies Avec Les Lambdas Java8",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, junit, test",
        "content": "Ce tutorial explique comment écrire et coder des tests BDD (Behavior Driven Development) grâce à Cucumber pour Java et se focalise sur l’apport des lambdas de Java8 pour cet outil. Notamment sur la simplicité d’écriture.Tests BDD avec Cucumber JavaSuite et reprise du post Tests BDD avec Cucumber Java.EnvironnementLe code pour lancer les scénarios de test reste le même.RunBDDTest.java@RunWith(Cucumber.class)public class RunBDDTest { }C’est lui qui va inspecter StepDefinitions.java.Code Java 8 (lambda)StepDefinitions.javapublic class StepDefinitions implements En {     // CE QUI EST A TESTER     private PersonRepository personRepositoryToTest = new PersonRepository();     // DONNEES COMMUNES ENTRE STEPS     private long givenPersonSize;    private PersonModel whenPersonId;    private PersonModel whenPerson;     public StepDefinitions() {         // # EXEMPLE SIMPLE         Given(\"^L'entrepot contient N Personnes$\", () -&gt; {            givenPersonSize = personRepositoryToTest.count();            assertThat(givenPersonSize).isPositive();        });         When(\"^Je cree une Personne$\", () -&gt; {            PersonModel person = new PersonModel();            whenPersonId = personRepositoryToTest.create(person);        });         Then(\"^J'obtiens l'ID de la Personne cree et l'entrepot contient plus de N Personnes$\",                () -&gt; {                    assertThat(whenPersonId).isNotNull();                    long thenPersonCount = personRepositoryToTest.count();                    assertThat(thenPersonCount).isGreaterThan(givenPersonSize);                });         // # EXEMPLE SPECIFIQUE AVEC ARGUMENTS         Given(\"^L'entrepot contient la Personnes Anakin Skywalker$\", () -&gt; {            givenPersonSize = personRepositoryToTest.count();            PersonModel p = personRepositoryToTest.read(1);            assertThat(p.getPrenom()).isEqualTo(\"Anakin\");        });         When(\"^Je supprime la Personne (\\\\d+)$\", (Integer id) -&gt; {            personRepositoryToTest.delete(id);        });         Then(\"^L'entrepot contient moins de N Personnes$\",                () -&gt; {                    assertThat(personRepositoryToTest.count()).isLessThan(                            givenPersonSize);                });         // # EXEMPLE AVEC SUBSTITUTION (SCENARIO OUTLINES + EXAMPLES)         When(\"^Je recupere la Personne (\\\\d+)$\", (Integer id) -&gt; {            whenPerson = personRepositoryToTest.read(id);        });         Then(\"^J'obtiens la Personne d'identifiant (\\\\d+) contenant les donnees (.*), (.*), (.*)$\",                (Integer id, String prenom, String nom, String naissance) -&gt; {                    // J'obtiens la Personne d'identifiant                    assertThat(whenPerson).isNotNull();                    assertThat(whenPerson.getId()).isEqualTo(id);                    // avec les donnees                    assertThat(whenPerson.getPrenom()).isEqualTo(prenom);                    assertThat(whenPerson.getNom()).isEqualTo(nom);                    assertThat(whenPerson.getNaissance()).isEqualTo(naissance);                });    } }Code Java 7 (methods, matchers)StepDefinitions.javapublic class StepDefinitions {     // CE QUI EST A TESTER     private PersonRepository personRepositoryToTest = new PersonRepository();     // DONNEES COMMUNES ENTRE STEPS     private long givenPersonSize;    private PersonModel whenPersonId;    private PersonModel whenPerson;     // # EXEMPLE SIMPLE     @Given(\"^L'entrepôt contient N Personnes$\")    public void l_entrepôt_contient_N_Personnes() throws Throwable {        // L'entrepôt contient N Personnes        givenPersonSize = personRepositoryToTest.count();        assertThat(givenPersonSize).isPositive();    }     @When(\"^Je crée une Personne$\")    public void je_crée_une_Personne() throws Throwable {        // Je crée une Personne        PersonModel person = new PersonModel();        whenPersonId = personRepositoryToTest.create(person);    }     @Then(\"^J'obtiens l'ID de la Personne créée et l'entrepôt contient plus de N Personnes$\")    public void j_obtiens_l_ID_de_la_Personne_créée_et_l_entrepôt_contient_plus_de_N_Personnes()            throws Throwable {        // J'obtiens l'ID de la Personne créée        assertThat(whenPersonId).isNotNull();        // l'entrepôt contient N+X Personnes        long thenPersonCount = personRepositoryToTest.count();        assertThat(thenPersonCount).isGreaterThan(givenPersonSize);    }     // # EXEMPLE SPECIFIQUE AVEC ARGUMENTS     @Given(\"^L'entrepôt contient la Personnes Anakin Skywalker$\")    public void l_entrepôt_contient_la_Personnes_Anakin_Skywalker()            throws Throwable {        givenPersonSize = personRepositoryToTest.count();        // L'entrepôt contient la Personnes Anakin Skywalker        PersonModel p = personRepositoryToTest.read(1);        assertThat(p.getPrenom()).isEqualTo(\"Anakin\");    }     @When(\"^Je supprime la Personne (\\\\d+)$\")    public void je_supprime_la_Personne(int arg1) throws Throwable {        // Je supprime la Personne        personRepositoryToTest.delete(arg1);    }     @Then(\"^L'entrepôt contient moins de N Personnes$\")    public void l_entrepôt_contient_moins_de_N_Personnes() throws Throwable {        // L'entrepôt contient N-X Personnes        assertThat(personRepositoryToTest.count()).isLessThan(givenPersonSize);    }     // # EXEMPLE AVEC SUBSTITUTION (SCENARIO OUTLINES + EXAMPLES)     @When(\"^Je recupère la Personne (\\\\d+)$\")    public void je_recupère_la_Personne(int arg1) throws Throwable {        // Je recupère la Personne        whenPerson = personRepositoryToTest.read(arg1);    }     @Then(\"^J'obtiens la Personne d'identifiant (\\\\d+) contenant les données (.*), (.*), (.*)$\")    public void j_obtiens_la_Personne_d_identifiant_contenant_les_données(            int arg1, String prenom, String nom, String naissance)            throws Throwable {        // J'obtiens la Personne d'identifiant        assertThat(whenPerson).isNotNull();        assertThat(whenPerson.getId()).isEqualTo(arg1);        // avec les données        assertThat(whenPerson.getPrenom()).isEqualTo(prenom);        assertThat(whenPerson.getNom()).isEqualTo(nom);        assertThat(whenPerson.getNaissance()).isEqualTo(naissance);    }     // # EXEMPLE AVEC DATA TABLES     @Given(\"^L'entrepôt contient les Personnes suivantes$\")    public void l_entrepôt_contient_les_Personnes_suivantes(DataTable expected)            throws Throwable {        givenPersonSize = personRepositoryToTest.count();        // L'entrepôt contient les Personnes suivantes        List&lt;PersonModel&gt; actual = personRepositoryToTest.readAll();        for (final PersonModel exp : expected.asList(PersonModel.class)) {            assertThat(actual).haveExactly(1, new Condition&lt;PersonModel&gt;() {                 @Override                public boolean matches(PersonModel act) {                    return act.getId().equals(exp.getId()) //                            &amp;&amp; act.getPrenom().equals(exp.getPrenom()) //                            &amp;&amp; act.getNom().equals(exp.getNom()) //                            &amp;&amp; act.getNaissance().equals(exp.getNaissance());                }            });        }    }     @When(\"^Je modifie la Personne (\\\\d+) avec (.*)$\")    public void je_modifie_la_Personne_avec_(int id, String nom)            throws Throwable {        PersonModel p = personRepositoryToTest.read(id);        p.setNom(nom);        whenPerson = personRepositoryToTest.update(p);    } }Dependency (Maven)Il faut penser à passer à Cucumber-Java8 et AssertJ 3 pour bénéficier des apports de Java8.pom.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150419-test-cucumber_java8_lambda&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;properties&gt;        &lt;jdk.version&gt;1.8&lt;/jdk.version&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.assertj&lt;/groupId&gt;            &lt;artifactId&gt;assertj-core&lt;/artifactId&gt;            &lt;version&gt;3.0.0&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;         &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;            &lt;version&gt;1.2.2&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-java8&lt;/artifactId&gt;            &lt;version&gt;1.2.2&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;ConclusionCucumber devient enfin utilisable et productif en Java.En Java7, chaque Step devait être une méthode annotée de @Given(…), @When(…) ou @Then(…). Les asserts reposaient sur les Matchers. Définir les Steps étaient pénible en Java7, à cause de la duplication de code entre l’annotation et le nom de méthode.En Java8, l’écriture se rapproche de Groovy par exemple grâce aux lambda. La syntaxe est plus légère et robuste.Sourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150419-test-cucumber_java8_lambdahttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150419-test-cucumber_java8_lambdaReferenceshttps://cukes.info/docs/reference/jvmhttps://cukes.info/docs/reference/jvmhttps://rmannibucau.wordpress.com/2015/01/26/cukespace-or-bdd-arquillian-and-java-8/https://rmannibucau.wordpress.com/2015/01/26/cukespace-or-bdd-arquillian-and-java-8/Originhttps://damienfremont.com/2015/04/19/tests-bdd-cucumber-simplifies-avec-les-lambdas-java8/",
        "url": "/2015/04/19/tests-bdd-cucumber-simplifies-avec-les-lambdas-java8"
      },
    
      "2015-04-08-some-readings-update-2015": {
        "title": "Some Readings Update 2015",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Here are some, well known, books that I think are useful …in any case, they were for me! Some are about Java or JavaEE, other Object Oriented Programming",
        "url": "/2015/04/08/some-readings-update-2015"
      },
    
      "2015-03-16-developpeur-freelance-en-2015-se-lancer-13": {
        "title": "Developpeur Freelance En 2015 Se Lancer 13",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Ceci est mon retour d’expérience du passage de salarié en SSII vers développeur freelance après deux premiers mois d’activité.Etapes1. Avant de se lancerEvaluer sa motivationJ’y gagne quoi ? Un revenu en plus, de l’indépendance dans le choix des missions, étendre son activité, des préavis de mission plus courts (attention ça marche dans les 2 sens), faire passer une partie de votre logement et matériel informatique en charges.J’y perd quoi ? Parfois une bonne SSII. Le CDI, et tout ce qui va avec (faire un emprunts, changer de logement logement quand on est locataire en région Parisienne). Les congés payés et maladie.Exemple : Dans mon cas, je ne voyais pas bien ce que m’apportait une structure SSII avec un CE dont je profite peu, une promotion interne faible, une communauté parfois inexistante et un salaire parfois très éloigné du taux journalier. Par contre, devenir plus libre dans le choix des missions, sans la pression d’un commercial avec l’inter-contrat, ainsi qu’élargir mon activité à un peu de formation en annexe m’a motivé …mais je voulais aussi changer d’appart dans les prochains :-Sj’ai changé d’appartement avant de démissionner (coût : 1000€), puis démissionné …avec un préavis de 3 mois (yeurk!)Estimer son futur revenuC’est important pour ne pas avoir de fausse joie et savoir à quoi s’attendre au moment de payer l’impôt.http://tarifs.freelance-info.fr/developpeur/http://tarifs.freelance-info.fr/developpeur/Voici une formule toute faite pour le net de l’année (Merci Didier) : ((( – )* – 12*)*0,75)/12 = net mensuelLe chiffre d’affaire est plus simple : ( – )* = CAExemple : j’ai calculé mon revenu pour un dev Java de 5 ans d’expérience (((218-40)510-121000)0,75)/12 = 4900€/m soit un net de 59000 €/an et un CA de (218-40)510 = 90780€/an.Préparer sa créationIl faut se prévoir un peu de liquidité, en plus de ce qu’exige votre niveau de vie actuel. Ainsi, il y a aura inter-contrat, les différentes caisses qui vont commencer à vous ponctionner dès le premier trimestre avant même que vous ayez des revenus (impôts, URSSAF, RSI, retraite) et votre 1er client qui vous paiera à 60 jours la plupart du temps.Exemple : On m’avait conseillé de prévoir de quoi tenir plusieurs mois à raison de 2-3000€ par mois (pour Paris, avec un loyer exorbitant). J’ai gardé de coté de quoi tenir plusieurs mois (15000€).2. La création 1/2 : immatriculationQuelle forme choisir ?Dans mon cas pour un simple développeur freelance chez un client, je fais parti des travailleurs indépendants / liberaux exerçant une activité de conseil. Le simple statut EI (Entreprise individuelle) suffit et certains commencent même auto-entrepreneur la 1ere année. C’est le gouv qui le dit : http://vosdroits.service-public.fr/professionnels-entreprises/F23458.xhtmlComment créer ?Cela peut aussi maintenant se faire en ligne, il faudra ici inscrire principalement :– vos informations personnelles (nom, prénom, adresse etc.)– la nature de vos activités (ex : Développeur web) et le début de votre activité– s’il s’agit d’une création d’activité ou une reprise– votre numéro de sécurité sociale– des informations de contact (téléphone, mail etc.)La seule subtilité concerne les options fiscales. Il s’agit simplement du régime dont vous désirez bénéficier. En clair, vous devrez choisir le Régime Spécial BNC (appelé aussi Micro BNC) et inscrire « Réel simplifié ».http://www.guichet-entreprises.fr/http://www.guichet-entreprises.fr/(évitez le vieux site des URSSAF, qui fait la même chose en moins clair …j’ai passé 1h sur ce truc, qui n’a pas fonctionné au final)3. La paperasse à conserverTOUT est à conserver !http://www.insee.fr/fr/service/default.asp?page=entreprises/sirene/immatriculation.htmComme l’explique l’INSEE ici http://www.insee.fr/fr/service/default.asp?page=entreprises/sirene/immatriculation.htm, il va se passer ça en environ 1 semaine. Au delà, contactez-les.Vous allez recevoir dans l’ordre :  inscription INSEE (SIREN et SIRET, 1 semaine)  immatriculation RSI (SECU, 1 mois)  immatriculation URSSAF (SECU, 1 mois) …mais parfois non  identifiants RAM (Retraite, 2 mois)Exemple : allez faire un tour sur le net pour vérifier votre société.https://www.infogreffe.fr/societes/entreprise-societe/804913630-fremont-damien-80491363000013.htmlhttps://www.infogreffe.fr/societes/entreprise-societe/804913630-fremont-damien-80491363000013.html4. La paperasse à faire de suite : assurance pro, impôts, AGAResponsabilité Civile ProfessionnelleVous devez souscrire immédiatement à une assurance pro (Responsabilité Civile Professionnelle). Les SSII et les clients vont vous la demander, autant qu’elle soit prête pour commencer la mission. Attention à bien choisir Professionnel de l’informatique et un chiffre d’affaire proche du CA calculé précédemment.Exemple : j’ai pris une assurance pro chez Hiscox (pour la seule raison que je pouvais tout faire en ligne et avoir un prélèvement mensuel de suite).Cotisation CFE (impôts, 3 mois)C’est le bazar, d’autres l’expliquent mieux que moi.http://autoentrepreneurinfo.com/que-faire-avec-la-declaration-initiale-de-cfe-2014http://autoentrepreneurinfo.com/que-faire-avec-la-declaration-initiale-de-cfe-2014http://www.planete-auto-entrepreneur.com/autoentrepreneur/foire-aux-questions/2348-je-viens-de-creer-mon-auto-entreprise-jai-recu-un-formulaire-de-declaration-initiale-de-cfe-nd1447-c-est-ce-normal-comment-la-renseigner-.htmlhttp://www.planete-auto-entrepreneur.com/autoentrepreneur/foire-aux-questions/2348-je-viens-de-creer-mon-auto-entreprise-jai-recu-un-formulaire-de-declaration-initiale-de-cfe-nd1447-c-est-ce-normal-comment-la-renseigner-.htmlhttps://www.evoportail.fr/actualites/2013/12/19/declaration-cfe-2014-auto-entrepreneur/https://www.evoportail.fr/actualites/2013/12/19/declaration-cfe-2014-auto-entrepreneur/Souscrire à une AGA dans les premiers mois !!!  Votre inscription à titre individuel ou de groupement d’exercice doit être effectuée dans les dans les cinq mois du début d’activité,  l’adhésion s’effectue alors que vous exercer déjà votre activité, elle doit être réalisée au plus tard à la date 31 mai (31 mars antérieurement)Et le resteVous allez recevoir dans l’ordre et remplir (attention aux dates limites car parfois à la réception il ne reste que 15 jours) :  questionnaire DGFIP (impôts, 1 semaine)  cotisation URSSAF (SECU, 1 mois)  avis d’acompte TVA (impôts, 2 mois)5. La paperasse à faire plus tard : impôts  en ligne, mutuelle, carte vitale, prévoyanceImpôts en lignePensez à activer votre compte en ligne sur les impôts pour professionnels. En effet, la procédure est simple, mais il faut attendre de recevoir un code d’activation par courrier (1 semaine). A faire avant d’en avoir besoin donc.http://www.impots.gouv.fr/portal/static/pro/pro.htmlhttp://www.impots.gouv.fr/portal/static/pro/pro.htmlSouscrire à une mutuelleA choisir en fonction de vos besoins (on a pas les mêmes besoin à 25 ans en pleine santé qu’à 50 ans avec le dos, les yeux et les dents pourries). Si possible en loi Madelin, pour également la déduire des charges.Mettre à jour de votre carte vitaleEt oui, vous avez changé de SECU ! A faire en pharmacie, comme d’habitude sur les bornes dédiées.Prendre une prévoyance (facultatif)Et oui, vous n’avez pas d’arrêt maladie donc en cas de pépinExemple : j’ai pris le minimum, une mutuelle. On verra bien après si l’activité persiste pour prendre la prévoyance retraite (si mon activité persiste et si je choisis de ne pas la faire par capitalisation)ConclusionC’était la partie énervante du projet. La suite dans “Développeur freelance en 2015 : trouver une mission (2/3)”.Développeur freelance en 2015 : la routine, les missions (2/3)La suite ici Développeur freelance en 2015 : la routine, les missions (2/3).RéférencesDidier GiovanettiMerci à Didier Giovanetti pour ses conseils (dev freelance également).http://fr.viadeo.com/fr/profile/didier.giovanettihttp://fr.viadeo.com/fr/profile/didier.giovanettihttp://www.java-freelance.fr/freelance/bilan#more-479http://www.java-freelance.fr/freelance/bilan#more-479http://www.java-freelance.fr/freelance/comment-gagner-6000e-par-mois-en-etant-developpeurhttp://www.java-freelance.fr/freelance/comment-gagner-6000e-par-mois-en-etant-developpeurhttp://blog-du-consultant.fr/les-septs-galeres-du-consultant-independant/http://blog-du-consultant.fr/les-septs-galeres-du-consultant-independant/Originhttps://damienfremont.com/2015/03/16/developpeur-freelance-en-2015-se-lancer-13/",
        "url": "/2015/03/16/developpeur-freelance-en-2015-se-lancer-13"
      },
    
      "2015-03-13-android-google-apps-alternatives-gmail-gmap-gkeep-agenda-hangout": {
        "title": "Android Google Apps Alternatives Gmail Gmap Gkeep Agenda Hangout",
        "author": "",
        "category": "",
        "tags": "android",
        "content": "Sortir de Google c’est possible, ou au moins ne plus en dépendre directement sans pour autant fermer la porte à cet énorme (et pratique) écosystème Android. Cela devient parfois nécessaire, la faute étant du coté de Google qui fait des choix radicaux pour leur business, parfois au détriment des utilisateurs.Comme tous les ans, je repasse sous une distribution alternative quand mon téléphone du moment se fait trop vieux, et c’est l’occasion de remettre en question ce que l’on va (re)installer.On reste dans un usage classique avec messagerie, mail, photo, recherche, musique, news, carte, navigateur, calendrier, taches et sport.Avant / Après :SystèmeAndroid, stock ou constructeur, impose beaucoup de logiciels impossible à désinstaller sans être admin.Alternative : Cyanogen qui offre plus de personnalisation.MessagerieHangout écrase mes photo perso de contact par ceux des profils google+, rebascule tout le temps en mode hangout malgré un début de conversation en mode sms.Alternatives : Textra, Hello plus prévisibles mais ils se limitent aux sms.MailGmail était devenu un peu lent, et de moins en moins offline.Alternatives : CloudMagic, AquaMailPhotoCamera ne propose pas d’effets après la prise de photo.Alternatives : VSCO Cam, A Better Camera, Instagram offrent beaucoup, beaucoup plus pour avant et après la photo.RechercheGoogle était lent, et Now n’allait pas dans le sens de la simple recherche.Alternative : DuckDuckGo donne moins l’impression d’être espionné !MusiquePlayMusique ne gérait pas d’égaliseur de son.Alternative : PowerAmpNewsActu ne gérait pas de données offline, et l’interface n’était pas très intuitiveAlternative : FeedlyCarteMaps a supprimé les numéro de lignes de métro quand on clique sur un arrêt.Alternatives : Here, MappyNavigateurChrome était devenu gourmand et lent à faire le rendu.Alternatives : Lightning est très léger et rapide, Firefox propose la sync des mot de passe comme chrome.  CalendrierAgenda devient moins rapide à utiliser. La cause à une suppression qui doit passer par l’édition, un bouton ajouter qui recouvre les soirées de fin de semaine, un design pas très sexy du mode semaine (à la outlook).Alternatives : Cal, SunriseTachesKeep contient des bugs sur des anciennes taches archivées qui reviennent en premier plan.Alternative : Evernote qui permet aussi le partage entre desktop et mobile via leur appli web.SportFit est trop imprécis, et ne propose pas de lien avec les autres applis de suivi.Alternatives : RunKeeper, iMapMyRunConclusionL’an prochain, qui sait, ce sera peut-être un FireFox OS, Ubuntu (ou Windows Phone).Referenceshttp://www.engadget.com/2014/02/13/best-google-alternative-android-apps/http://www.greenbot.com/article/2365901/the-best-alternatives-to-stock-android-apps.htmlhttp://www.techradar.com/news/software/applications/getting-rid-of-google-best-replacement-apps-for-android-users-1265301",
        "url": "/2015/03/13/android-google-apps-alternatives-gmail-gmap-gkeep-agenda-hangout"
      },
    
      "2015-02-04-et-si-un-langage-de-programmation-etait-un-bateau": {
        "title": "Et Si Un Langage De Programmation Etait Un Bateau",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Aujourd’hui c’est vendredi, et comme tous les vendredis on se détend à l’approche du week-end. Ce post est une compilation – en français – autour du thème “If a programming language was a boat…”.JavaJava serait un cargo. Il est très grand, très Entreprise (Edition). Mais il peut aussi devenir très lourd. Fera l’affaire, mais pas très agréable à manœuvrer.PerlPerl serait un remorqueur. Suffisamment puissant pour remorquer Java, et ce en moins de 80 caractères.RubyRuby serait difficile à décrire. Il est élégant, sexy et très agréable à conduire.C / C++C serait un sous-marin nucléaire. Les instructions sont probablement écrites dans une langue étrangère, mais tout le matériel lui-même est optimisé pour la performance.AssembleurL’assembleur serait un sous-marin de sauvetage. Facile à comprendre, presque impossible à faire fonctionner …et si quelque chose va mal, quelqu’un aura de très gros ennuis.PHPPHP serait un radeau en bambou. Une série de hacks attachés par une ficelle, qui continue de se maintenir à flot malgré tout.JavaScriptJavaScript serait le Q-Boat de James Bond. Il est petit, mais puissant et il est vraiment facile de vous tuer en essayant de l’utiliser.HTML/XMLHTML/XML ne serait pas vraiment un langage de programmation bateau.C#C# serait un bateau de croisière. Élégant, beau et très confortable. Cependant pas très rapide, coûteux et d’une certaine manière limité.PythonPython serait un catamaran. Léger et fonctionnel, il brille par son “espacement”.BasicBasic serait un bateau gonflable. Du style que les enfants utilisent dans la piscine.SQLSQL serait un ferry-à-câble. Fournissant un échange entre deux côtes proches, en toute sécurité et efficacement.FortranFortran serait une frégate. Construite pour combattre les chiffres !Flash/ActionScriptFlash/ActionScript serait un navire en perdition. Il n’est plus fonctionnel, et tout le monde saute du bateau.SmalltalkSmallTalk serait un de ces vieux voiliers majestueux. C’est le langage de programmation parfait et le plus élégant jamais inventé, mais qui l’utilise encore?LispLisp serait un hydroptère. La première réaction de tout le monde serait “comment ça marche ??“. Ensuite après avoir baigné dans le “fonctionnel”, tous les autres bateaux vous semblerons bizarres et inefficaces.CobolCOBOL serait juste comme le Titanic. Énorme, conçu il y a très longtemps, peu adapté pour aujourd’hui. Mais les gens l’utilisent encore!Carte perforéeLa carte perforée serait un bateau en papyrus. Très très ancien, fait de fibre.WinDev (French Tech!)WinDev serait une voiture tuning amphibie. Un peu beauf sur les bords et pas très utile finalement.Referenceshttp://compsci.ca/blog/if-a-programming-language-was-a-boat/http://frexxx.soup.io/post/138322340/If-a-programming-language-was-a-boathttp://stillalivedeveloper.blogspot.fr/2011/10/if-programming-language-was-boat.html",
        "url": "/2015/02/04/et-si-un-langage-de-programmation-etait-un-bateau"
      },
    
      "2015-01-29-tests-bdd-avec-cucumber-java": {
        "title": "Tests Bdd Avec Cucumber Java",
        "author": "",
        "category": "",
        "tags": "bdd, cucumber, java, test",
        "content": "Ce tutorial explique comment écrire et coder des tests BDD (Behavior Driven Development) grâce à Cucumber pour Java, permettant des cas de test plus fonctionnels, maintenables par des MOA, afin de partager la responsabilité de la qualité et gagner en productivité.EnvironnementCucumber Java, c’est quoi ? C’est un outil qui permet de tester. Il automatise les tests d’acceptation par un formalise axé sur le style de développement BDD et sur un vocabulaire précis (Given, When, Then …Etant donnée, Quand, Alors …Arrange, Act, Assert).https://github.com/cucumber/cucumber/wiki/Feature-Introductionhttps://github.com/cucumber/cucumber/wiki/Feature-IntroductionLe besoin se situe entre le TDD/TU et le test d’acceptance, au coeur du fonctionnel.Installation de Cucumber…http://cukes.info/install-cucumber-jvm.htmlhttp://cukes.info/install-cucumber-jvm.htmlpom.xml (Maven)&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150129-test-cucumber_java&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;jdk.version&gt;1.7&lt;/jdk.version&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.assertj&lt;/groupId&gt;            &lt;artifactId&gt;assertj-core&lt;/artifactId&gt;            &lt;version&gt;1.7.1&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;         &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-junit&lt;/artifactId&gt;            &lt;version&gt;1.2.2&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;info.cukes&lt;/groupId&gt;            &lt;artifactId&gt;cucumber-java&lt;/artifactId&gt;            &lt;version&gt;1.2.2&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;…et du plugin eclipse pour la coloration syntaxique et le formatage de votre texte (optionnal)http://cukes.info/cucumber-eclipse/http://cukes.info/cucumber-eclipse/CodeLes tests vont porter sur un entrepôt de donnée (une simple DAO) autour de l’entité Personne.Les étapes décrites sur le site de Cucumber sont reprises ici, mais pour du Java et avec un peu plus de Français.http://cukes.info/http://cukes.info/1. Describe behaviour in plain textFeature: Entrepôt de données 'Personne'   # EXEMPLE SIMPLE  Scenario: Création    Given L'entrepôt contient N Personnes    When Je crée une Personne    Then J'obtiens l'ID de la Personne créée et l'entrepôt contient plus de N Personnes   # EXEMPLE SPECIFIQUE  Scenario: Suppression    Given L'entrepôt contient la Personnes Anakin Skywalker    When Je supprime la Personne 1    Then L'entrepôt contient moins de N Personnes   # EXEMPLE AVEC SUBSTITUTION (SCENARIO OUTLINES + EXAMPLES)  Scenario Outline: Lecture    Given L'entrepôt contient N Personnes    When Je recupère la Personne &lt;id&gt;    Then J'obtiens la Personne d'identifiant &lt;id&gt; contenant les données &lt;prenom&gt;, &lt;nom&gt;, &lt;naissance&gt;     Examples:      | id | prenom | nom         | naissance |      | 1  | Anakin | Skywalker   | 41.9 BBY  |      | 2  | Luke   | Skywalker   | 19 BBY    |      | 3  | Leia   | Organa Solo | 19 BBY    |   # EXEMPLE AVEC DATA TABLES  Scenario Outline: Modification    Given L'entrepôt contient les Personnes suivantes      | id | prenom | nom         | naissance |      | 3  | Leia   | Organa Solo | 19 BBY    |    When Je modifie la Personne &lt;id&gt; avec &lt;nom&gt;    Then J'obtiens la Personne d'identifiant &lt;id&gt; contenant les données &lt;prenom&gt;, &lt;nom&gt;, &lt;naissance&gt;     Examples:      | id | prenom | nom                   | naissance |      | 3  | Leia   | Organa Solo Skywalker | 19 BBY    |http://cukes.info/step-definitions.htmlPour les détails de syntaxe, voir le site officiel.http://cukes.info/step-definitions.html2. Write a step definition in JavaIl faut absolument s’aider du feedback console de Cucumber (sinon c’est fastidieux et on rate quelques subtilités sur les caractères à échapper dans les annotations @Given, @When, @Then).Pour cela il suffit de lancer vos scénarios et vous obtiendrez les squelettes de méthodes manquants.RunBDDTest.java (le lanceur de tests)@RunWith(Cucumber.class)public class RunBDDTest { }Sortie Console :6 Scenarios ([33m6 undefined[0m)18 Steps ([33m18 undefined[0m)0m0.000s You can implement missing steps with the snippets below: @Given(\"^L'entrepôt contient N Personnes$\")public void l_entrepôt_contient_N_Personnes() throws Throwable {    // Write code here that turns the phrase above into concrete actions    throw new PendingException();} @When(\"^Je crée une Personne$\")public void je_crée_une_Personne() throws Throwable {    // Write code here that turns the phrase above into concrete actions    throw new PendingException();} ...ATTENTION : le code généré n’est pas optimisé, surtout pour les tags .Avec un step écrit comme ceci…When Je modifie la Personne &lt;id&gt; avec &lt;nom&gt; Examples:  | numero | prenom | nom                   | dateDeNaissance |  | 2      | Luke   | Maitre Jedi Skywalker | 19 BBY          |  | 3      | Leia   | Organa Solo Skywalker | 19 BBY          |…et pour cela de généré…@When(\"^Je modifie la Personne (\\\\d+) avec Organa Solo Skywalker$\")public void je_modifie_la_Personne_avec_Organa_Solo_Skywalker(int arg1) throws Throwable {    // Write code here that turns the phrase above into concrete actions    throw new PendingException();} @When(\"^Je modifie la Personne (\\\\d+) avec Maitre Jedi Skywalker$\")public void je_modifie_la_Personne_avec_Maitre_Jedi_Skywalker(int arg1) throws Throwable {    // Write code here that turns the phrase above into concrete actions    throw new PendingException();}…il est possible de seulement écrire ça (réutilisable) :@When(\"^Je modifie la Personne (\\\\d+) avec (.*)$\")public void je_modifie_la_Personne_avec_(int id, String nom) throws Throwable {    // Write code here that turns the phrase above into concrete actions    throw new PendingException();}Ce qui donne au final StepDefinitions.javapublic class StepDefinitions {     // CE QUI EST A TESTER     private PersonRepository personRepositoryToTest = new PersonRepository();     // DONNEES COMMUNES ENTRE STEPS     private long givenPersonSize;    private PersonModel whenPersonId;    private PersonModel whenPerson;     // # EXEMPLE SIMPLE     @Given(\"^L'entrepôt contient N Personnes$\")    public void l_entrepôt_contient_N_Personnes() throws Throwable {        // L'entrepôt contient N Personnes        givenPersonSize = personRepositoryToTest.count();        assertThat(givenPersonSize).isPositive();    }     @When(\"^Je crée une Personne$\")    public void je_crée_une_Personne() throws Throwable {        // Je crée une Personne        PersonModel person = new PersonModel();        whenPersonId = personRepositoryToTest.create(person);    }     @Then(\"^J'obtiens l'ID de la Personne créée et l'entrepôt contient plus de N Personnes$\")    public void j_obtiens_l_ID_de_la_Personne_créée_et_l_entrepôt_contient_plus_de_N_Personnes()            throws Throwable {        // J'obtiens l'ID de la Personne créée        assertThat(whenPersonId).isNotNull();        // l'entrepôt contient N+X Personnes        long thenPersonCount = personRepositoryToTest.count();        assertThat(thenPersonCount).isGreaterThan(givenPersonSize);    }     // # EXEMPLE SPECIFIQUE AVEC ARGUMENTS     @Given(\"^L'entrepôt contient la Personnes Anakin Skywalker$\")    public void l_entrepôt_contient_la_Personnes_Anakin_Skywalker()            throws Throwable {        givenPersonSize = personRepositoryToTest.count();        // L'entrepôt contient la Personnes Anakin Skywalker        PersonModel p = personRepositoryToTest.read(1);        assertThat(p.getPrenom()).isEqualTo(\"Anakin\");    }     @When(\"^Je supprime la Personne (\\\\d+)$\")    public void je_supprime_la_Personne(int arg1) throws Throwable {        // Je supprime la Personne        personRepositoryToTest.delete(arg1);    }     @Then(\"^L'entrepôt contient moins de N Personnes$\")    public void l_entrepôt_contient_moins_de_N_Personnes() throws Throwable {        // L'entrepôt contient N-X Personnes        assertThat(personRepositoryToTest.count()).isLessThan(givenPersonSize);    }     // # EXEMPLE AVEC SUBSTITUTION (SCENARIO OUTLINES + EXAMPLES)     @When(\"^Je recupère la Personne (\\\\d+)$\")    public void je_recupère_la_Personne(int arg1) throws Throwable {        // Je recupère la Personne        whenPerson = personRepositoryToTest.read(arg1);    }     @Then(\"^J'obtiens la Personne d'identifiant (\\\\d+) contenant les données (.*), (.*), (.*)$\")    public void j_obtiens_la_Personne_d_identifiant_contenant_les_données(            int arg1, String prenom, String nom, String naissance)            throws Throwable {        // J'obtiens la Personne d'identifiant        assertThat(whenPerson).isNotNull();        assertThat(whenPerson.getId()).isEqualTo(arg1);        // avec les données        assertThat(whenPerson.getPrenom()).isEqualTo(prenom);        assertThat(whenPerson.getNom()).isEqualTo(nom);        assertThat(whenPerson.getNaissance()).isEqualTo(naissance);    }     // # EXEMPLE AVEC DATA TABLES     @Given(\"^L'entrepôt contient les Personnes suivantes$\")    public void l_entrepôt_contient_les_Personnes_suivantes(DataTable expected)            throws Throwable {        givenPersonSize = personRepositoryToTest.count();        // L'entrepôt contient les Personnes suivantes        List&lt;PersonModel&gt; actual = personRepositoryToTest.readAll();        for (final PersonModel exp : expected.asList(PersonModel.class)) {            assertThat(actual).haveExactly(1, new Condition&lt;PersonModel&gt;() {                 @Override                public boolean matches(PersonModel act) {                    return act.getId().equals(exp.getId()) //                            &amp;&amp; act.getPrenom().equals(exp.getPrenom()) //                            &amp;&amp; act.getNom().equals(exp.getNom()) //                            &amp;&amp; act.getNaissance().equals(exp.getNaissance());                }            });        }    }     @When(\"^Je modifie la Personne (\\\\d+) avec (.*)$\")    public void je_modifie_la_Personne_avec_(int id, String nom)            throws Throwable {        PersonModel p = personRepositoryToTest.read(id);        p.setNom(nom);        whenPerson = personRepositoryToTest.update(p);    } }3. Run and watch it failRunBDDTest.java (le lanceur de tests)@RunWith(Cucumber.class)public class RunBDDTest { }4. Write code to make the step passPersonModel.javapublic class PersonModel implements Serializable {     private static final long serialVersionUID = 6879685199191377814L;     private Integer id;    private String prenom;    private String nom;    private String naissance;     public PersonModel() {    }     public PersonModel(Integer id, String prenom, String nom, String naissance) {        super();        this.id = id;        this.prenom = prenom;        this.nom = nom;        this.naissance = naissance;    }     public Integer getId() {        return id;    }     public void setId(Integer id) {        this.id = id;    }     public String getPrenom() {        return prenom;    }     public void setPrenom(String prenom) {        this.prenom = prenom;    }     public String getNom() {        return nom;    }     public void setNom(String nom) {        this.nom = nom;    }     public String getNaissance() {        return naissance;    }     public void setNaissance(String naissance) {        this.naissance = naissance;    } }PersonRepository.javapublic class PersonRepository {     /* DATAS */     private static Map&lt;Integer, PersonModel&gt; datas = null;     public PersonRepository() {        datas = new HashMap&lt;&gt;();        datas.put(1, new PersonModel(1, \"Anakin\", \"Skywalker\", \"41.9 BBY\"));        datas.put(2, new PersonModel(2, \"Luke\", \"Skywalker\", \"19 BBY\"));        datas.put(3, new PersonModel(3, \"Leia\", \"Organa Solo\", \"19 BBY\"));    }     public long count() {        return datas.size();    }     /* CRUD METHODS */     public PersonModel create(PersonModel entity) {        int randomNum = new Random().nextInt();        entity.setId(randomNum);        datas.put(entity.getId(), entity);        return entity;    }     public PersonModel read(Integer id) {        return datas.get(id);    }     public List&lt;PersonModel&gt; readAll() {        return new ArrayList&lt;PersonModel&gt;(datas.values());    }     public PersonModel update(PersonModel entity) {        return datas.put(entity.getId(), entity);    }     public void delete(Integer id) {        datas.remove(id);    } }5. Run again and see the step pass6. Repeat 2-5 until green like a cuke(idem)ConclusionCucumber est un outils puissant, voir indispensable pour garantir une approche agile sur vos projet et leur bonne maintenance. Mais il faut garder à l’esprit que l’intérêt de ce genre de techno n’est clairement pas du coté des développeurs, mais des MOA. On n’écharpera pas aux commentaires du genre “c’est pas plus rapide à coder”, “ça me limite”.Les plus :  un document commun avec votre MOA, dont elle doit avoir la responsabilité  gros gain de productivité sur les tests des cas aux limites d’un scénario  analyse de la couverture de code par des plugins comme Emma qui fonctionne toujoursLes moins :  un peu laborieux car travail très manuel (peu de compilation) mais la productivité est au rendez-vous  Pas d’erreur si un step n’est pas trouvé, juste un skip du test.  Pour un projet qui bouge beaucoup, Cucumber-JS ou Ruby semblent plus indiqués (voir problème de duplication de code ci-dessous sur un langage compilé comme Java), même si cela oblige à manipuler 2 contextes d’exécution (JS + la techno de votre projet, Java par exemple).      Feedbacks un peu léger pour les débutants sur les erreurs de syntax dans un fichier feature. Et le plugin Cucumber-Eclipse n’apporte rien de plus à ce niveau là.    Par contre le pendant Cucumber-Java est lourd à utiliser car il implique de la duplication de code par rapport à Cucumber-JS lors de l’étape de définition des steps.Cucumber-Java (il faut taper un nom de méthode en plus)@Given(\"^I have entered (.*) into the calculator$\")public void i_have_entered_into_the_calculator() throws Throwable {// express the regexp above with the code you wish you had}Cucumber-JSGiven( /^I have entered (.*) into the calculator$/, function(callback) {// express the regexp above with the code you wish you hadcallback.pending();});Cucumber-RUBYGiven /^I have entered (.*) into the calculator$/ do |arg1|pending # express the regexp above with the code you wish you hadendAttention, ce genre de test n’est pas fait pour des tests unitaires de briques logiciels. A privilégier plutôt pour des suites de tests fonctionnels, à rédiger en binôme avec vos responsables fonctionnels / MOA / PO.Pour aller plus loinIl faudrait ajouter du reporting plus propre pour la MOA avec Maven Surefire Report Plugin ou une page de rapport de server de build type Bamboo ou Jenkins.Et un éditeur tel que Gherkin ou sa version collaborative pour permettre à des non-devs d’écrirent ces scénarios.https://github.com/cucumber/gherkin-editorhttps://github.com/cucumber/gherkin-editorSourcehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150129-test-cucumber_javahttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150129-test-cucumber_javaReferenceshttp://cukes.info/http://cukes.info/http://cukes.info/install-cucumber-jvm.htmlhttp://cukes.info/install-cucumber-jvm.htmlhttp://cukes.info/step-definitions.htmlhttp://cukes.info/step-definitions.htmlhttp://www.goodercode.com/wp/using-cucumber-tests-with-maven-and-java/http://www.goodercode.com/wp/using-cucumber-tests-with-maven-and-java/https://thomassundberg.wordpress.com/2014/05/29/cucumber-jvm-hello-world/https://thomassundberg.wordpress.com/2014/05/29/cucumber-jvm-hello-world/http://cukes.info/cucumber-eclipse/http://cukes.info/cucumber-eclipse/Originhttps://damienfremont.com/2015/01/29/tests-bdd-avec-cucumber-java/",
        "url": "/2015/01/29/tests-bdd-avec-cucumber-java"
      },
    
      "2015-01-25-test-web-ui-automatise-avec-fluentlenium-java": {
        "title": "Test Web Ui Automatise Avec Fluentlenium Java",
        "author": "",
        "category": "",
        "tags": "java, selenium, test",
        "content": "Tester une webapp avec Selenium Java, PhantomJS et un webserver embarqué ?Ce tuto permet de tester une interface web de façon rapide et maintenable en utilisant Fluentlenium avec les classiques JUnit, Selenium et FestAssert. C’est une version améliorée du tuto Tester une webapp avec Selenium Java, PhantomJS et un webserver embarqué ?Environnement“FluentLenium is a framework that helps you to write Selenium tests. FluentLenium provides you afluent interface to the Selenium Web Driver. FluentLenium lets you use the assertion framework you like, either jUnit assertions, Hamcrest or AssertJ” source : https://github.com/FluentLenium/FluentLeniumCodeUn test s’écrit très facilement. Le formalisme se prête même au TDD.WebUITest.java (1/2) : tests...    // TESTS **********************     @Test    public void test_QUAND_acces_site_ETANT_DONNE_main_page_ALORS_afficher_main_page() {         // QUAND        goTo(baseUrl);         // ALORS        assertThat(mainPage).isAt();         assertThat(mainPage.title).isDisplayed().hasText(\"Main page\");        assertThat(mainPage.goToPage1Btn).isDisplayed();        assertThat(mainPage.goToPage2Btn).isDisplayed();    }     @Test    public void test_QUAND_navigue_vers_page_1_ETANT_DONNE_main_page_ALORS_afficher_page_1() {         // ETANT DONNE        goTo(mainPage);        assertThat(mainPage).isAt();         // QUAND        mainPage.goToPage1Btn.click();         // ALORS        assertThat(page1).isAt();        assertThat(page1.title).isDisplayed().hasText(\"Page 1\");        assertThat(page1.backBtn).isDisplayed().hasText(\"Return\");    }     @Test    public void test_QUAND_navigue_vers_page_2_ETANT_DONNE_page_2_cassee_ALORS_erreur_404() {         // ETANT DONNE        goTo(mainPage);        assertThat(mainPage).isAt();         // QUAND        mainPage.goToPage2Btn.click();         // ALORS        Assertions.assertThat(find(\"body\").getText()).contains(\"404\");    }}Mais avant de coder les tests, il faut pas mal d’init et de config.Il faut penser à inclure les imports en tête des fichiers source. Attention à la résolution auto des imports de votre IDE.import static org.fluentlenium.core.filter.FilterConstructor.*;import static org.assertj.core.api.Assertions.assertThat;import static org.fluentlenium.assertj.FluentLeniumAssertions.assertThat;Il faut également initialiser le web-server, le navigateur et son driver ainsi que FluentLenium.WebUITest.java (2/2) : init, toolspublic class WebUITest extends FluentTest {     static EmbeddedServer server;    static WebDriver driver;    static String baseUrl;     // SELENIUM INIT **************     @BeforeClass    public static void startServer() throws ServletException {         // INIT WEB SERVER (TOMCAT)        server = new EmbeddedServer(8080, \"/20150125-test-fluentlenium\");        server.start();    }     @AfterClass    public static void stopServer() {        server.stop();        driver.quit();    }     // FLUENTLENIUM INIT **********     // Override of this method to change the driver    @Override    public WebDriver getDefaultDriver() {         // INIT WEB BROWSER (SELENIUM + PHANTOMJS)        driver = new PhantomJSDriver(new DesiredCapabilities(ImmutableMap.of( //                PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, //                new PhantomJsDownloader().downloadAndExtract()                        .getAbsolutePath())));        baseUrl = \"http://localhost:8080/20150125-test-fluentlenium\";        driver.manage().timeouts().implicitlyWait(5, SECONDS);         return driver;    }     @Page    MainPage mainPage;     @Page    MainPage1 page1;...La dernière étape consiste à coder en PagePattern (une page web / écran = une classe, héritant de FluentPage). Visuellement, ces classes Java “ressembleront de loin” dans la forme à vos pages web testées (avec un peu de code utilitaire à coté).Ainsi, la 1ere page du site……donne MainPage.java// PAGE PATTERN DE LA PAGE PRINCIPALEpublic class MainPage extends FluentPage {     // FLUENTLENIUM UTILS     @Override    public String getUrl() {        return \"http://localhost:8080/20150125-test-fluentlenium/\";    }     @Override    public void isAt() {        FluentLeniumAssertions.assertThat(title).hasText(\"Main page\");    }     // WEB ELEMENT (text, href, etc)     @FindBy(css = \".container .title\")    FluentWebElement title;     @FindBy(css = \".container li:nth-child(1) .goto.btn\")    FluentWebElement goToPage1Btn;     @FindBy(css = \".container li:nth-child(2) .goto.btn\")    FluentWebElement goToPage2Btn; }Et la seconde page……donne MainPage1.java// PAGE PATTERN DE LA PAGE 1public class MainPage1 extends FluentPage {     @Override    public String getUrl() {        return \"http://localhost:8080/20150125-test-fluentlenium/page1.html\";    }     @Override    public void isAt() {        FluentLeniumAssertions.assertThat(title).hasText(\"Page 1\");    }     @FindBy(css = \".container .title\")    FluentWebElement title;     @FindBy(css = \".container .back.btn\")    FluentWebElement backBtn; }Ce qui donne le projet Java suivant.pom.xml config Maven&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150125-test-fluentlenium&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;war&lt;/packaging&gt;    &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;jdk.version&gt;1.7&lt;/jdk.version&gt;        &lt;tomcat-version&gt;8.0.15&lt;/tomcat-version&gt;        &lt;fluentlenium.version&gt;0.10.3&lt;/fluentlenium.version&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;!-- TEST --&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.11&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.fluentlenium&lt;/groupId&gt;            &lt;artifactId&gt;fluentlenium-core&lt;/artifactId&gt;            &lt;version&gt;${fluentlenium.version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.fluentlenium&lt;/groupId&gt;            &lt;artifactId&gt;fluentlenium-assertj&lt;/artifactId&gt;            &lt;version&gt;${fluentlenium.version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;         &lt;!-- TEST: EMBEDDED PHANTOMJS WEBBROWSER --&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.codeborne&lt;/groupId&gt;            &lt;artifactId&gt;phantomjsdriver&lt;/artifactId&gt;            &lt;version&gt;1.2.1&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.google.guava&lt;/groupId&gt;            &lt;artifactId&gt;guava&lt;/artifactId&gt;            &lt;version&gt;14.0.1&lt;/version&gt;        &lt;/dependency&gt;         &lt;!-- TEST : EMBEDDED TOMCAT SERVER --&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-core&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-logging-juli&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jasper&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jasper-el&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jsp-api&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;DemoComme pour des tests unitaires, il suffit de lancer les tests du projet ou de la classe WebUITest.java.En effet, tout est embarqué DANS le test JUnit :  server : Tomcat  (pour tester dans une usine de dev, un Jenkins, etc)  navigateur web : PhantomJSLe comportement est également le même qu’un test unitaire, avec son rapport.ConclusionFluentLenium aide beaucoup pour la réalisation de tests UI/IHM :  approche plus productive (moins de code boilerplate, moins d’erreurs)  introduit des bonnes pratiques (page pattern, assertions, séparation du code)  rend possible l’approche TDD (formalisme que prennent les tests)Pour aller plus loin, il est possible d’industrialiser l’initialisation des classes de test (avec un super objet contenant webdriver, init du server, une politique de login, du processus contenant le browser)Source codehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150125-test-fluentleniumhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150125-test-fluentleniumReferenceshttps://github.com/FluentLenium/FluentLeniumhttps://github.com/FluentLenium/FluentLeniumOriginhttps://damienfremont.com/2015/01/25/test-web-ui-automatise-avec-fluentlenium-java/",
        "url": "/2015/01/25/test-web-ui-automatise-avec-fluentlenium-java"
      },
    
      "2015-01-20-creer-et-tester-un-client-http-rest-en-jax-rs-javaee-avec-jersey": {
        "title": "Creer Et Tester Un Client Http Rest En Jax Rs Javaee Avec Jersey",
        "author": "",
        "category": "",
        "tags": "java, rest, test",
        "content": "Voici comment créer un client HTTP REST en Java appelant un simple service CRUD. La solution se base sur le standard JavaEE JAX-RS avec comme implémentation Jersey-client pour le mapping et RESTEasy pour l’exécution, testé par JUnit et Jadler qui émule un server REST.EnvironnementLe client va appeler un service REST dont l’API est la suivante :Sourcepom.xml (config Maven)&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150117-javaee-jersey_client&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;jar&lt;/packaging&gt;    &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;jdk.version&gt;1.7&lt;/jdk.version&gt;        &lt;jersey.version&gt;1.18.3&lt;/jersey.version&gt;        &lt;resteasy.version&gt;2.3.1.GA&lt;/resteasy.version&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;!-- JERSEY CLIENT --&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-json&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-client&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.jboss.resteasy&lt;/groupId&gt;            &lt;artifactId&gt;resteasy-jaxrs&lt;/artifactId&gt;            &lt;version&gt;${resteasy.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.jboss.resteasy&lt;/groupId&gt;            &lt;artifactId&gt;resteasy-jettison-provider&lt;/artifactId&gt;            &lt;version&gt;${resteasy.version}&lt;/version&gt;        &lt;/dependency&gt;         &lt;!-- TEST --&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.9&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.easytesting&lt;/groupId&gt;            &lt;artifactId&gt;fest-assert-core&lt;/artifactId&gt;            &lt;version&gt;2.0M5&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;net.jadler&lt;/groupId&gt;            &lt;artifactId&gt;jadler-all&lt;/artifactId&gt;            &lt;version&gt;1.1.1&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.hamcrest&lt;/groupId&gt;            &lt;artifactId&gt;hamcrest-core&lt;/artifactId&gt;            &lt;version&gt;1.3&lt;/version&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.2&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;PersonModel.java (un simple POJO, annoté en JAX-RS )@XmlRootElement(name=\"person\")@JsonIgnoreProperties(ignoreUnknown = true)public class PersonModel implements Serializable {     private static final long serialVersionUID = 6879685199191377814L;     private Integer id;    private String firstName;    private String lastName;    private String birthDate;     public Integer getId() {        return id;    }     public void setId(Integer id) {        this.id = id;    }     public String getFirstName() {        return firstName;    }     public void setFirstName(String firstName) {        this.firstName = firstName;    }     public String getLastName() {        return lastName;    }     public void setLastName(String lastName) {        this.lastName = lastName;    }     public String getBirthDate() {        return birthDate;    }     public void setBirthDate(String birthDate) {        this.birthDate = birthDate;    } }Personservice.java (une simple interface décrivant l’API, annotée en JAX-RS aussi)@Path(\"persons\")public interface PersonService {     @GET    public void ping();     @POST    @Consumes(MediaType.APPLICATION_JSON)    public String createPerson(PersonModel newPerson);     @GET    @Path(\"id/{id}\")    @Produces(MediaType.APPLICATION_JSON)    public PersonModel readPerson(@PathParam(\"id\") Integer id);     @POST    @Path(\"id/{id}\")    @Consumes(MediaType.APPLICATION_JSON)    public String updatePerson(@PathParam(\"id\") Integer id, PersonModel actualPerson);     @DELETE    @Path(\"id/{id}\")    public void deletePerson(@PathParam(\"id\") Integer id);}DemoPour commencer, voici un test de connexion de notre client vers l’API en émulant un server HTTP REST avec Jadler.PersonClientTest .javapublic class PersonClientTest {     PersonService client;     @Before    public void setUp() {        // INIT MOCK        initJadler();        // INIT REST CLIENT        client = ProxyFactory.create(//                PersonService.class, //                \"http://localhost:\" + Jadler.port() + \"/api\");    }     @After    public void tearDown() {        closeJadler();    }     @Test    public void test_QUAND_create_person_ETANT_DONNE_new_ALORS_success() {         // ETANT DONNE        onRequest().havingMethodEqualTo(\"POST\")                .havingPathEqualTo(\"/api/persons\").respond()                .withBody(\"Location: /persons/id/6\") //                .withEncoding(Charset.forName(\"UTF-8\")) //                .withContentType(\"text/plain; charset=UTF-8\") //                .withStatus(204);         PersonModel newPerson = new PersonModel();        newPerson.setFirstName(\"Luke\");        newPerson.setLastName(\"Skylwalker\");        newPerson.setBirthDate(\"19 BBY\");         // QUAND        client.createPerson(newPerson);         // ALORS        // nothing to assert    }     @Test    public void test_QUAND_get_person_ETANT_DONNE_id_valid_ALORS_success() {         // ETANT DONNE        onRequest()                .havingMethodEqualTo(\"GET\")                .havingPathEqualTo(\"/api/persons/id/1\")                .respond()                .withBody(                        \"{person:{\" //                                + \"\\\"id\\\":\\\"1\\\",\"                                + \"\\\"firstName\\\":\\\"Anakin\\\",\"                                + \"\\\"lastName\\\":\\\"Skylwalker\\\",\"                                + \"\\\"birthDate\\\":\\\"41.9 BBY\\\"\" //                                + \"}}\") //                .withEncoding(Charset.forName(\"UTF-8\")) //                .withContentType(\"application/json; charset=UTF-8\") //                .withStatus(200);         Integer arg = 1;         // QUAND        PersonModel response = client.readPerson(arg);         // ALORS        assertThat(response).isNotNull();        assertThat(response.getId()).isNotNull();        assertThat(response.getFirstName()).isEqualTo(\"Anakin\");        assertThat(response.getLastName()).isEqualTo(\"Skylwalker\");        assertThat(response.getBirthDate()).isEqualTo(\"41.9 BBY\");    }     @Test    public void test_QUAND_post_person_ETANT_DONNE_person_exists_ALORS_success() {         // ETANT DONNE        onRequest()                .havingMethodEqualTo(\"POST\")                .havingPathEqualTo(\"/api/persons/id/1\")                .respond()                .withStatus(200);         Integer arg = 1;        PersonModel newPerson = new PersonModel();        newPerson.setId(1);        newPerson.setFirstName(\"Anakin\");        newPerson.setLastName(\"Skylwalker\");        newPerson.setBirthDate(\"41.9 BBY\");         // QUAND        client.updatePerson(arg, newPerson);         // ALORS        // nothing to assert    }     @Test    public void test_QUAND_delete_person_ETANT_DONNE_person_exists_ALORS_success() {         // ETANT DONNE        onRequest()                .havingMethodEqualTo(\"DELETE\")                .havingPathEqualTo(\"/api/persons/id/1\")                .respond()                .withStatus(200);         Integer arg = 1;         // QUAND        client.deletePerson(arg);         // ALORS        // nothing to assert    }}C’est donc un test d’intégration du client que l’on peut lancer comme un simple test JUnit.AméliorationIl est recommandé de configurer les TimeOuts sur votre client JAX-RS, pour éviter de bloquer votre application (ou un de vos threads si c’est un server).Executor.javapublic class Executor extends ApacheHttpClient4Executor{     private static final int    connectionTimeoutMillis = 2000;    private static final int    socketTimeoutMillis = 3000;     public Executor()    {        super( initHttpClient() );    }     private static DefaultHttpClient initHttpClient()    {        DefaultHttpClient httpClient = new DefaultHttpClient();        HttpParams params = httpClient.getParams();        HttpConnectionParams.setConnectionTimeout( params, connectionTimeoutMillis );        HttpConnectionParams.setSoTimeout( params, socketTimeoutMillis );        return httpClient;    }}Qui peut aussi se tester avec Jadler.ExecutorTest.javapublic class ExecutorTest {     PersonService client;     @Before    public void setUp() {        // INIT MOCK        initJadler();        // INIT REST CLIENT        client = ProxyFactory.create(//                PersonService.class, //                \"http://localhost:\" + Jadler.port() + \"/api\", new Executor());    }     @After    public void tearDown() {        closeJadler();    }     @Test    public void test_QUAND_ping_ETANT_DONNE_system_ok_ALORS_success() {         // ETANT DONNE        onRequest().havingMethodEqualTo(\"GET\")                .havingPathEqualTo(\"/api/persons\").respond()                .withDelay(1, SECONDS);         // QUAND        client.ping();    }     @Test    public void test_QUAND_ping_ETANT_DONNE_system_lag_ALORS_timeout() {         // ETANT DONNE        onRequest().havingMethodEqualTo(\"GET\")                .havingPathEqualTo(\"/api/persons\").respond()                .withDelay(50, SECONDS);         // QUAND        try {            client.ping();            fail(\"Expected Exception!\");        } catch (Exception e) {             // ALORS            assertThat(e.getMessage()).contains(\"Read timed out\");        }    } }ConclusionPour une fois, pas de réelle contre-partie :  Le client est facile à coder car il n’y a même pas d’implémentation.  Les tests sont auto-documentés et automatisé (indépendants, répétables, non-régression, etc).Le plus intéressant étant que la maintenance en est grandement simplifié …le source ne contenant que du code “métier” (pas de code boilerplate) et le comportement est testé.Source codehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150120-javaee-jersey_clienthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150120-javaee-jersey_clientReferenceshttp://www.mkyong.com/tutorials/jax-rs-tutorials/http://www.mkyong.com/tutorials/jax-rs-tutorials/http://www.mastertheboss.com/jboss-frameworks/resteasy/resteasy-tutorialhttp://www.mastertheboss.com/jboss-frameworks/resteasy/resteasy-tutorialOriginhttps://damienfremont.com/2015/01/20/creer-et-tester-un-client-http-rest-en-jax-rs-javaee-avec-jersey",
        "url": "/2015/01/20/creer-et-tester-un-client-http-rest-en-jax-rs-javaee-avec-jersey"
      },
    
      "2015-01-18-tester-une-webapp-avec-selenium-java-phantomjs-et-un-webserver-embarque": {
        "title": "Tester Une Webapp Avec Selenium Java Phantomjs Et Un Webserver Embarque",
        "author": "",
        "category": "",
        "tags": "java, junit, selenium, test",
        "content": "Vous avez besoin de tester en permanence votre webapp ? Mais ne disposez pas d’une infrastructure de test (preprod) ni d’une équipe de testeurs humains ? Ou vous aimeriez tester le front avec le même confort qu’un test unitaire. Ce tuto permet de lancer un mini environnement navigateur+webserver via JUnit et de tester votre interface web.EnvironnementLes outils utilisés sont JUnit, Selenium et un environnement de base navigateur (Phantomjs) / server web (Tomcat).Ici, le test lancé avec JUnit utilise Selenium. Selenium qui se connecte via un webdriver au navigateur web. Le navigateur web (phantomjs) envoie des requêtes au serveur web (tomcat).Pourquoi PhantomJS ? Il y a plusieurs bonnes raisons :  Indépendance : parce que l’on veux, comme toujours, des tests indépendants du système sur lequel ils sont exécutés. PhantomJS sera un navigateur téléchargé par le projet (même logique que Maven et les libs Java).  Stabilité : téléchargé dans une version précise, il n’y a pas dépendance à une quelconque version installée (firefox v35, chrome v53, etc). Car oui, certains navigateurs comportent des bugs dans webdriver d’une version à l’autre.  Rapidité : PhantomJS est un navigateur dit “headless” car il n’a pas d’interface graphique. Il est donc très léger et rapide.Les tests UI s’exécutent ainsi avec le même niveau de confort qu’un test unitaire, automatisé et indépendant de toute intervention extérieure.Pour ces tests, de simples pages web avec quelques liens suffisent.Main pagePage 1Page 2 (une 404, pour tester une erreur)Code&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150118-test-selenium&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;war&lt;/packaging&gt;    &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;jdk.version&gt;1.7&lt;/jdk.version&gt;        &lt;tomcat-version&gt;8.0.15&lt;/tomcat-version&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;!-- TEST --&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.11&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.seleniumhq.selenium&lt;/groupId&gt;            &lt;artifactId&gt;selenium-java&lt;/artifactId&gt;            &lt;version&gt;2.44.0&lt;/version&gt;        &lt;/dependency&gt;                 &lt;!-- TEST: EMBEDDED PHANTOMJS WEBBROWSER --&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.codeborne&lt;/groupId&gt;            &lt;artifactId&gt;phantomjsdriver&lt;/artifactId&gt;            &lt;version&gt;1.2.1&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.google.guava&lt;/groupId&gt;            &lt;artifactId&gt;guava&lt;/artifactId&gt;            &lt;version&gt;14.0.1&lt;/version&gt;        &lt;/dependency&gt;                 &lt;!-- TEST : EMBEDDED TOMCAT SERVER --&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-core&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-logging-juli&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jasper&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jasper-el&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jsp-api&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.2&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;WebUITest.java 1/2 : la partie utilitairepublic class WebUITest {     private static EmbeddedServer server;    private static WebDriver driver;    private static String baseUrl;     @BeforeClass    public static void startServer() throws ServletException {         // INIT WEB SERVER (TOMCAT)        server = new EmbeddedServer(8080, \"/20150118-test-selenium\");        server.start();         // INIT WEB BROWSER (SELENIUM + PHANTOMJS)        driver = new PhantomJSDriver(        new DesiredCapabilities(ImmutableMap.of( //                PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, //                new PhantomJsDownloader().downloadAndExtract()                        .getAbsolutePath())));        baseUrl = \"http://localhost:8080/20150118-test-selenium\";        driver.manage().timeouts().implicitlyWait(5, SECONDS);    }     @AfterClass    public static void stopServer() {        server.stop();        driver.quit();    }...WebUITest.java 2/2 : les testsLes tests fonctionnent à base de sélection d’élèments dans le DOM de la page web. Du coup, il faut utiliser à font les cssSelector pour sélectionner (ID, c’est dépassé ne pas les utiliser évite de les maintenir et redonne du sens à votre structure html). Un cssSelector, c’est tout simplement la règle css qui décrit comment sélectionner un élément dans le DOM (comme “#container h1” dans un fichier *.css pour appliquer une couleur). Heureusement, pour écrire ces formules quand on est pas un pro du CSS, il y a les outils.Exemple en utilisant le plugin de dev de votre navigateur (Chrome ici)Autour de ces sélection d’éléments, Selenium propose des méthodes pour intéragir avec. Il y a des click(), des isDisplayed(), text(), etc.Les tests nous donne donc :...     @Test    public void test_QUAND_acces_site_ETANT_DONNE_main_page_ALORS_afficher_main_page() {         // QUAND        driver.get(baseUrl);         // ALORS        assertTrue(driver.findElement(By.cssSelector(\".container .title\"))                .isDisplayed());        assertTrue(driver.findElement(By.cssSelector(\".container .title\"))                .getText().contains(\"Main page\"));        assertTrue(driver.findElement(                By.cssSelector(\".container li:nth-child(1) .goto.btn\"))                .isDisplayed());        assertTrue(driver.findElement(                By.cssSelector(\".container li:nth-child(2) .goto.btn\"))                .isDisplayed());    }     @Test    public void test_QUAND_navigue_vers_page_1_ETANT_DONNE_main_page_ALORS_afficher_page_1() {         // ETANT DONNE        driver.get(baseUrl);        assertTrue(driver.findElement(By.cssSelector(\".container .title\"))                .getText().contains(\"Main page\"));         // QUAND        driver.findElement(                By.cssSelector(\".container li:nth-child(1) .goto.btn\")).click();         // ALORS        assertTrue(driver.getCurrentUrl().contains(\"page1\"));         assertTrue(driver.findElement(By.cssSelector(\".container .title\"))                .isDisplayed());        assertTrue(driver.findElement(By.cssSelector(\".container .title\"))                .getText().contains(\"Page 1\"));    }     @Test    public void test_QUAND_navigue_vers_page_2_ETANT_DONNE_page_2_cassee_ALORS_erreur_404() {         // ETANT DONNE        driver.get(baseUrl);        assertTrue(driver.findElement(By.cssSelector(\".container .title\"))                .getText().contains(\"Main page\"));         // QUAND        driver.findElement(                By.cssSelector(\".container li:nth-child(2) .goto.btn\")).click();         // ALORS        assertTrue(driver.getCurrentUrl().contains(\"page2\"));        assertTrue(driver.findElement(By.cssSelector(\"body\"))                .getText().contains(\"404\"));    } }PhantomJs n’étant pas disponible dans Maven, il faut le faire télécharger par le test JUnit (ça reste mieux que de le versionner dans votre projet sous GIT ou SVN). Un utilitaire est dispo sur le net : PhantomJsDownloaderclass PhantomJsDownloader {     private final boolean isWindows;    private final boolean isMac;    private final boolean isLinux64;     PhantomJsDownloader() {        String osName = System.getProperty(\"os.name\");        isWindows = osName.startsWith(\"Windows\");        isMac = osName.startsWith(\"Mac OS X\") || osName.startsWith(\"Darwin\");        isLinux64 = System.getProperty(\"sun.arch.data.model\").equals(\"64\");    }     public File downloadAndExtract() {        File installDir = new File(\".phantomjstest\");        String url;        File phantomJsExe;        if (isWindows) {            url = \"http://phantomjs.googlecode.com/files/phantomjs-1.9.2-windows.zip\";            phantomJsExe = new File(installDir,                    \"phantomjs-1.9.2-windows/phantomjs.exe\");        } else if (isMac) {            url = \"http://phantomjs.googlecode.com/files/phantomjs-1.9.2-macosx.zip\";            phantomJsExe = new File(installDir,                    \"phantomjs-1.9.2-macosx/bin/phantomjs\");        } else if (isLinux64) {            url = \"http://phantomjs.googlecode.com/files/phantomjs-1.9.2-linux-x86_64.tar.bz2\";            phantomJsExe = new File(installDir,                    \"phantomjs-1.9.2-linux-x86_64/bin/phantomjs\");        } else {            url = \"http://phantomjs.googlecode.com/files/phantomjs-1.9.2-linux-i686.tar.bz2\";            phantomJsExe = new File(installDir,                    \"phantomjs-1.9.2-linux-i686/bin/phantomjs\");        }        extractExe(url, installDir, phantomJsExe);        return phantomJsExe;    }     private void extractExe(String url, File phantomInstallDir,            File phantomJsExe) {        if (phantomJsExe.exists()) {            return;        }        File targetZip = new File(phantomInstallDir, \"phantomjs.zip\");        downloadZip(url, targetZip);        try {            if (isWindows) {                unzip(targetZip, phantomInstallDir);            } else if (isMac) {                new ProcessBuilder()                        .command(\"/usr/bin/unzip\", \"-qo\", \"phantomjs.zip\")                        .directory(phantomInstallDir).start().waitFor();            } else {                new ProcessBuilder().command(\"tar\", \"-xjvf\", \"phantomjs.zip\")                        .directory(phantomInstallDir).start().waitFor();            }        } catch (Exception e) {            throw new IllegalStateException(\"Unable to unzip phantomjs from \"                    + targetZip.getAbsolutePath());        }    }     private void downloadZip(String url, File targetZip) {        if (targetZip.exists()) {            return;        }        File zipTemp = new File(targetZip.getAbsolutePath() + \".temp\");        try {            zipTemp.getParentFile().mkdirs();            InputSupplier&lt;InputStream&gt; input = Resources                    .newInputStreamSupplier(URI.create(url).toURL());            OutputSupplier&lt;FileOutputStream&gt; ouput = Files                    .newOutputStreamSupplier(zipTemp);            ByteStreams.copy(input, ouput);        } catch (IOException e) {            String message = \"Unable to download phantomjs from \" + url;            throw new IllegalStateException(message, e);        }        zipTemp.renameTo(targetZip);    }     private static void unzip(File zip, File toDir) throws IOException {        try (final ZipFile zipFile = new ZipFile(zip);) {            Enumeration&lt;? extends ZipEntry&gt; entries = zipFile.entries();            while (entries.hasMoreElements()) {                final ZipEntry entry = entries.nextElement();                if (entry.isDirectory()) {                    continue;                }                File to = new File(toDir, entry.getName());                to.getParentFile().mkdirs();                InputSupplier&lt;InputStream&gt; from = new InputSupplier&lt;InputStream&gt;() {                    public InputStream getInput() throws IOException {                        return zipFile.getInputStream(entry);                    }                };                Files.copy(from, to);            }        }    }}http://grepcode.com/file/repo1.maven.org/maven2/net.code-story/simplelenium/1.21/net/codestory/simplelenium/driver/PhantomJsDownloader.javahttp://grepcode.com/file/repo1.maven.org/maven2/net.code-story/simplelenium/1.21/net/codestory/simplelenium/driver/PhantomJsDownloader.javaDemoIl y a 2 façons de procéder selon le besoin.1. Utiliser le server tomcat embarqué dans les tests (pour tester dans une usine de dev, un Jenkins, etc)…le plus simple, il suffit de lancer les tests du projet ou de la classe WebUITest.2. Tester un server externe au test (pour tester vers le poste local, la preprod, etc)…le moins simple, qui méritera une fonction de configuration / paramétrage si utilisé régulièrement (config de l’URL du server, login, password, etc)Il faut désactiver le Tomcat embarqué avant de lancer les tests.public class WebUITest { //  private static EmbeddedServer server;    private static WebDriver driver;    private static String baseUrl;     @BeforeClass    public static void startServer() throws ServletException {         // INIT WEB SERVER (TOMCAT)//      server = new EmbeddedServer(8080, \"/20150118-test-selenium\");//      server.start();         // INIT WEB BROWSER (SELENIUM + PHANTOMJS)        driver = new PhantomJSDriver(        new DesiredCapabilities(ImmutableMap.of( //                PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY, //                new PhantomJsDownloader().downloadAndExtract()                        .getAbsolutePath())));// URL A CHANGER SI BESOIN        baseUrl = \"http://localhost:8080/20150118-test-selenium\";        driver.manage().timeouts().implicitlyWait(5, SECONDS);    }     @AfterClass    public static void stopServer() {//      server.stop();        driver.quit();    }Puis lancer votre propre server si besoin, puis les tests.Dans les 2 cas, c’est la suite JUnit qui montrera le résultat.ConclusionCe type de test est très utile, voir indispensables pour la non régression et la productivité. Ils permettent même de concevoir votre UI en TDD.  TDD : les tests UI ont le même effet sur le code que les test Unitaires. Ils le rendent plus maintenable en évitant de coder ce qui sort du besoin des tests, et le formate en le rendant plus lisible et mieux conçu.  STABILITE : la protection contre la régression est importante et exécutée autant de fois que nécessaire (à chaque modification de code et livraison d’application).  PRODUCTIVITE : ces tests interviennent dès la phase de dev, sont codés et exécutés TRES rapidement. La boucle de retour d’erreur est plus rapide car directement durant la phase de dev. Et il est possible par la suite de diminuer la charge d’une équipe de test.Mais ils sont difficiles à comprendre et à maintenir. La faute au besoin de ce test de rester indépendant de toute plateforme et d’être automatisable (ajout de PhantomJS et de Tomcat).Des solution à base de refactoring du code (Page pattern par exemple) ou carrément l’utilisation de frameworks plus haut niveau tel que FluentLenium améliorent beaucoup la productivité et la maintenance sur ce type de tests.Source codehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150118-test-seleniumhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150118-test-seleniumReferenceshttp://atatorus.developpez.com/tutoriels/java/test-application-web-avec-selenium/http://atatorus.developpez.com/tutoriels/java/test-application-web-avec-selenium/Originhttps://damienfremont.com/2015/01/18/tester-une-webapp-avec-selenium-java-phantomjs-et-un-webserver-embarque",
        "url": "/2015/01/18/tester-une-webapp-avec-selenium-java-phantomjs-et-un-webserver-embarque"
      },
    
      "2015-01-15-comment-creer-et-tester-un-server-http-rest-en-jax-rs-javaee-sous-tomcat": {
        "title": "Comment Creer Et Tester Un Server Http Rest En Jax Rs Javaee Sous Tomcat",
        "author": "",
        "category": "",
        "tags": "java, rest, test",
        "content": "Ce tutoriel couvre l’implémentation d’un server HTTP REST exposant du CRUD sur un simple objet. Ainsi que ses tests avec l’intégration d’un Tomcat dans JUnit et l’écriture de tests en BDD avec RestAssured. Il se fera en 2 partie : un dev/test de base, puis un dev/test gérant la validation de données et les codes d’erreur.EnvironnementEclipse, Jersey-Server, Tomcat et RestAssured. RestAssured propose un formalise BDD (Behavior Driven Development), plus proche de l’écriture d’un cas d’utilisation que d’un test unitaire. Ce choix rend le code plus maintenable et évite les solution “maison” qui dérivent trop.Source codePersonModel.javapublic class PersonModel implements Serializable {     private static final long serialVersionUID = 6879685199191377814L;     private Integer id;    private String firstName;    private String lastName;    private String birthDate;     public PersonModel() {    }     public PersonModel(String firstName, String lastName, String birthDate) {        super();        this.firstName = firstName;        this.lastName = lastName;        this.birthDate = birthDate;    }     public PersonModel(Integer id, String firstName, String lastName,            String birthDate) {        this(firstName, lastName, birthDate);        this.id = id;    }     public Integer getId() {        return id;    }     public void setId(Integer id) {        this.id = id;    }...PersonRepositorypublic class PersonRepository {     /* DATAS */     private static Map&lt;Integer, PersonModel&gt; datas = null;     public PersonRepository() {        datas = new HashMap&lt;&gt;();        datas.put(1, new PersonModel(1, \"Anakin\", \"Skywalker\", \"41.9 BBY\"));        datas.put(2, new PersonModel(2, \"Luke\", \"Skywalker\", \"19 BBY\"));        datas.put(3, new PersonModel(3, \"Leia\", \"Organa Solo\", \"19 BBY\"));    }     /* CRUD METHODS */     public PersonModel create(PersonModel entity) {        int randomNum = new Random().nextInt();        entity.setId(randomNum);        datas.put(entity.getId(), entity);        return entity;    }     public PersonModel read(Integer id) {        return datas.get(id);    }     public List&lt;PersonModel&gt; readAll() {        return new ArrayList&lt;PersonModel&gt;(datas.values());    }     public PersonModel update(PersonModel entity) {        return datas.put(entity.getId(), entity);    }     public void delete(Integer id) {        datas.remove(id);    } }pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150114-javaee-jersey_server&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;war&lt;/packaging&gt;    &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;jdk.version&gt;1.7&lt;/jdk.version&gt;        &lt;jersey.version&gt;1.18.3&lt;/jersey.version&gt;        &lt;jersey.test&gt;2.14&lt;/jersey.test&gt;        &lt;tomcat-version&gt;8.0.15&lt;/tomcat-version&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;!-- JERSEY SERVER --&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-json&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-server&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-servlet&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;         &lt;!-- TEST --&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.9&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.jayway.restassured&lt;/groupId&gt;            &lt;artifactId&gt;rest-assured&lt;/artifactId&gt;            &lt;version&gt;1.2.3&lt;/version&gt;        &lt;/dependency&gt;         &lt;!-- TEST : EMBEDDED SERVER (TOMCAT) --&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-core&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-logging-juli&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jasper&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jasper-el&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.apache.tomcat&lt;/groupId&gt;            &lt;artifactId&gt;tomcat-jsp-api&lt;/artifactId&gt;            &lt;version&gt;${tomcat-version}&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.2&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;Source code du service (version simple)Voici une version simple du service: on laisse faire jersey-server. La gestion précise des codes d’erreur et la validation des données viendra plus tard.PersonService1 .java@Path(\"/persons\")public class PersonService1 {     private PersonRepository dao = new PersonRepository();     /* CRUD METHODS */     @POST    @Produces(MediaType.TEXT_PLAIN)    public String createPerson(PersonModel person) {        return String.valueOf( dao.create(person).getId());    }     @GET    @Path(\"/id/{id}\")    @Produces(MediaType.APPLICATION_JSON)    public PersonModel readPerson(@PathParam(\"id\") Integer id) {        return dao.read(id);    }     @GET    @Produces(MediaType.APPLICATION_JSON)    public List&lt;PersonModel&gt; readPersons() {        return dao.readAll();    }     @POST    @Path(\"/id/{id}\")    public void updatePerson(@PathParam(\"id\") Integer id, PersonModel person) {        dao.update(person);    }     @DELETE    @Path(\"/id/{id}\")    public void deletePerson(@PathParam(\"id\") Integer id) {        dao.delete(id);    }}Demo / TestLes tests pourront s’exécuter au choix vers un serveur Tomcat local ou embarqué dans le test (c’est plus rapide et moins répétitif).Voici le test “à la main”. Il faut monter le projet dans un serveur Tomcat installé sur le poste de dev, à l’aide du plugin d’Eclipse par exemple. Puis tester avec votre navigateur web préféré ou SOAP-UI.http://zsoltfabok.com/blog/2012/08/embedded-web-services-for-testing/Voici le test automatisé. Il est réalisé à l’aide d’une classe EmbeddedServer qui “contient” Tomcat. Merci http://zsoltfabok.com/blog/2012/08/embedded-web-services-for-testing/.Faire attention au port utilisé par le serveur. Par défaut 8080, qui en local peut entrer en conflit avec un server, ou qui sur un CI (Jenkins par exemple) peut entrer en conflit avec un autre test (voir un autre server également).EmbeddedServer .java/* * FROM http://zsoltfabok.com/blog/2012/08/embedded-web-services-for-testing/ */public class EmbeddedServer implements Runnable {     private Tomcat tomcat;    private Thread serverThread;     public EmbeddedServer(int port, String contextPath) throws ServletException {        tomcat = new Tomcat();        tomcat.setPort(port);        tomcat.setBaseDir(\"target/tomcat\");        tomcat.addWebapp(contextPath,                new File(\"src/main/webapp\").getAbsolutePath());        serverThread = new Thread(this);     }     public void start() {        serverThread.start();    }     public void run() {        try {            tomcat.start();        } catch (LifecycleException e) {            throw new RuntimeException(e);        }        tomcat.getServer().await();    }     public void stop() {        try {            tomcat.stop();            tomcat.destroy();            deleteDirectory(new File(\"target/tomcat/\"));        } catch (LifecycleException e) {            throw new RuntimeException(e);        }    }     void deleteDirectory(File path) {        if (path == null)            return;        if (path.exists()) {            for (File f : path.listFiles()) {                if (f.isDirectory()) {                    deleteDirectory(f);                    f.delete();                } else {                    f.delete();                }            }            path.delete();        }    }}PersonService1Test.javapublic class PersonService1Test {     /* EMBEDDED SERVER (TOMCAT) */     private static EmbeddedServer server;     @BeforeClass    public static void startServer() throws ServletException {        server = new EmbeddedServer(8080, \"/20150114-javaee-jersey_server\");        server.start();    }     @AfterClass    public static void stopServer() {        server.stop();    }     /* TESTS */     private static final String REST_API = \"/20150114-javaee-jersey_server/api\";     @Test    public void testPersonCreateSuccess() {        expect()            .statusCode(200)            .body(notNullValue())        .given()            .contentType(\"application/json\")            .parameters(                    \"firstName\", \"Padme\",                    \"lastName\", \"Amidala\",                    \"birthDate\", \"46 BBY\")        .when()            .post(REST_API + \"/persons\");    }     @Test    public void testPersonGetSuccess() {        expect()            .statusCode(200)            .body(\"id\", equalTo(1))            .body(\"firstName\", equalTo(\"Anakin\"))            .body(\"lastName\", equalTo(\"Skywalker\"))            .body(\"birthDate\", equalTo(\"41.9 BBY\")) //        .when()            .get(REST_API + \"/persons/id/1\");    }     @Test    public void testPersonGetAllSuccess() {        expect()            .statusCode(200)            .body(\"id\", hasItems(1, 2, 3)) //        .when()            .get(REST_API + \"/persons\");    }     @Test    public void testPersonPostUpdateSuccess() {        expect()            .statusCode(204)        .given()            .contentType(\"application/json\")            .parameters(                    \"firstName\", \"Anakin\",                    \"lastName\", \"Skywalker\",                    \"birthDate\", \"41.9 BBY\")        .when()            .post(REST_API + \"/persons/id/1\");    }     @Test    public void testPersonDeleteSuccess() {        expect()            .statusCode(204)        .when()            .delete(REST_API + \"/persons/id/3\");    }}C’est quand même plus simple pour tous les jours !Source code du service (version avancée)Voici une version avancée du service : on implémente certains comportements (validations, codes http).PersonService2 .java@Path(\"/persons2\")public class PersonService2 {     private PersonRepository dao = new PersonRepository();     /* CRUD METHODS */     @POST    @Produces(MediaType.TEXT_PLAIN)    public Response createPerson(PersonModel person) {        // VALIDATION        if (!(person != null                &amp;&amp; person.getFirstName() != null &amp;&amp; person.getLastName() != null &amp;&amp; person.getBirthDate() != null)) {            return Response                    .status(BAD_REQUEST)                    .build();        }        // PROCESS        PersonModel newEntity = dao.create(person);        // RESULT        return Response                .status(CREATED)                .entity(\"Location: /persons2/\" + newEntity.getId())                .build();    }     @GET    @Path(\"/id/{id}\")    @Produces(MediaType.APPLICATION_JSON)    public Response readPerson(@PathParam(\"id\") Integer id) {        // VALIDATION        if (id == null)            return Response                    .status(Status.BAD_REQUEST)                    .build();        // PROCESS        PersonModel entity = dao.read(id);        // RESULT        return Response                .status(ACCEPTED)                .entity(entity)                .build();    }     @GET    @Produces(MediaType.APPLICATION_JSON)    public Response readPersons() {        // PROCESS        List&lt;PersonModel&gt; entities = dao.readAll();        // RESULT        return Response                .status(ACCEPTED)                .entity(entities)                .build();    }     @POST    @Path(\"/id/{id}\")    public Response updatePerson(@PathParam(\"id\") Integer id, PersonModel person) {        // VALIDATION        if (!(person != null &amp;&amp; id != null                &amp;&amp; person.getFirstName() != null &amp;&amp; person.getLastName() != null &amp;&amp; person.getBirthDate() != null)) {            return Response                    .status(BAD_REQUEST)                    .build();        }        // PROCESS        dao.update(person);        // RESULT        return Response                .status(ACCEPTED)                .build();    }     @DELETE    @Path(\"/id/{id}\")    public Response deletePerson(@PathParam(\"id\") Integer id) {        // VALIDATION        if (id == null)            return Response                    .status(BAD_REQUEST)                    .build();        // PROCESS        dao.delete(id);        // RESULT        return Response                .status(ACCEPTED)                .build();    }}Demo / TestPersonService2Test .javapublic class PersonService2Test {     /* EMBEDDED SERVER (TOMCAT) */     private static EmbeddedServer server;     @BeforeClass    public static void startServer() throws ServletException {        server = new EmbeddedServer(8080, \"/20150114-javaee-jersey_server\");        server.start();    }     @AfterClass    public static void stopServer() {        server.stop();    }     /* TESTS */     private static final String REST_API = \"/20150114-javaee-jersey_server/api\";     @Test    public void testPersonCreateSuccess() {        expect()            .statusCode(201)            .body(notNullValue())        .given()            .contentType(\"application/json\")            .parameters(                    \"firstName\", \"Padme\",                    \"lastName\", \"Amidala\",                    \"birthDate\", \"46 BBY\")        .when()            .post(REST_API + \"/persons2\");    }     @Test    public void testPersonCreateBadRequest() {        expect()            .statusCode(400)        .given()            .contentType(\"application/json\")            .parameters(                    // missing firstname !!!                    \"lastName\", \"Amidala\",                    \"birthDate\", \"46 BBY\")        .when()            .post(REST_API + \"/persons2\");    } }ConclusionJersey-server reste pratique pour développer rapidement comme pour aller plus loin. RestAssured permet de tester encore plus facilement, tout en auto-documentant le code avec une approche BDD. Et Tomcat Embedded simplifie la maintenance en s’intégrant facilement avec JUnit.Pour aller plus loin, il y a la possibilité de :  utiliser une validation de données plus simple (JavaEE, BeanValidation, Guava ou ApacheCommon)  remplacer le Repository par un mock (mockito) qui permettrait de : isoler le code simuler des pannes (test erreurs 500) vérifier les appels effectués aux couches basses de l’application  mettre en place une injection de dépendanceTroubleshooting“Caused by: com.sun.jersey.api.MessageException: A message body writer for Java class …, and Java type class…, and MIME media type application/json was not found”La dépendance à jersey-json est manquante. Ajouter au pom.xml&lt;dependency&gt;  &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;  &lt;artifactId&gt;jersey-json&lt;/artifactId&gt;  &lt;version&gt;1.18.3&lt;/version&gt;&lt;/dependency&gt;Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150114-javaee-jersey_serverhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150114-javaee-jersey_serverReferenceshttps://jersey.java.net/https://jersey.java.net/http://blog.xebia.fr/2014/03/17/post-vs-put-la-confusion/http://blog.xebia.fr/2014/03/17/post-vs-put-la-confusion/http://www.mkyong.com/tutorials/jax-rs-tutorials/http://www.mkyong.com/tutorials/jax-rs-tutorials/https://code.google.com/p/rest-assured/wiki/Usagehttps://code.google.com/p/rest-assured/wiki/Usagehttp://www.hascode.com/2011/09/rest-assured-vs-jersey-test-framework-testing-your-restful-web-services/#Using_REST-assuredhttp://www.hascode.com/2011/09/rest-assured-vs-jersey-test-framework-testing-your-restful-web-services/#Using_REST-assuredhttp://blog.fastconnect.fr/?p=1565http://blog.fastconnect.fr/?p=1565Originhttps://damienfremont.com/2015/01/15/comment-creer-et-tester-un-server-http-rest-en-jax-rs-javaee-sous-tomcat/",
        "url": "/2015/01/15/comment-creer-et-tester-un-server-http-rest-en-jax-rs-javaee-sous-tomcat"
      },
    
      "2015-01-13-comment-utiliser-beanvalidation-manuellement-hors-dun-serveur-javaee": {
        "title": "Comment Utiliser Beanvalidation Manuellement Hors Dun Serveur Javaee",
        "author": "",
        "category": "",
        "tags": "java, rest, spring",
        "content": "Ce tuto décrit comment valider un modèle de données manuellement avec JavaEE BeanValidation (JSR 303). L’intérêt ? Eviter une pile de  inmaintenable dans le code quand on n’a pas accès à l’annotation @Valid (pas de server JavaEE, un Tomcat par exemple). Ce point étant couvert par la spécification mais rarement décrit. Les exceptions et les messages d’erreurs seront également abordés.EnvironnementIl faut Java 1.6, un IDE Eclipse et Maven.pom.xml&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.damienfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20150113-javaee-beanvalidator&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;url&gt;http://damienfremont.com&lt;/url&gt;    &lt;dependencies&gt;        &lt;dependency&gt;            &lt;groupId&gt;junit&lt;/groupId&gt;            &lt;artifactId&gt;junit&lt;/artifactId&gt;            &lt;version&gt;4.12&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.assertj&lt;/groupId&gt;            &lt;artifactId&gt;assertj-core&lt;/artifactId&gt;            &lt;version&gt;1.7.1&lt;/version&gt;            &lt;scope&gt;test&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;javax.validation&lt;/groupId&gt;            &lt;artifactId&gt;validation-api&lt;/artifactId&gt;            &lt;version&gt;1.1.0.Final&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.hibernate&lt;/groupId&gt;            &lt;artifactId&gt;hibernate-validator&lt;/artifactId&gt;            &lt;version&gt;5.1.3.Final&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;org.glassfish&lt;/groupId&gt;            &lt;artifactId&gt;javax.el&lt;/artifactId&gt;            &lt;version&gt;3.0.0&lt;/version&gt;        &lt;/dependency&gt;    &lt;/dependencies&gt;    &lt;build&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.2&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;1.7&lt;/source&gt;                    &lt;target&gt;1.7&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;Source codeLa même Entité / Bean est utilisé pour tout le tuto. C’est un POJO autour de la personne, il contient ses 3 données de base : nom, prénom, date de naissance. Il en porte également la validation au travers des annotations JavaEE qui vont bien.PersonModel.javapackage com.damienfremont.blog; import java.util.Calendar; import javax.validation.constraints.NotNull;import javax.validation.constraints.Past;import javax.validation.constraints.Size; public class PersonModel {     @NotNull    @Size(min = 1, max = 16)    private String firstName;     @NotNull    @Size(min = 1, max = 16)    private String lastName;     @NotNull    @Past    private Calendar birthDate;     public PersonModel(String firstName, String lastName, Calendar birthDate) {        super();        this.firstName = firstName;        this.lastName = lastName;        this.birthDate = birthDate;    } }@Null : Vérifier que la valeur du type concerné soit null@NotNull : Vérifier que la valeur du type concerné soit non null@Size : Vérifier que la taille de la donnée soit comprise en les valeurs min et max fournies@Past : Vérifier que la date soit dans le passé (antérieure à la date courante)DemoPersonModelTest.javapackage com.damienfremont.blog; import static org.assertj.core.api.Assertions.assertThat; import java.util.Calendar;import java.util.GregorianCalendar;import java.util.Set; import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import javax.validation.ValidatorFactory; import org.assertj.core.api.Condition;import org.junit.Test; public class PersonModelTest {     @Test    public void test_WHEN_valid_GIVEN_valid_model_THEN_ok_no_errors() {         // GIVEN         PersonModel person = new PersonModel( //                \"Kim\", //                \"Kardashian\", //                new GregorianCalendar(1980, Calendar.OCTOBER, 21));        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();        Validator validator = factory.getValidator();         // WHEN         Set&lt;ConstraintViolation&lt;PersonModel&gt;&gt; constraintViolations = validator                .validate(person);         // THEN         assertThat(constraintViolations).isEmpty();    }     @Test    public void test_WHEN_valid_GIVEN_invalid_model_THEN_error() {         // GIVEN         PersonModel person = new PersonModel( //                null, //                \"\", //                null);         ValidatorFactory factory = Validation.buildDefaultValidatorFactory();        Validator validator = factory.getValidator();         // WHEN         Set&lt;ConstraintViolation&lt;PersonModel&gt;&gt; constraintViolations = validator                .validate(person);         // THEN         assertThat(constraintViolations) //                .hasSize(3) //                .haveExactly(2, notNullCondition) //                .haveExactly(1, notEmptyCondition);    }     Condition&lt;ConstraintViolation&lt;PersonModel&gt;&gt; notNullCondition = new Condition&lt;ConstraintViolation&lt;PersonModel&gt;&gt;() {         @Override        public boolean matches(ConstraintViolation&lt;PersonModel&gt; arg0) {            return arg0.getMessage().contains(\"may not be null\");        }    };    Condition&lt;ConstraintViolation&lt;PersonModel&gt;&gt; notEmptyCondition = new Condition&lt;ConstraintViolation&lt;PersonModel&gt;&gt;() {         @Override        public boolean matches(ConstraintViolation&lt;PersonModel&gt; arg0) {            return arg0.getMessage().contains(\"size must be between\");        }    };}Gestion des ExceptionsIl est facile de décliner cette solution pour créer des Exceptions, pour un back-end par exemple.Source codeIci, on veut qu’une Exception soir remontée si et seulement si il y a une erreur de validation.ValidationByExceptionHandler.javapackage com.damienfremont.blog; import java.util.Set; import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator; public class ValidationByExceptionHandler {     Validator jeeValidator = Validation.buildDefaultValidatorFactory()            .getValidator();     &lt;T&gt; void validate(T object) {        Set&lt;ConstraintViolation&lt;T&gt;&gt; errs = jeeValidator.validate(object);        if (errs.size() &gt; 0) { // error            String msg = \"Invalid Bean, constraint error(s) : \";            for (ConstraintViolation&lt;T&gt; err : errs) {                msg += err.getPropertyPath() + \" \" + err.getMessage() + \". \";            }            throw new IllegalArgumentException(msg);        }    }}DemoValidationByExceptionHandlerTest.javapackage com.damienfremont.blog; import static org.assertj.core.api.Assertions.assertThat;import static org.junit.Assert.fail; import java.util.Calendar;import java.util.GregorianCalendar; import org.junit.Test; public class ValidationByExceptionHandlerTest {     @Test    public void test_WHEN_valid_GIVEN_valid_model_THEN_ok_no_errors() {         // GIVEN         PersonModel person = new PersonModel( //                \"Kim\", //                \"Kardashian\", //                new GregorianCalendar(1980, Calendar.OCTOBER, 21));        ValidationByExceptionHandler validator = new ValidationByExceptionHandler();         // WHEN         validator.validate(person);         // THEN        // nothing to do    }     @Test    public void test_WHEN_valid_GIVEN_invalid_model_THEN_error() {         // GIVEN         PersonModel person = new PersonModel( //                null, //                \"\", //                null);        ValidationByExceptionHandler validator = new ValidationByExceptionHandler();         // WHEN         try {            validator.validate(person);            fail();        } catch (IllegalArgumentException e) {             // THEN             assertThat(e.getMessage())                    .contains(\"Invalid Bean, constraint error(s) : \")                    .contains(\"birthDate may not be null.\")                    .contains(\"firstName may not be null.\")                    .contains(\"lastName size must be between 1 and 16.\");        }    } }Gestion des ResponsesVoici un exemple de gestion plus spécifique, pour un back-end HTTP.Source codeIl faut mettre à jour la conf Maven pour gérer les Response JAX-RS.pom.xml...        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-json&lt;/artifactId&gt;            &lt;version&gt;1.8&lt;/version&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-client&lt;/artifactId&gt;            &lt;version&gt;1.12&lt;/version&gt;        &lt;/dependency&gt;    &lt;/dependencies&gt;    &lt;build&gt;...Ici, on veut construire le Response du server HTTP, dans les cas avec ou sans erreur de validation.ValidationByResponseHandler.javapackage com.damienfremont.blog; import java.util.Set; import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import javax.ws.rs.core.Response; public class ValidationByResponseHandler {     Validator jeeValidator = Validation.buildDefaultValidatorFactory()            .getValidator();     &lt;T&gt; Response validate(T object) {        Set&lt;ConstraintViolation&lt;T&gt;&gt; errs = jeeValidator.validate(object);        if (errs.isEmpty()) { // no error            return Response.status(200).entity(object).build();        } else { // error            String msg = \"Invalid Bean, constraint error(s) : \";            for (ConstraintViolation&lt;T&gt; err : errs) {                msg += err.getPropertyPath() + \" \" + err.getMessage() + \". \";            }            return Response.status(400).entity(msg).build();        }     }}DemoValidationByResponseHandlerTest.javapackage com.damienfremont.blog; import static org.assertj.core.api.Assertions.assertThat; import java.util.Calendar;import java.util.GregorianCalendar; import javax.ws.rs.core.Response; import org.junit.Test; public class ValidationByResponseHandlerTest {     @Test    public void test_WHEN_valid_GIVEN_valid_model_THEN_ok_no_errors() {         // GIVEN         PersonModel person = new PersonModel( //                \"Kim\", //                \"Kardashian\", //                new GregorianCalendar(1980, Calendar.OCTOBER, 21));        ValidationByResponseHandler validator = new ValidationByResponseHandler();         // WHEN         Response response = validator.validate(person);         // THEN        assertThat(response.getStatus()).isEqualTo(200);    }     @Test    public void test_WHEN_valid_GIVEN_invalid_model_THEN_error() {         // GIVEN         PersonModel person = new PersonModel( //                null, //                \"\", //                null);        ValidationByResponseHandler validator = new ValidationByResponseHandler();         // WHEN         Response response = validator.validate(person);         // THEN        assertThat(response.getStatus()).isEqualTo(400);        assertThat(response.getEntity().toString())                .contains(\"Invalid Bean, constraint error(s) : \")                .contains(\"birthDate may not be null.\")                .contains(\"firstName may not be null.\")                .contains(\"lastName size must be between 1 and 16.\");    } }ConclusionCe genre de solution permet de rester proche des standards JavaEE. Elle permet donc de faciliter la maintenance et la compréhension entre développeur par rapport à une solution custom parfois instable ( dans tous les sens). Elle arrive aussi avec ses outils préfabriqués qui accélèrent le dev. Tel que les validations de base, les annotations, l’inspection de toutes les contraintes (analyse au delà de la première erreur) et la génération des messages d’erreurs.Toutefois, la validation manuelle n’a pratiquement plus sa place dans un server JavaEE. Les annotations @Valid la remplaçant déjà dans SpringMVC et JavaEE. Reste toutefois les petits projets, les batch et les servers non JavaEE.@Path(\"/example\")public class MyExampleResourceImpl {     @POST    @Path(\"/\")    public Response postExample(@Valid final Example example) {        // ....    }}http://stackoverflow.com/questions/14523201/hibernate-validator-how-to-work-with-valid-annotationhttp://stackoverflow.com/questions/14523201/hibernate-validator-how-to-work-with-valid-annotation@Controller@RequestMapping(\"/customer\")public class SignUpController {     @RequestMapping(value = \"/signup\", method = RequestMethod.POST)    public String addCustomer(@Valid Customer customer, BindingResult result) {         // ....    }}http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/Sourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150113-javaee-beanvalidatorhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20150113-javaee-beanvalidatorReferenceshttp://beanvalidation.org/http://beanvalidation.org/http://hibernate.org/validator/http://hibernate.org/validator/http://www.adam-bien.com/roller/abien/entry/unit_integration_testing_the_beanhttp://www.adam-bien.com/roller/abien/entry/unit_integration_testing_the_beanhttp://docs.oracle.com/javaee/6/tutorial/doc/gircz.htmlhttp://docs.oracle.com/javaee/6/tutorial/doc/gircz.htmlhttp://www.jmdoudoux.fr/java/dej/chap-validation_donnees.htmhttp://www.jmdoudoux.fr/java/dej/chap-validation_donnees.htmOriginhttps://damienfremont.com/2015/01/13/comment-utiliser-beanvalidation-manuellement-hors-dun-serveur-javaee/",
        "url": "/2015/01/13/comment-utiliser-beanvalidation-manuellement-hors-dun-serveur-javaee"
      },
    
      "2015-01-13-comment-simplifier-un-modele-objet": {
        "title": "Comment Simplifier Un Modele Objet",
        "author": "",
        "category": "",
        "tags": "design, quicktip",
        "content": "Voici un tutoriel expliquant comment simplifier un modèle objet devenu trop complexe ou lourd à gérer. Une méthode basique est appliquée, autour d’un objet classique : la personne et ses informations.Méthode  Utiliser un modèle brut          Remettre à plat le modèle      Réaliser un exemple de données        Gérer les relations uniques (1-1)          Identifier      Rapatrier ces données dans l’objet principale        Gérer les relations multiples (1-N)          Identifier      Sortir ces données        Utiliser des abstractions  Gérer les excès de modélisation          Supprimer les abstractions inutiles      Limiter le nombre de niveaux de relation      Exemple : la personne1. Modèle de baseRemettre à plat le modèle, sans abstractions, avec 1 seul niveau de relation.Réaliser un exemple de données pour comprendre les relations dans le modèle.2. Gérer les relations uniques (1-1)Nom, prénom et date de naissance : identifiant unique d’une personne physique.Rapatrier ces données dans l’objet principal3. Gérer les relations multiples (1-N)Sortir ces données de l’objet principal. Pour Facebook et Twitter : techniquement, il est possible d’avoir plusieurs comptes.4. Utiliser des abstractionsChercher à faire des regroupements, Rester généraliste.5. Gérer les excès de modélisationSupprimer les abstractions inutiles (les erreurs permettent d’avancer).Exemple :  « Web » n’apporte pas de valeur  Seul les sites principaux nous intéressent (retour à une relation 1-1)  Facebook et Twitter ne seront pas utilisés comme contactsLimiter le nombre de niveaux de relation.Exemple : les sous-types « pro » et « perso » n’ont pas de particularité -&gt; ils migrent vers un niveau plus hautExemple de modèle finalisé",
        "url": "/2015/01/13/comment-simplifier-un-modele-objet"
      },
    
      "2014-12-19-how-to-expandcollapse-table-rows-with-bootstrap": {
        "title": "How-To Bootstrap: Expand and Collapse Table Rows With Bootstrap",
        "author": "",
        "category": "",
        "tags": "bootstrap, css, javascript",
        "content": "How to do accordions effect on table rows with Bootstrap? We will see that using a HTML table to make a table … is not a good idea!GoalMake a table where each row is clickable to show a hidden sub-content (left side) and / or to navigate with clickable buttons (right).bootstrap collapse componentstylish buttonsWe must therefore integrate bootstrap collapse component and stylish buttons.Bad Idea with tableStep 1 : tableit is the one bootstrap offers us a simple tableNothing to say is the most logical solution, because it is the one bootstrap offers us a simple table.&lt;tr&gt;    &lt;td&gt;1&lt;/td&gt;    &lt;td&gt;Mark&lt;/td&gt;    &lt;td&gt;Otto&lt;/td&gt;    &lt;td&gt;@mdo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;2&lt;/td&gt;    &lt;td&gt;Jacob&lt;/td&gt;    &lt;td&gt;Thornton&lt;/td&gt;    &lt;td&gt;@fat&lt;/td&gt;&lt;/tr&gt;Step 2 : table + collapsebootstrap the doc with only data-target and collapseYou must use the bootstrap the doc with only data-target and collapse.Problem: The collapse does not work with a TR tag for target.Solution: Create a DIV in a sub-TR (optional: add CSS to hide the permanent residual margin/padding of the hidden/collapsed line).&lt;tr class=\"accordion-toggle\"  data-toggle=\"collapse\" data-target=\"#collapseOne\"&gt;    &lt;td&gt;1&lt;/td&gt;    &lt;td&gt;Mark&lt;/td&gt;    &lt;td&gt;Otto&lt;/td&gt;    &lt;td&gt;@mdo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td colspan=\"3\"&gt;        &lt;div id=\"collapseOne\" class=\"collapse in\"&gt;            Details 1 &lt;br/&gt;            Details 2 &lt;br/&gt;            Details 3 &lt;br/&gt;        &lt;/div&gt;    &lt;/td&gt;&lt;/tr&gt;Step 3 : table + collapse + buttonsProblem: a click on a button causes a side effect of expand/collapse the container row. It’s bad when you click for a new tab/window on the details button to displays, because it will activate the accordion effect on the current row (example: click on edit).Solution: you must prevent the expand/collapse from triggering when a button is clicked. It is therefore necessary to assign the click to expand each cell rather than on the TD TR tags.It works BUT JavaScript lags on expanding/collapsing when there are dozens of roww and sub-rows on the page and there are duplicate code.&lt;tr class=\"accordion-toggle\"  &gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;1&lt;/td&gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;Mark&lt;/td&gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;Otto&lt;/td&gt;    &lt;td data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;@mdo&lt;/td&gt;    &lt;td&gt;&lt;a class=\"btn btn-primary\" href=\"https://www.google.com/\"&gt;&lt;i class=\"icon-search icon-white\"&gt;&lt;/i&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td colspan=\"4\"&gt;        &lt;div id=\"collapseTwo\" class=\"collapse in\"&gt;            - Details 1 &lt;br/&gt;            - Details 2 &lt;br/&gt;            - Details 3 &lt;br/&gt;        &lt;/div&gt;    &lt;/td&gt;&lt;/tr&gt;Better Idea with divStep 1 : divBootstrap grid systemYou must use the Bootstrap grid system.Problem: table style is lost.Solution: (optional) You must duplicate the CSS if you will get the same rendering as before (top row border, cell width, header bold).&lt;div class=\"row-fluid\" &gt;    &lt;div class=\"span2\"&gt;1&lt;/div&gt;    &lt;div class=\"span2\"&gt;Mark&lt;/div&gt;    &lt;div class=\"span2\"&gt;Otto&lt;/div&gt;    &lt;div class=\"span2\"&gt;@mdo&lt;/div&gt;&lt;/div&gt;Step 2 : div + collapse(same solution table and collapse)Problem: The cursor’s shape does not change when being over the clickable row (“hand” icon expected here).Solution: (optional) use a personal style or re-use the class accordion-toggle on the collapsable DIV.&lt;div class=\"row-fluid\" data-toggle=\"collapse\" data-target=\"#collapseTwo\"&gt;    &lt;div class=\"span1\"&gt;1&lt;/div&gt;    &lt;div class=\"span3\"&gt;Mark&lt;/div&gt;    &lt;div class=\"span3\"&gt;Otto&lt;/div&gt;    &lt;div class=\"span3\"&gt;@mdo&lt;/div&gt;&lt;/div&gt;&lt;div id=\"collapseTwo\" class=\"row-fluid collapse in\"&gt;    &lt;div class=\"span1\"&gt;&lt;/div&gt;    &lt;div class=\"span9\"&gt;        Details 1 &lt;br/&gt;        Details 2 &lt;br/&gt;        Details 3 &lt;br/&gt;    &lt;/div&gt;&lt;/div&gt;Step 3 : div + collapse + buttons(same solution collapse + table + buttons)Problem: Adding buttons also add conflicts with the collapse/expand effect.Solution: remove the button form the DIV toggler.Solution&lt;div class=\"row-fluid\" &gt;    &lt;div class=\"accordion-toggle\" data-toggle=\"collapse\" data-target=\"#collapseThree\"&gt;        &lt;div class=\"span1\"&gt;1&lt;/div&gt;        &lt;div class=\"span3\"&gt;Mark&lt;/div&gt;        &lt;div class=\"span3\"&gt;Otto&lt;/div&gt;        &lt;div class=\"span3\"&gt;@mdo&lt;/div&gt;    &lt;/div&gt;    &lt;div class=\"span1\"&gt;        &lt;button type=\"button\" class=\"btn btn-primary\"&gt;&lt;i class=\"icon-search icon-white\"&gt;&lt;/i&gt;&lt;/button&gt;    &lt;/div&gt;&lt;/div&gt;&lt;div id=\"collapseThree\" class=\"row-fluid collapse in\"&gt;    &lt;div class=\"span1\"&gt;&lt;/div&gt;    &lt;div class=\"span9\"&gt;        Details 1 &lt;br/&gt;        Details 2 &lt;br/&gt;        Details 3 &lt;br/&gt;    &lt;/div&gt;&lt;/div&gt;#ConclusionI currently use the DIV version. With TABLE, fhe final page was not reactive enough, the source code was duplicated, and there were a lot of bugs/maintenance and technical solution TABLE was not always understandable, even with the doc bootstrap support.COLLAPSABLE TABLE  Pro : defaut bootstrap CSS style  Con : it’s a hack, performance issues, code duplicationCOLLAPSABLE  DIV  Pro : responsive, fast, reliable  Con : custom style for cursor and TABLESourceshttp://github.com/damienfremont/blog/tree/master/20141216-bootstrap-collapsable_tablehttp://github.com/damienfremont/blog/tree/master/20141216-bootstrap-collapsable_tableReferenceshttp://getbootstrap.com/2.3.2/http://getbootstrap.com/2.3.2/http://getbootstrap.com/2.3.2/base-css.htmlhttp://getbootstrap.com/2.3.2/base-css.htmlhttp://getbootstrap.com/2.3.2/javascript.htmlhttp://getbootstrap.com/2.3.2/javascript.htmlhttp://getbootstrap.com/2.3.2/scaffolding.htmlhttp://getbootstrap.com/2.3.2/scaffolding.htmlhttp://getbootstrap.com/2.3.2/components.htmlhttp://getbootstrap.com/2.3.2/components.htmlOriginhttps://damienfremont.com/2014/12/19/how-to-expandcollapse-table-rows-with-bootstrap",
        "url": "/2014/12/19/how-to-expandcollapse-table-rows-with-bootstrap"
      },
    
      "2014-12-17-todo-list-exemple-full-java-avec-gwt-tomcat-jersey": {
        "title": "Todo List Exemple Full Java Avec Gwt Tomcat Jersey",
        "author": "",
        "category": "",
        "tags": "java, rest",
        "content": "todoapp jsCe tutoriel est la suite de todoapp js, mais en java cette fois-ci. C’est le dev d’une simple TODO list de type client-serveur (front-end + back-end). Le but est d’utiliser une stack technique complète en Java pour comparer avec d’autres technologies.EnvironnementeclipseMaventomcat7plugin GWTEn DEV : un IDE eclipse JavaEE + Maven et un tomcat7, ensuite installer le plugin GWT, manuellement ou via le marketplace d’eclipse.todomvc.comexemple en GWTEn RUN : le front-end se base sur le site todomvc.com avec l’exemple en GWT. Le back-end est un Tomcat avec une servlet REST HTTP Jersey (JAX-RS).La structure (classique) est composé d’un MVC coté front et d’un service REST coté back :  Front Model View Controler  Back Service RepositoryCodegithub sourceRécupérer le code à partir de github source puis builder le projet.Le plus obscure est la pom.xml, il permet de jonglet avec : les incompatibilité de compilation (la partie serveur compilée en Java et la partie cliente GWT compilée en Java puis Javascript et certaines librairies sont en commun comme asm), les dossiers target (la partie Java/Maven/Eclipse/Tomcat attend les fichiers générés dans target et la partie GWT le fait dans src/main/webapp).&lt;project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"&gt;    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;    &lt;groupId&gt;com.dfremont.blog&lt;/groupId&gt;    &lt;artifactId&gt;20141215-todoapp-java&lt;/artifactId&gt;    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;    &lt;packaging&gt;war&lt;/packaging&gt;    &lt;properties&gt;        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;        &lt;jdk.version&gt;1.6&lt;/jdk.version&gt;        &lt;jersey.version&gt;1.8&lt;/jersey.version&gt;        &lt;gwt.version&gt;2.7.0&lt;/gwt.version&gt;        &lt;webappDirectory&gt;${project.build.directory}/${project.build.finalName}&lt;/webappDirectory&gt;    &lt;/properties&gt;    &lt;dependencies&gt;         &lt;dependency&gt;            &lt;groupId&gt;com.google.gwt&lt;/groupId&gt;            &lt;artifactId&gt;gwt-servlet&lt;/artifactId&gt;            &lt;version&gt;${gwt.version}&lt;/version&gt;            &lt;scope&gt;runtime&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.google.gwt&lt;/groupId&gt;            &lt;artifactId&gt;gwt-user&lt;/artifactId&gt;            &lt;version&gt;${gwt.version}&lt;/version&gt;            &lt;scope&gt;provided&lt;/scope&gt;        &lt;/dependency&gt;         &lt;dependency&gt;            &lt;artifactId&gt;asm&lt;/artifactId&gt;            &lt;groupId&gt;asm&lt;/groupId&gt;            &lt;version&gt;3.1&lt;/version&gt;            &lt;scope&gt;runtime&lt;/scope&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-server&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;            &lt;exclusions&gt;                &lt;exclusion&gt;                    &lt;artifactId&gt;asm&lt;/artifactId&gt;                    &lt;groupId&gt;asm&lt;/groupId&gt;                &lt;/exclusion&gt;            &lt;/exclusions&gt;        &lt;/dependency&gt;        &lt;dependency&gt;            &lt;groupId&gt;com.sun.jersey&lt;/groupId&gt;            &lt;artifactId&gt;jersey-json&lt;/artifactId&gt;            &lt;version&gt;${jersey.version}&lt;/version&gt;        &lt;/dependency&gt;     &lt;/dependencies&gt;    &lt;build&gt;        &lt;resources&gt;            &lt;resource&gt;                &lt;directory&gt;src/main/java&lt;/directory&gt;                &lt;includes&gt;                    &lt;include&gt;src/main/java/com/todo/**/*.java&lt;/include&gt;                    &lt;include&gt;**/*.gwt.xml&lt;/include&gt;                &lt;/includes&gt;            &lt;/resource&gt;        &lt;/resources&gt;        &lt;plugins&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;                &lt;version&gt;3.0&lt;/version&gt;                &lt;configuration&gt;                    &lt;source&gt;${jdk.version}&lt;/source&gt;                    &lt;target&gt;${jdk.version}&lt;/target&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;            &lt;plugin&gt;                &lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;                &lt;artifactId&gt;gwt-maven-plugin&lt;/artifactId&gt;                &lt;version&gt;${gwt.version}&lt;/version&gt;                &lt;executions&gt;                    &lt;execution&gt;                        &lt;configuration&gt;                            &lt;module&gt;com.todo.GwtToDo&lt;/module&gt;                            &lt;runTarget&gt;index.html&lt;/runTarget&gt;                            &lt;hostedWebapp&gt;src/main/webapp&lt;/hostedWebapp&gt;                            &lt;warSourceDirectory&gt;src/main/webapp&lt;/warSourceDirectory&gt;                            &lt;outputDirectory&gt;src/main/webapp&lt;/outputDirectory&gt;                        &lt;/configuration&gt;                        &lt;goals&gt;                            &lt;goal&gt;compile&lt;/goal&gt;                        &lt;/goals&gt;                    &lt;/execution&gt;                &lt;/executions&gt;            &lt;/plugin&gt;            &lt;plugin&gt;                &lt;artifactId&gt;maven-clean-plugin&lt;/artifactId&gt;                &lt;version&gt;2.6&lt;/version&gt;                &lt;executions&gt;                    &lt;execution&gt;                        &lt;id&gt;Deleting all unnecessary files before lint analysis&lt;/id&gt;                        &lt;goals&gt;                            &lt;goal&gt;clean&lt;/goal&gt;                        &lt;/goals&gt;                    &lt;/execution&gt;                &lt;/executions&gt;                &lt;configuration&gt;                    &lt;excludeDefaultDirectories&gt;true&lt;/excludeDefaultDirectories&gt;                    &lt;filesets&gt;                        &lt;fileset&gt;                            &lt;directory&gt;src/main/webapp/gwttodo&lt;/directory&gt;                            &lt;followSymlinks&gt;false&lt;/followSymlinks&gt;                        &lt;/fileset&gt;                        &lt;fileset&gt;                            &lt;directory&gt;src/main/gwt-unitCache&lt;/directory&gt;                            &lt;followSymlinks&gt;false&lt;/followSymlinks&gt;                        &lt;/fileset&gt;                    &lt;/filesets&gt;                    &lt;verbose&gt;true&lt;/verbose&gt;                &lt;/configuration&gt;            &lt;/plugin&gt;        &lt;/plugins&gt;    &lt;/build&gt;&lt;/project&gt;Coté serveur, c’est du REST en Jersey (classique …et simple).TodoService.javapackage com.dfremont.blog; import javax.ws.rs.Consumes;import javax.ws.rs.GET;import javax.ws.rs.PUT;import javax.ws.rs.Path;import javax.ws.rs.Produces;import javax.ws.rs.core.MediaType;import javax.ws.rs.core.Response; @Path(\"/todos\")public class TodoService {     private TodoRepository dao = new TodoRepository();     @GET    @Produces(MediaType.APPLICATION_JSON)    public Response readTodos() {        // log        System.out.println(\"@GET todos\");        try {            // find            TodoModel[] todos = dao.findAll();            // success            return Response.status(200).entity(todos).build();        } catch (Exception e) {            // error            return Response.status(500).build();        }    }     @PUT    @Consumes(MediaType.APPLICATION_JSON)    public Response updateTodos(TodoModel[] updatedTodos) {        // log        System.out.println(\"@PUT todos\");        try {            // update            dao.updateAll(updatedTodos);            // success            return Response.status(201).entity(\"Track saved\").build();        } catch (Exception e) {            // error            return Response.status(500).build();        }    } }web.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:web=\"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\"    xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\"    id=\"WebApp_ID\" version=\"2.5\"&gt;    &lt;servlet&gt;        &lt;servlet-name&gt;Jersey REST Service&lt;/servlet-name&gt;        &lt;servlet-class&gt;com.sun.jersey.spi.container.servlet.ServletContainer&lt;/servlet-class&gt;        &lt;init-param&gt;            &lt;param-name&gt;com.sun.jersey.config.property.packages&lt;/param-name&gt;             &lt;!-- Your rest package --&gt;            &lt;param-value&gt;com.dfremont.blog&lt;/param-value&gt;         &lt;/init-param&gt;        &lt;init-param&gt;            &lt;param-name&gt;com.sun.jersey.api.json.POJOMappingFeature&lt;/param-name&gt;            &lt;param-value&gt;true&lt;/param-value&gt;        &lt;/init-param&gt;        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;    &lt;/servlet&gt;    &lt;servlet-mapping&gt;        &lt;servlet-name&gt;Jersey REST Service&lt;/servlet-name&gt;        &lt;url-pattern&gt;/api/*&lt;/url-pattern&gt;    &lt;/servlet-mapping&gt;&lt;/web-app&gt;Coté client, c’est du GWT (classique …et compliqué pour rien. Voir le source sur github ou todomvc.DemoLancer le serveur.http://localhost:8080/20141215-todoapp-java/api/todosTester sur L’URL du back. http://localhost:8080/20141215-todoapp-java/api/todos##http://localhost:8080/20141215-todoapp-java/Tester sur L’URL du front. http://localhost:8080/20141215-todoapp-java/Jouer avec l’application.Le client doit envoyer des requetes PUT et GET au serveur. Serveur qui trace tout dans la console.Sourceshttp://github.com/damienfremont/blog/tree/master/20141215-todoapp-javahttp://github.com/damienfremont/blog/tree/master/20141215-todoapp-javaReferenceshttp://www.vogella.com/articles/REST/article.htmlhttp://www.vogella.com/articles/REST/article.htmlhttp://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/http://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/http://mojo.codehaus.org/gwt-maven-plugin/user-guide/project.htmlhttp://mojo.codehaus.org/gwt-maven-plugin/user-guide/project.htmlhttp://mojo.codehaus.org/gwt-maven-plugin/user-guide/compile.htmlhttp://mojo.codehaus.org/gwt-maven-plugin/user-guide/compile.htmlOriginhttps://damienfremont.com/2014/12/17/todo-list-exemple-full-java-avec-gwt-tomcat-jersey/",
        "url": "/2014/12/17/todo-list-exemple-full-java-avec-gwt-tomcat-jersey"
      },
    
      "2014-12-15-todo-list-exemple-full-javascript-avec-angularjs-nodejs-express": {
        "title": "Todo List Exemple Full Javascript Avec Angularjs Nodejs Express",
        "author": "",
        "category": "",
        "tags": "angularjs, expressjs, javascript, nodejs",
        "content": "Ce tutoriel est le dev d’une simple TODO list de type client-serveur (front-end + back-end). Le but est d’utiliser une stack technique complète en JavaScript pour comparer avec d’autres technologies.EnvironnementeclipsenodeclipseEn DEV : un IDE eclipse avec le plugin nodeclipse d’installé via le menu marketplace d’eclipse. Avoir aussi un NodeJS et son npm Express.todomvc.comangularjsEn RUN : le front-end se base sur le site todomvc.com via l’exemple angularjs. Le back-end en plus est un NodeJS avec le serveur REST HTTP de Express.La structure (classique) est composé d’un MVC coté front et d’un service REST coté back :  Front Model View Controler  Back Service RepositoryCodegithub iciRécupérer le code à partir de github ici.La partie back se présente avec un fichier de conf, une app et des routes :package.json (conf)Faire un clique droit sur le fichier package.json pour lancer une commande Run As Npm Install. Afin d’installer les dépendances nécessaires dans le projet eclipse.{  &amp;amp;amp;quot;name&amp;amp;amp;quot;: &amp;amp;amp;quot;20141214-todoapp-javascript&amp;amp;amp;quot;,  &amp;amp;amp;quot;version&amp;amp;amp;quot;: &amp;amp;amp;quot;0.0.1&amp;amp;amp;quot;,  &amp;amp;amp;quot;private&amp;amp;amp;quot;: true,  &amp;amp;amp;quot;scripts&amp;amp;amp;quot;: {    &amp;amp;amp;quot;start&amp;amp;amp;quot;: &amp;amp;amp;quot;node app.js&amp;amp;amp;quot;  },  &amp;amp;amp;quot;dependencies&amp;amp;amp;quot;: {    &amp;amp;amp;quot;express&amp;amp;amp;quot;: &amp;amp;amp;quot;3.2.6&amp;amp;amp;quot;,    &amp;amp;amp;quot;jade&amp;amp;amp;quot;: &amp;amp;amp;quot;*&amp;amp;amp;quot;  }}app.jsC’est le point central du server. Il contient les dépendances, la config et le démarrage./** * Module dependencies. */ var express = require('express') , todoRepository = require('./routes/todoRepository') , todoService = require('./routes/todoService') , http = require('http') , path = require('path'); var app = express(); // all environmentsapp.set('port', process.env.PORT || 3000);app.use(express.logger('dev'));app.use(express.bodyParser());app.use(express.methodOverride());app.use(app.router);app.use(express.static(path.join(__dirname, 'public'))); // development onlyif ('development' == app.get('env')) { app.use(express.errorHandler());} // rest serverapp.get('/api/todos', todoService.list);app.put('/api/todos', todoService.save); // starthttp.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port'));});todoService.jsContient le service et l’accès au données suite aux appels REST.var repository = require('./todoRepository'); exports.list = function(req, res) {    res.send(repository.findAll());}; exports.save = function(req, res) {    console.log(req.body);    res.send(repository.updateAll(req.body));};DemoLancer le serverVérifier les logshttp://localhost:3000/api/todosTester sur L’URL du backhttp://localhost:3000/api/todoshttp://localhost:3000/index.html#/Tester sur L’URL du fronthttp://localhost:3000/index.html#/Jouer avec l’application.Le client doit envoyer des requetes PUT et GET au serveur. Serveur qui trace tout dans la console.PS : en cas d’erreur lors de npm install, tenter la commandenpm install -g expressSourceshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20141214-todoapp-javascripthttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20141214-todoapp-javascriptReferenceshttp://todomvc.com/architecture-examples/angularjshttp://todomvc.com/architecture-examples/angularjshttp://docs.angularjs.org/tutorial/step_11http://docs.angularjs.org/api/ngResource.$resourcehttp://docs.angularjs.org/tutorial/step_11http://docs.angularjs.org/api/ngResource.$resourcehttp://openclassrooms.com/courses/des-applications-ultra-rapides-avec-node-jshttp://openclassrooms.com/courses/des-applications-ultra-rapides-avec-node-jsOriginhttps://damienfremont.com/2014/12/15/todo-list-exemple-full-javascript-avec-angularjs-nodejs-express/",
        "url": "/2014/12/15/todo-list-exemple-full-javascript-avec-angularjs-nodejs-express"
      },
    
      "2013-09-14-springbatch-xml-config-helloworld-repeat-example": {
        "title": "Springbatch Xml Config Helloworld Repeat Example",
        "author": "",
        "category": "",
        "tags": "java, spring",
        "content": "In Java, the development of batch can be achieved with few solutions. Most applications use SpringBatch. This is the SpringBatch framework with its XML configuration that is used here. Another example with the configuration JavaConfig follow.The focus of this tutorial is to develop a batch that will perform an “HelloWorld” task as many times as requested (value specify in argument content).1. How it works?JobExecution jobExecution = jobLauncherTestUtils.launchJob(    new JobParametersBuilder().addLong(\"execution.times\", 10L).toJobParameters()  // exec 10 times);2. Demo (console output)...sept. 14, 2013 5:10:17 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 runINFO: Job: [FlowJob: [name=helloWorldJob]] launched with the following parameters: [{execution.times=10}]sept. 14, 2013 5:10:17 PM org.springframework.batch.core.job.SimpleStepHandler handleStepINFO: Executing step: [helloWorldStep]Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!sept. 14, 2013 5:10:17 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 runINFO: Job: [FlowJob: [name=helloWorldJob]] completed with the following parameters: [{execution.times=10}] and the following status: [COMPLETED]2. ImplementationHelloWorldReader.javapackage com.dfremont.blog; import org.springframework.batch.item.ItemReader;import org.springframework.batch.item.ParseException;import org.springframework.batch.item.UnexpectedInputException; /** * reads as many times as there are executionTimes. */public class HelloWorldReader implements ItemReader&lt;Object&gt; {     private int executionTimes;     public void setExecutionTimes(String newValue) {        executionTimes = Integer.valueOf(newValue);    }     public Object read() throws Exception, UnexpectedInputException,            ParseException {        Object o = null;        if (executionTimes &gt; 0) {            executionTimes--;            o = new Object();        }        return o;    }}HelloWorldWriter.javapackage com.dfremont.blog; import java.util.List;import org.springframework.batch.item.ItemWriter; /** * Task to repeat (helloworld). */public class HelloWorldWriter implements ItemWriter&lt;Object&gt; {     public void write(List&lt;? extends Object&gt; arg0) throws Exception {        System.out.println(\"Hello World!\");    } }applicationContext.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;beans:beans xmlns=\"http://www.springframework.org/schema/batch\"    xmlns:beans=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.0.xsd\"&gt;     &lt;beans:bean id=\"jobRepository\"        class=\"org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean\"&gt;        &lt;beans:property name=\"transactionManager\" ref=\"transactionManager\" /&gt;    &lt;/beans:bean&gt;     &lt;beans:bean id=\"jobLauncher\"        class=\"org.springframework.batch.core.launch.support.SimpleJobLauncher\"&gt;        &lt;beans:property name=\"jobRepository\" ref=\"jobRepository\" /&gt;    &lt;/beans:bean&gt;     &lt;beans:bean id=\"transactionManager\"        class=\"org.springframework.batch.support.transaction.ResourcelessTransactionManager\" /&gt;&lt;/beans:beans&gt;simpleJob.xml&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;&lt;beans:beans xmlns=\"http://www.springframework.org/schema/batch\"    xmlns:beans=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"    xsi:schemaLocation=\"http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.0.xsdhttp://www.springframework.org/schema/batchhttp://www.springframework.org/schema/batch/spring-batch-2.1.xsd\"&gt;     &lt;beans:import resource=\"applicationContext.xml\" /&gt;     &lt;job id=\"helloWorldJob\" job-repository=\"jobRepository\"&gt;        &lt;!-- Job validator --&gt;        &lt;validator ref=\"helloWorldJobParametersValidator\" /&gt;         &lt;step id=\"helloWorldStep\"&gt;            &lt;tasklet&gt;                &lt;chunk reader=\"helloWorldReader\" writer=\"helloWorldWriter\"                    commit-interval=\"0\"&gt;                &lt;/chunk&gt;            &lt;/tasklet&gt;        &lt;/step&gt;    &lt;/job&gt;     &lt;beans:bean id=\"helloWorldJobParametersValidator\"        class=\"org.springframework.batch.core.job.DefaultJobParametersValidator\"&gt;        &lt;beans:property name=\"requiredKeys\" value=\"execution.times\" /&gt;    &lt;/beans:bean&gt;     &lt;beans:bean name=\"helloWorldReader\" class=\"com.dfremont.blog.HelloWorldReader\"        scope=\"step\"&gt;        &lt;beans:property name=\"executionTimes\"            value=\"#{jobParameters['execution.times']}\" /&gt;    &lt;/beans:bean&gt;     &lt;beans:bean name=\"helloWorldWriter\" class=\"com.dfremont.blog.HelloWorldWriter\"&gt;    &lt;/beans:bean&gt;     &lt;!-- To run the job from the command line type the following: mvn exec:java        -Dexec.mainClass=org.springframework.batch.core.launch.support.CommandLineJobRunner        -Dexec.args=\"simpleJob.xml helloWorldJob\" --&gt;&lt;/beans:beans&gt;View source code and more testshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20130914-springbatch-xmlconfighttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20130914-springbatch-xmlconfigOriginhttps://damienfremont.com/2013/09/14/springbatch-xml-config-helloworld-repeat-example/",
        "url": "/2013/09/14/springbatch-xml-config-helloworld-repeat-example"
      },
    
      "2013-09-13-java-batch-simple-helloworld-repeat-example": {
        "title": "Java Batch Simple Helloworld Repeat Example",
        "author": "",
        "category": "",
        "tags": "java",
        "content": "In Java, the development of batch can be achieved with few solutions. Most applications use their own code from scratch. Here’s a quick example of full java batch, without any external dependecy.Without using any Framework, you need to develop every time the same parts of the batch: arg validation, batch processing, and error handling. Another example with the SpringBatch follow.The focus of this tutorial is to develop a batch that will perform an “HelloWorld” task as many times as requested (value specify in argument content).1. How it works?HelloWorldBatch.main(    new String[] { \"10\" } // exec 10 times);2. Demo (console output)Executing batchinput args okExecuting jobHello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Ending job (success)Ending batch3. ImplementationHelloWorldBatch.javapackage com.dfremont.blog; public class HelloWorldBatch {     public static void main(String[] args) {        System.out.println(\"Executing batch\");         // arg validation        if (args != null &amp;&amp; args.length == 1 &amp;&amp; args[0] != null) {            System.out.println(\"input args ok\");        } else {            System.out.println(\"Error with input args\");            throw new IllegalArgumentException(\"Error with input args\");        }         // batch processing        try {            System.out.println(\"Executing job\");            for (int i = 0; i &lt; Integer.valueOf(args[0]); i++) {                 // task to repeat                System.out.println(\"Hello World!\");            }            System.out.println(\"Ending job (success)\");        } catch (Exception e) {             // error handling            System.out.println(\"Error during job (failure)\");            System.out.println(e.getMessage());            throw new RuntimeException(\"Error during task (failure)\", e);        }        System.out.println(\"Ending batch\");    } }View source code and more testshttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20130913-javabatch-helloworldhttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20130913-javabatch-helloworldOriginhttps://damienfremont.com/2013/09/13/java-batch-simple-helloworld-repeat-example/",
        "url": "/2013/09/13/java-batch-simple-helloworld-repeat-example"
      },
    
      "2013-07-25-new-batch-implementation": {
        "title": "New Batch Implementation",
        "author": "",
        "category": "",
        "tags": "java",
        "content": "You’re tired of spring batch? the future JavaEE batch API  leaves you cold?I’m trying to make a basic implementation of batch, not dependent on any framework and compatible with SpringBatch extensions (if needed) and with the same service quality (batch structure, extensions like jdbc, jpa, file, message, etc).It’s called SimpleBatch and it’s very cool indeed. With future fluent API.if you have any need, or advice, please visit my GitHub project or post a comment here.https://github.com/damienfremont/simplebatch",
        "url": "/2013/07/25/new-batch-implementation"
      },
    
      "2013-04-09-tutorials-available-on-github": {
        "title": "Tutorials Available On Github",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Java projects for each posts are now available on my GitHub account !You only need to import the Git repository from https://github.com/damienfremont/dfremont-blog and use the projects with Maven. And if in any case you are interested in my account, it’s here https://github.com/damienfremont",
        "url": "/2013/04/09/tutorials-available-on-github"
      },
    
      "2013-04-08-some-readings": {
        "title": "Some Readings",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "Here are some, well known, books that I think are useful … at least they were for me! Some are about Java or JavaEE, other Object Oriented Programming.",
        "url": "/2013/04/08/some-readings"
      },
    
      "2012-02-27-from-junit-to-junit4": {
        "title": "From Junit To Junit4",
        "author": "",
        "category": "",
        "tags": "java, junit, test",
        "content": "A post about simple JUnit tests. Unit testing is necessary, but reduce its volume (source test) is always interresting … it reduces development and maintenance tasks (code analyzer tools are your best friends). We need tools : a code analyzer : PMD, and … a testing framework : JUnit.We will do the following steps :  write an old-fashion JUnit3 test class  use JUnit4 new features  apply PMD on it  rewrite the testThis is the Class-to-test : a simple class providing a “divide()” method, and sometimes it throws an ArithmeticException ! (will test it)package com.dfremont.blog; public class ClassToTest {     public int divide(final int argValue, final int argDivider) {        if (argDivider == 0) {            throw new ArithmeticException(\"Division by zero prohibited!\");        }        return (argValue / argDivider);    }}And now, some test classes !1st iteration, write an old-fashion JUnit3 test classpackage com.dfremont.blog; import junit.framework.TestCase; public class JUnit3Test extends TestCase {     public void testDivide() {        // Arrange        ClassToTest classToTest = new ClassToTest();        int param1 = 10;        int param2 = 2;        // Act        int result = classToTest.divide(param1, param2);        // Assert        assertEquals(\"ok\", 5, result);    }     public void testDivideValueWith0() {        // Arrange        ClassToTest classToTest = new ClassToTest();        int param1 = 10;        int param2 = 0;        // Act        try {            classToTest.divide(param1, param2);            fail(\"expected error!\");        } catch (ArithmeticException e) {            // Assert            assertEquals(\"Division by zero prohibited!\", e.getMessage());        }    }}Very simple to read/understand, but it smells very bad :PROS : compartmented testsCONS : “Arrange” section fails to clarify the test. The “try/catch” is verbose, and dangerous if you forgot to put a fail() in your try clause. Because if the method call doesn’t fail, the test is still at succes status (despite the fact that we want to assert the opposite)2nd iteration, apply JUnit4 it.package com.dfremont.blog; import static org.junit.Assert.assertEquals; import org.junit.Test; public class JUnit4Step4NewFeaturesTest {     private static ClassToTest classToTest = new ClassToTest();     @Test    public void testDivideValue() {        // Act        final int result = classToTest.divide(10, 2);        // Assert        assertEquals(\"Result wrong value!\", 5, result);    }     @Test(expected = ArithmeticException.class)    public void testDivideValueWith0() {        // Act        classToTest.divide(10, 0);    }}Shorter …Try/catch gone, but unreadable to such a simple case. and it’s not shorter !PROS: cleanCONS: but no line recovered3rd iteration, use JUnit4 new features&lt;/pre&gt;package com.dfremont.blog; import static org.junit.Assert.assertEquals; import org.junit.Rule;import org.junit.Test;import org.junit.rules.ExpectedException; public class JUnit4Step3NewFeaturesTest {     private static ClassToTest classToTest = new ClassToTest();     @Rule    public final ExpectedException exception = ExpectedException.none();     @Test    public void testDivideValue() {        // Act        final int result = classToTest.divide(10, 2);        // Assert        assertEquals(\"Result wrong value!\", 5, result);    }     @Test    public void testDivideValueWith0() {        // Arrange        exception.expect(ArithmeticException.class);        exception.expectMessage(\"Division by zero prohibited!\");        // Act        classToTest.divide(10, 0);    }}&lt;pre&gt;Try/catch gone, but unreadable to such a simple case. and it’s not shorter !PROS: cleanCONS: but no line recoveredConclusionWhy so much effort? To reduce code size …but above all, to make each line of code so indispensable, that the developer maintaining this code and can not introduce regressions in these tests.For example, by commenting “dispensable” sections :package com.dfremont.blog; import org.junit.Test; public class JUnit4WrongTest {     @Test    @SuppressWarnings(\"unused\")    public void testDivideValue() {        // Arrange        ClassToTest classToTest = new ClassToTest();        int param1 = 10;        int param2 = 2;        // Act        int result = classToTest.divide(param1, param2);        // Assert        // assertEquals(5, result);    }     @Test    public void testDivideValueWith0() {        // Arrange        ClassToTest classToTest = new ClassToTest();        int param1 = 10;        int param2 = 0;        // Act        try {            classToTest.divide(param1, param2);            // fail(\"Expected error!\");        } catch (ArithmeticException e) {            // Assert            // assertEquals(\"Wrong Exc msg!\", \"Division by zero prohibited!\",            // e.getMessage());        }    }}View source codehttps://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20120227-junit3_to_junit4https://github.com/DamienFremont/damienfremont.com-blog-labs/tree/master/20120227-junit3_to_junit4Originhttps://damienfremont.com/2012/02/27/from-junit-to-junit4/",
        "url": "/2012/02/27/from-junit-to-junit4"
      },
    
      "2012-02-02-website-open": {
        "title": "Website Open",
        "author": "",
        "category": "",
        "tags": "other",
        "content": "The purpose of this blog? Aggregate some feedbacks, about Java and tools used to produce applications.Comming soon : tutorials (and more).",
        "url": "/2012/02/02/website-open"
      }
    
}