import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ConcurrentHashMap;

import static spark.Spark.*;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.philihp.weblabora.model.*;
import org.apache.commons.codec.binary.Hex;

public class Main {

  private static ObjectMapper objectMapper = new ObjectMapper();

  private static ConcurrentHashMap<String, String> cache = new ConcurrentHashMap<>();

  public static void main(String[] args) {

    port(Integer.valueOf(System.getenv("PORT")));

    get("/:hash", "application/json", (request, response) -> {
      String hash = request.params(":hash");
      return cache.get(hash);
    });

    put("/", "application/json", (request, response) -> {
      String hash = hash(request.body());
      if(!cache.contains(hash)) {
        Board board = new Board();
        String[] tokens = request.body().split("\n+");
        for (String token : tokens) {
          MoveProcessor.processMove(board, token);
        }
        cache.put(hash, objectMapper.valueToTree(board).toString());
      }
      response.redirect("/" + hash, 303);
      return null;
    });

  }

  private static String hash(String contents) {
    try {
      MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
      messageDigest.update(contents.getBytes());
      return new String(Hex.encodeHex(messageDigest.digest())).substring(0,6);
    } catch (NoSuchAlgorithmException e) {
      return Integer.toString(contents.hashCode());
    }
  }

}

@@ -104,33 +104,24 @@
 current.
-ConcurrentHashMap
+TimeUnit
 ;%0A%0Aimpor
@@ -197,16 +197,99 @@
 Mapper;%0A
+import com.google.common.cache.Cache;%0Aimport com.google.common.cache.CacheBuilder;%0A
 import c
@@ -468,32 +468,20 @@
 static C
-oncurrentHashMap
+ache
 %3CString,
@@ -500,32 +500,129 @@
 he =
- new ConcurrentHashMap%3C%3E
+%0A      CacheBuilder.newBuilder()%0A        .maximumSize(100000)%0A        .expireAfterAccess(7, TimeUnit.DAYS)%0A        .build
 ();%0A
@@ -852,16 +852,134 @@
 get(hash
+, () -%3E %7B%0A        response.status(404);%0A        return %22%7B%5C%22error%5C%22:%5C%22Forgot state of board. Please retry.%5C%22%7D%22;%0A      %7D
 );%0A    %7D
@@ -1086,44 +1086,8 @@
 ));%0A
-      if(!cache.contains(hash)) %7B%0A  
     
@@ -1115,18 +1115,16 @@
 oard();%0A
-  
       St
@@ -1174,18 +1174,16 @@
 ;%0A      
-  
 for (Str
@@ -1200,26 +1200,24 @@
 : tokens) %7B%0A
-  
         Move
@@ -1259,26 +1259,24 @@
 ;%0A      
-  
 %7D%0A      
   cache.
@@ -1267,18 +1267,16 @@
 %7D%0A      
- 
- 
 cache.pu
@@ -1328,24 +1328,16 @@
 ing());%0A
-      %7D%0A
       re
@@ -1369,16 +1369,45 @@
 h, 303);
+ // very important to use 303
 %0A      r
@@ -1561,11 +1561,9 @@
 SHA-
-256
+1
 %22);%0A
@@ -1690,9 +1690,9 @@
 g(0,
-6
+8
 );%0A 

Save boards in an expirable cache