diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..67a85520e87ea07fe850898c49e8e2d17f048066
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+json-utility
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..0310e9fbba9d3c113a2a53916c09b450a5cf2ac7
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,5 @@
+FROM golang:1.16.2-buster
+WORKDIR .
+COPY . .
+RUN make build
+RUN make build file=example.json
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..2a586d60038879687dd20f90977af0b719d20703
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Ivanov, Ivan (UG - Computer Science)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..432a791044157129c35edd891e8c0550078107f0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,6 @@
+build:
+	go get
+run:
+	go run . $(mode) $(file)
+test:
+	go test
\ No newline at end of file
diff --git a/README.md b/README.md
index 391b083923e35535161a0d7536e2ad3745912970..3fc22dc4939ad77cee9008bd420414f96339051f 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,18 @@
-# json-utility
+# JSON Utility
+## Usage
+```
+$ make build
+$ make run mode=TEST file=example.json #TESTING WITH LOCAL FILE. Where example.json is the file we want to process
+$ make run mode=CONTAINER #RUN AS REST API. 
+```
 
+## Testing
+```
+$ make test
+```
+## Discussion
+- Designing the solution is made based on the assumption that the load will be a
+JSON file containing an array of all the entries needed to perform the calculations.
+
+## Dependencies
+- You'd need to have GOPATH exported.  GOBIN for MACOS for go get command
\ No newline at end of file
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/example.json b/example.json
index 8d7ccf38535c60585a8d8f8eca202b55cab2bcb7..4c887006a34d8220c203731c7f03ded3d6d9e54b 100644
--- a/example.json
+++ b/example.json
@@ -2,7 +2,7 @@
     {
         "userid": "user1",
         "url": "http://www.someamazingwebsite.com/1",
-        "type": "GET",
+        "type": "POST",
         "timestamp": 1360662163000
     },
     {
@@ -13,7 +13,7 @@
     },
     {
         "userid": "user2",
-        "url": "http://www.someamazingwebsite.com/3",
+        "url": "http://www.someamazingwebsite.com/1",
         "type": "GET",
         "timestamp": 1360662163000
     },
@@ -25,8 +25,8 @@
     },
     {
         "userid": "user2",
-        "url": "http://www.someamazingwebsite.com/2",
-        "type": "GET",
+        "url": "http://www.someamazingwebsite.com/3",
+        "type": "POST",
         "timestamp": 1360462163000
     }
 ]
\ No newline at end of file
diff --git a/handlers.go b/handlers.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ff70b0d22719e2997c3b5a10a3f35a24cf9a851
--- /dev/null
+++ b/handlers.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"encoding/json"
+	"log"
+	"net/http"
+	"os"
+	"sync"
+)
+
+//Handles opens the JSON file and calls extractJSON to parse
+//the data passed as file. Returns the result as a struct.
+func Handles(argument string) (urls *Links, err error) {
+	jsonFile, err := os.Open(argument)
+	if err != nil {
+		log.Println(err)
+		return nil, err
+	}
+	log.Println("Successfully Opened", argument)
+	//Close when done.
+	defer jsonFile.Close()
+	payload := ExctractJSON(jsonFile)
+	result := ProcessJson(payload)
+	return result, err
+}
+
+//Web handler for requests containing JSON input.
+func Index(w http.ResponseWriter, r *http.Request) {
+	decoder := json.NewDecoder(r.Body)
+	var loads []Load
+
+	err := decoder.Decode(&loads)
+	if err != nil {
+		panic(err)
+	}
+
+	result := ProcessJson(loads)
+	WriteResult(w, result)
+}
+
+//Preocessing the JSON as a whole array.
+func ProcessJson(loads []Load) (links *Links) {
+	visited := Links{URL: make(map[string]*Dates)}
+
+	wg := new(sync.WaitGroup)
+
+	for _, load := range loads {
+		if load.TypeRequest != "GET" {
+			log.Println("Request is invalid: ", load.TypeRequest)
+			continue
+		}
+		wg.Add(1)
+		go ProcessLoad(&visited, load, wg)
+
+	}
+	wg.Wait()
+	return &visited
+}
diff --git a/handlerstest.go b/handlerstest.go
new file mode 100644
index 0000000000000000000000000000000000000000..69bd69cd781496426c5af0f3f47c0a044a675934
--- /dev/null
+++ b/handlerstest.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"testing"
+)
+
+/*
+Standard assert Equals function
+*/
+func assertEqual(t *testing.T, a interface{}, b interface{}, message string) {
+	if a == b {
+		return
+	}
+	if len(message) == 0 {
+		message = fmt.Sprintf("%v != %v", a, b)
+	}
+	t.Fatal(message)
+}
+
+/*
+Testing with sample JSON tha websites are visited.
+*/
+func TestWebsites(t *testing.T) {
+	result, err := Handles("test/test-websites.json")
+	if err != nil {
+		log.Println(err)
+		return
+	}
+
+	assertEqual(t, len(result.URL), 1, "")
+}
+
+/*
+Testing if a user visits one URL multiple times but in
+different days if it's still going to add it.
+*/
+func TestWebsites2(t *testing.T) {
+	result, err := Handles("test/test-websites2.json")
+	if err != nil {
+		log.Println(err)
+		return
+	}
+	assertEqual(t, len(result.URL), 1, "")
+}
+
+/*
+Testing if each date gets added. Basic case. 1 user visits 1 page on
+2 different dates. 2 Dates should be returned. Also checks if POST
+requests get dropped.
+*/
+func TestDates(t *testing.T) {
+	result, err := Handles("test/test-dates.json")
+	if err != nil {
+		log.Println(err)
+		return
+	}
+	assertEqual(t, len(result.URL["http://www.someamazingwebsite.com/1"].Date), 2, "")
+}
+
+/*
+Testing if each date gets added. Advaced case. 3 user visits 2 page on
+3 different dates. 2 Dates should be returned for each website.
+*/
+func TestDates2(t *testing.T) {
+	result, err := Handles("test/test-dates2.json")
+	if err != nil {
+		log.Println(err)
+		return
+	}
+	assertEqual(t, len(result.URL["http://www.someamazingwebsite.com/1"].Date), 2, "")
+	assertEqual(t, len(result.URL["http://www.someamazingwebsite.com/2"].Date), 2, "")
+}
diff --git a/json-utility b/json-utility
new file mode 100755
index 0000000000000000000000000000000000000000..0347b29c76a60301c422e545efda95c73a1d895d
Binary files /dev/null and b/json-utility differ
diff --git a/main.go b/main.go
index eba4f1321bb5e3908de9fa594f08477869ba4cff..2182a257528aeacdb0d8b5b1cdff1b77c1a4ab8b 100644
--- a/main.go
+++ b/main.go
@@ -1,116 +1,58 @@
-/*
-Example payload:
-userid: A unique ID representing the user
-url : The URL the visitor has accessed
-type: The HTTP method used to access the URL
-timestamp: The timestamp for when the action occurred
-*/
+// Package implments JSON parser utility to process a stream of JSON messages
+// and calculate the number of unique viewers per day for each URL in the stream.
 package main
 
 import (
-	"encoding/json"
 	"log"
 	"net/http"
-	"time"
+	"os"
+	"sync"
 
 	"github.com/gorilla/mux"
 )
 
 type Load struct {
 	Userid      string `json:"userid"`
-	Url         string `json:"url"`
+	URL         string `json:"url"`
 	TypeRequest string `json:"type"`
 	Timestamp   int64  `json:"timestamp"`
 }
 
-type Dates struct {
-	Exists map[string]*URLs
+type Links struct {
+	URL map[string]*Dates //map holding all the Dates a certain URL is visited
+	mux sync.RWMutex      //mutex for race condition
 }
-type URLs struct {
-	Exists map[string]*URL
+type Dates struct {
+	Date map[string]*Visits //map holding all visits for certain date
 }
 
-type URL struct {
-	Counter int
-	UserIds map[string]bool
+type Visits struct {
+	mux     sync.RWMutex    //mutex for race condition
+	Counter int             //Counter for unique visits
+	UserIds map[string]bool //map holding different user ids
 }
 
 func main() {
-
-	router := mux.NewRouter().StrictSlash(true)
-	router.HandleFunc("/", Index)
-
-	log.Fatal(http.ListenAndServe(":8080", router))
-}
-
-func Index(w http.ResponseWriter, r *http.Request) {
-	decoder := json.NewDecoder(r.Body)
-
-	var loads []Load
-	dates := Dates{Exists: make(map[string]*URLs)}
-
-	err := decoder.Decode(&loads)
-	if err != nil {
-		panic(err)
-	}
-
-	for _, load := range loads {
-		if load.TypeRequest != "GET" {
-			log.Println("Request is invalid")
-			continue
+	if os.Args[1] == "CONTAINER" {
+		router := mux.NewRouter().StrictSlash(true)
+		router.HandleFunc("/", Index)
+		log.Fatal(http.ListenAndServe(":8080", router))
+	} else {
+		//Check if the usage of the script has been correct.
+		if len(os.Args) != 3 {
+			log.Println("USAGE: ./json-utility [mode] [path/to/file]")
+			return
 		}
 
-		var t string
-
-		if time.Now().UnixNano() > load.Timestamp {
-			t = time.Unix(load.Timestamp/1000, 0).Format("2006-01-02")
-		} else {
-			t = time.Unix(load.Timestamp/1000, 0).Format("2006-01-02")
+		//Get the result from a file.
+		result, err := Handles(os.Args[2])
+		if err != nil {
+			log.Println(err)
+			return
 		}
-		log.Println(t)
-		if site, ok := dates.Exists[t]; ok {
-			log.Println("Date exists.")
-
-			if url, ok := site.Exists[load.Url]; ok {
-				log.Println("URL exists.")
-				if url.UserIds[load.Userid] {
-					continue //Continue as the user has already visited that website for this day once.
-				} else {
-
-					url.Counter += 1
-					url.UserIds[load.Userid] = true
-					log.Println(url.Counter)
-				}
-			} else {
-				//Add the URL and a visit.
-				entry := URL{Counter: 0, UserIds: make(map[string]bool)}
 
-				entry.Counter += 1
-				entry.UserIds[load.Userid] = true
-				dates.Exists[t].Exists[load.Url] = &entry
-				log.Println("URL is added.")
-			}
-		} else {
-			log.Println("Date doesnt yet exist.")
-			//Initialising Date and Urls for that date.
-			entry := URL{Counter: 0, UserIds: make(map[string]bool)}
-			urls := URLs{Exists: make(map[string]*URL)}
-
-			entry.Counter += 1
-			entry.UserIds[load.Userid] = true
-			urls.Exists[load.Url] = &entry
-			dates.Exists[t] = &urls
-			log.Println("We added it though")
-		}
-		log.Println(dates)
-		//fmt.Fprintf(w, "%q", json.NewEncoder(w).Encode(load))
+		//Print the result
+		PrintResult(result)
 	}
 
-	// loop over elements of slice
-	for k, v := range dates.Exists {
-		// m is a map[string]interface.
-		// loop over keys and values in the map.
-		log.Println(k, "value is", v)
-
-	}
 }
diff --git a/process.go b/process.go
new file mode 100644
index 0000000000000000000000000000000000000000..30f970d0fddbe7d36bf045b2726db244391afc3e
--- /dev/null
+++ b/process.go
@@ -0,0 +1,73 @@
+package main
+
+import (
+	"log"
+	"sync"
+	"time"
+)
+
+//Process handles processing a load given by
+func ProcessLoad(visited *Links, load Load, wg *sync.WaitGroup) {
+	//Notify main that this routine is done.
+	defer wg.Done()
+	//Time should be accepted both in epoch milliseconds or seconds.
+	var t string
+	if time.Now().UnixNano() > load.Timestamp {
+		t = time.Unix(load.Timestamp/1000, 0).Format("2006-01-02")
+	} else {
+		t = time.Unix(load.Timestamp, 0).Format("2006-01-02")
+	}
+
+	visited.mux.Lock()
+
+	if date, ok := visited.URL[load.URL]; ok {
+		log.Println("URL exists.")
+		if visit, ok := date.Date[t]; ok {
+			log.Println("Date exists.")
+			if visit.UserIds[load.Userid] {
+				visited.mux.Unlock()
+				return //Return as the user has already visited that website for this day once.
+			} else {
+
+				visit.mux.Lock()
+				visit.Counter += 1
+				visit.UserIds[load.Userid] = true
+
+				visited.mux.Unlock()
+				visit.mux.Unlock()
+				return
+			}
+		} else {
+			//Add the Date and a Visit.
+			entry := Visits{Counter: 0, UserIds: make(map[string]bool)}
+			entry.mux.Lock()
+			entry.Counter += 1
+			entry.UserIds[load.Userid] = true
+			entry.mux.Unlock()
+
+			visited.URL[load.URL].Date[t] = &entry
+			visited.mux.Unlock()
+
+			log.Println("Date and Visit are added.")
+			return
+		}
+	} else {
+		log.Println("URL doesn't exist.")
+		//Initialising URL, date and visits for that date.
+
+		entry := Visits{Counter: 0, UserIds: make(map[string]bool)}
+		entry.mux.Lock()
+
+		dates := Dates{Date: make(map[string]*Visits)}
+
+		entry.Counter += 1
+		entry.UserIds[load.Userid] = true
+		entry.mux.Unlock()
+
+		dates.Date[t] = &entry
+
+		visited.URL[load.URL] = &dates
+		visited.mux.Unlock()
+		return
+	}
+}
diff --git a/test/test-dates.json b/test/test-dates.json
new file mode 100644
index 0000000000000000000000000000000000000000..28c515146fae92b8b942e052705e013b05d8c9bb
--- /dev/null
+++ b/test/test-dates.json
@@ -0,0 +1,14 @@
+[
+    {
+        "userid": "user1",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1360662163000
+    },
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1160165163000
+    }
+]
\ No newline at end of file
diff --git a/test/test-dates2.json b/test/test-dates2.json
new file mode 100644
index 0000000000000000000000000000000000000000..5da1d9ae8425699ab0361253bd274b447df6c78f
--- /dev/null
+++ b/test/test-dates2.json
@@ -0,0 +1,38 @@
+[
+    {
+        "userid": "user1",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1360662163000
+    },
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/3",
+        "type": "GET",
+        "timestamp": 1160165163000
+    },
+    {
+        "userid": "user3",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1358122163000
+    },
+    {
+        "userid": "user1",
+        "url": "http://www.someamazingwebsite.com/2",
+        "type": "GET",
+        "timestamp": 1360662163000
+    },
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/2",
+        "type": "GET",
+        "timestamp": 1160165163000
+    },
+    {
+        "userid": "user3",
+        "url": "http://www.someamazingwebsite.com/2",
+        "type": "GET",
+        "timestamp": 1358122163000
+    }
+]
\ No newline at end of file
diff --git a/test/test-websites.json b/test/test-websites.json
new file mode 100644
index 0000000000000000000000000000000000000000..8a309917ca5683922e50cf7b4e2e2cc1f44678cc
--- /dev/null
+++ b/test/test-websites.json
@@ -0,0 +1,14 @@
+[
+    {
+        "userid": "user1",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "POST",
+        "timestamp": 1360662163000
+    },
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1360662163000
+    }
+]
\ No newline at end of file
diff --git a/test/test-websites2.json b/test/test-websites2.json
new file mode 100644
index 0000000000000000000000000000000000000000..7b115afa06147f4213136aec7db9ec250e71694e
--- /dev/null
+++ b/test/test-websites2.json
@@ -0,0 +1,21 @@
+[
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1360662163000
+    },
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1360662163000
+    },
+    {
+        "userid": "user2",
+        "url": "http://www.someamazingwebsite.com/1",
+        "type": "GET",
+        "timestamp": 1310666163000
+    }
+
+]
\ No newline at end of file
diff --git a/utils.go b/utils.go
new file mode 100644
index 0000000000000000000000000000000000000000..cd45c4ee1d6886629bec4fc3f24562a0e5904082
--- /dev/null
+++ b/utils.go
@@ -0,0 +1,45 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"os"
+)
+
+//Prints the results for a given structure containing already processed Links.
+func PrintResult(result *Links) {
+	for k, v := range result.URL {
+		log.Println("For URL: ", k)
+		for m, x := range v.Date {
+			log.Println("↳", m, "there are:", x.Counter, "unique visits.")
+		}
+	}
+}
+
+//Function for returning response to the user if the code runs in container
+//as an API
+func WriteResult(w http.ResponseWriter, result *Links) {
+	for k, v := range result.URL {
+		fmt.Fprintf(w, "For URL, %v\n", k)
+		log.Println("For URL: ", k)
+		for m, x := range v.Date {
+			fmt.Fprintf(w, "↳%v there are: %v unique visits.\n", m, x.Counter)
+			log.Println("↳", m, "there are:", x.Counter, "unique visits.")
+		}
+	}
+}
+
+//Extracts JSON payload and calls Process to handle the data.
+func ExctractJSON(file *os.File) (load []Load) {
+	d := json.NewDecoder(file)
+
+	var loads []Load
+
+	err := d.Decode(&loads)
+	if err != nil {
+		log.Panic(err)
+	}
+	return loads
+}