about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md51
-rw-r--r--bots/amaterasu.x86-32.asm35
-rw-r--r--bots/pancake.x86-32.asm7
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rwxr-xr-xrun.sh2
-rw-r--r--src/battle.go1043
-rw-r--r--src/bot.go21
-rw-r--r--src/db.go10
-rw-r--r--src/main.go25
-rw-r--r--src/r2.go3
-rw-r--r--src/user.go60
-rw-r--r--templates/battleNew.html45
-rw-r--r--templates/battleQuick.html57
-rw-r--r--templates/battleSingle.html355
-rw-r--r--templates/battles.html4
-rw-r--r--templates/botSingle.html16
-rw-r--r--templates/bots.html6
-rw-r--r--templates/footer.html1
-rw-r--r--templates/head.html30
-rw-r--r--templates/index.html12
-rw-r--r--templates/nav.html12
-rw-r--r--vendor/modules.txt2
24 files changed, 1442 insertions, 360 deletions
diff --git a/.gitignore b/.gitignore
index f0b11c5..1d306c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
 main.db
 sessions.db
 server.log
-
 result/
+.DS_Store
 
diff --git a/README.md b/README.md
index 525915d..558db4f 100644
--- a/README.md
+++ b/README.md
@@ -20,3 +20,54 @@ If you want to clone from git.emile.space, you can currently do so like this:
 git clone git://git.emile.space/r2wars-web.git
 git clone git://git.emile.space/hefe.git
 ```
+
+## Usage
+
+```
+; CGO_ENABLED=0 SESSION_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa go run ./src --help
+Usage of /var/folders/bt/2db5y4ds5yq2y9m29tt8g5dm0000gn/T/go-build1055665732/b001/exe/src:
+  -databasepath string
+    	The path to the main database (default "./main.db")
+  -h string
+    	The host to listen on (shorthand) (default "127.0.0.1")
+  -host string
+    	The host to listen on (default "127.0.0.1")
+  -logfilepath string
+    	The path to the log file (default "./server.log")
+  -p int
+    	The port to listen on (shorthand) (default 8080)
+  -port int
+    	The port to listen on (default 8080)
+  -sessiondbpath string
+    	The path to the session database (default "./sesions.db")
+  -templates string
+    	The path to the templates used (default "./templates")
+```
+
+## Architecture
+
+There are essentially the following objects which are all linked to each other (using a table joining their ids):
+
+- User
+  - You, the player
+- Bots
+  - The bots to be run within a battle
+- Battles
+  - An arena in which bots can be placed and run. Constraints on what bots can be added are defined here
+- Architectures
+  - The archs supported by r2 in order to be used by bots and battles
+- Bits
+  - The bits (8, 16, 32, 64) supported by r2 in order to be used by bots and battles
+
+## TODO
+
+- [ ] Add user creating battle as default owner
+- [ ] Allow adding other users as owners to battles
+- [x] Implement submitting bots
+- [x] Implement running the battle
+- [x] Add a "start battle now" button
+- [ ] Add a "battle starts at this time" field into the battle
+- [ ] Figure out how time is stored and restored with the db
+- [x] Do some magic to display the current fight backlog with all info
+- [ ] After having added a bot to a battle with the right arch, the arch can be changed
+      When updating the bot, make sure that it is still valid in all currently linked battles
diff --git a/bots/amaterasu.x86-32.asm b/bots/amaterasu.x86-32.asm
new file mode 100644
index 0000000..55d38df
--- /dev/null
+++ b/bots/amaterasu.x86-32.asm
@@ -0,0 +1,35 @@
+start:
+    mov ebp, 0x3e0
+    mov esp, 0x3e0
+    ; lea eax, [end + 0x20]
+    ; lea ebx, [start - 0x20]
+    mov eax, 0xffffffff
+    mov ebx, 0xffffffff
+    mov ecx, 0xffffffff
+    mov edx, 0xffffffff
+    mov edi, 0xffffffff
+    mov esi, 0xffffffff
+
+bot_loop:
+    ; cmp esp, eax
+    ; cmovbe esp, ebx
+
+    ; push 128 bytes at once
+    pushad
+    pushad
+    pushad
+    pushad
+
+    ; push again
+    pushad
+    pushad
+    pushad
+    pushad
+
+    ; jmp to beginning once again
+    cmp esp, 0x10
+    cmovz esp, ebp
+    jmp bot_loop
+
+end:
+    nop
\ No newline at end of file
diff --git a/bots/pancake.x86-32.asm b/bots/pancake.x86-32.asm
new file mode 100644
index 0000000..25eda04
--- /dev/null
+++ b/bots/pancake.x86-32.asm
@@ -0,0 +1,7 @@
+call rest
+rest:
+  pop esp
+rep:
+  add esp, 64
+  pusha
+  jmp rep
diff --git a/go.mod b/go.mod
index b897dd4..9a6722a 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,6 @@ require (
 	github.com/gorilla/securecookie v1.1.2
 	github.com/gorilla/sessions v1.3.0
 	github.com/radareorg/r2pipe-go v0.2.1
-	github.com/xiaoqidun/entps v1.32.0
 	golang.org/x/crypto v0.26.0
 	modernc.org/sqlite v1.32.0
 )
diff --git a/go.sum b/go.sum
index 5022658..6ba4f7d 100644
--- a/go.sum
+++ b/go.sum
@@ -28,8 +28,6 @@ github.com/radareorg/r2pipe-go v0.2.1 h1:2bVIi7qHPQCdjjngcJbQO2VHSqPaRBt5LUAMk2u
 github.com/radareorg/r2pipe-go v0.2.1/go.mod h1:HNUWNjS7SjzhZ7McDLhvIBSOLz1X9DNLjj4J52pAj3Y=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
-github.com/xiaoqidun/entps v1.32.0 h1:shF2tBvry0F0wYlqeWpj7SUbq6fYS6cmHGDp5ZShKqg=
-github.com/xiaoqidun/entps v1.32.0/go.mod h1:42K0gnlDRuO4sc5GWmpFXz40kB81LjabFu/kK9BzKXI=
 golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
 golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
 golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
diff --git a/run.sh b/run.sh
index 64b35c5..fea0921 100755
--- a/run.sh
+++ b/run.sh
@@ -1,3 +1,3 @@
 set +e
 
-CGO_ENABLED=0 SESSION_KEY=aes1Itheich4aeQu9Ouz7ahcaiVoogh9 go run ./... -h ""
+CGO_ENABLED=0 SESSION_KEY=aes1Itheich4aeQu9Ouz7ahcaiVoogh9 go run ./src
diff --git a/src/battle.go b/src/battle.go
index 7aa949a..af7043b 100644
--- a/src/battle.go
+++ b/src/battle.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"html/template"
 	"log"
+	"math/rand"
 	"net/http"
 	"os"
 	"strconv"
@@ -11,16 +12,20 @@ import (
 	"time"
 
 	"github.com/gorilla/mux"
+	"github.com/radareorg/r2pipe-go"
 )
 
 type Battle struct {
-	ID     int
-	Name   string
-	Bots   []Bot
-	Owners []User
-	Public bool
-	Archs  []Arch
-	Bits   []Bit
+	ID        int
+	Name      string
+	Bots      []Bot
+	Owners    []User
+	Public    bool
+	Archs     []Arch
+	Bits      []Bit
+	RawOutput string
+	MaxRounds int
+	ArenaSize int
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -30,14 +35,18 @@ func BattleGetAll() ([]Battle, error) {
 	return globalState.GetAllBattles()
 }
 
-func BattleCreate(name string, public bool) (int, error) {
-	return globalState.InsertBattle(Battle{Name: name, Public: public})
+func BattleCreate(battle Battle, owner User) (int, error) {
+	return globalState.InsertBattle(battle, owner)
 }
 
 func BattleLinkBot(botid int, battleid int) error {
 	return globalState.LinkBotBattle(botid, battleid)
 }
 
+func BattleUnlinkAllBotsForUser(userid int, battleid int) error {
+	return globalState.UnlinkAllBotsForUserFromBattle(userid, battleid)
+}
+
 func BattleGetByIdDeep(id int) (Battle, error) {
 	return globalState.GetBattleByIdDeep(id)
 }
@@ -54,44 +63,130 @@ func BattleLinkBitIDs(battleid int, bitIDs []int) error {
 	return globalState.LinkBitIDsToBattle(battleid, bitIDs)
 }
 
+func BattleLinkOwnerIDs(battleid int, ownerIDs []int) error {
+	return globalState.LinkOwnerIDsToBattle(battleid, ownerIDs)
+}
+
+func BattleSaveRawOutput(battleid int, rawOutput string) error {
+	return globalState.UpdateBattleRawOutput(battleid, rawOutput)
+}
+
+func BattleDeleteID(battleid int) error {
+	return globalState.DeleteBattleByID(battleid)
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // DATABASE
 
-func (s *State) InsertBattle(battle Battle) (int, error) {
-	res, err := s.db.Exec("INSERT INTO battles VALUES(NULL,?,?,?);", time.Now(), battle.Name, battle.Public)
+func (s *State) InsertBattle(battle Battle, owner User) (int, error) {
+	// create the battle
+	res, err := s.db.Exec(`
+		INSERT INTO battles
+		VALUES(NULL,?,?,?,?,?,?)
+		`, time.Now(),
+		battle.Name,
+		battle.Public,
+		battle.RawOutput,
+		battle.MaxRounds,
+		battle.ArenaSize)
+
 	if err != nil {
+		log.Println(err)
 		return -1, err
 	}
 
 	var id int64
 	if id, err = res.LastInsertId(); err != nil {
+		log.Println(err)
 		return -1, err
 	}
+
+	// insert the owner into the battle_owner rel
+	_, err = s.db.Exec("INSERT INTO owner_battle_rel VALUES (?, ?)", owner.ID, battle.ID)
+	if err != nil {
+		log.Println(err)
+		return -1, err
+	}
+
 	return int(id), nil
 }
 
 func (s *State) UpdateBattle(battle Battle) error {
-	_, err := s.db.Exec("UPDATE battles SET name=?, public=? WHERE id=?", battle.Name, battle.Public, battle.ID)
+	log.Println("Updating battle:")
+	log.Println(battle.ArenaSize)
+	_, err := s.db.Exec(`
+		UPDATE battles
+		SET name=?, public=?, arena_size=?, max_rounds=?
+		WHERE id=?`,
+		battle.Name,
+		battle.Public,
+		battle.ArenaSize,
+		battle.MaxRounds,
+		battle.ID)
 	if err != nil {
+		log.Println(err)
 		return err
 	}
+	log.Println("Done updating")
 	return nil
 }
 
 func (s *State) LinkBotBattle(botid int, battleid int) error {
 	_, err := s.db.Exec("INSERT INTO bot_battle_rel VALUES (?, ?)", botid, battleid)
 	if err != nil {
-		log.Println("Error linking bot to battle: ", err)
+		log.Println(err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+func (s *State) LinkOwnerBattle(battleid int, ownerid int) error {
+	_, err := s.db.Exec("INSERT INTO owner_battle_rel VALUES (?, ?)", ownerid, battleid)
+	if err != nil {
+		log.Println(err)
 		return err
 	} else {
 		return nil
 	}
 }
 
+func (s *State) UnlinkAllBotsForUserFromBattle(userid int, battleid int) error {
+	// get a user with the given id
+	// for all of their bots
+	// delete the bots from the bot_battle relation
+
+	// there are some joins to get through the following links:
+	// bot_battle_rel.bot_id
+	//   -> bot.id
+	//   -> user_bot_rel.bot_id
+	//   -> user_bot_rel.user_id
+	//   -> user.id
+
+	// delete preexisting links
+	_, err := s.db.Exec(`
+	DELETE FROM bot_battle_rel
+	WHERE bot_id IN
+		(SELECT b.id
+		 FROM bot_battle_rel bb_rel
+		 JOIN bots b ON b.id = bb_rel.bot_id
+		 JOIN user_bot_rel ub_rel ON ub_rel.bot_id = b.id
+		 JOIN users u ON u.id = ub_rel.user_id
+		 WHERE u.id=?)`, userid)
+
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	return nil
+}
+
 func (s *State) LinkArchIDsToBattle(battleid int, archIDs []int) error {
 	// delete preexisting links
-	_, err := s.db.Exec("DELETE FROM arch_battle_rel WHERE battle_id=?;", battleid)
+	_, err := s.db.Exec("DELETE FROM arch_battle_rel WHERE battle_id=?", battleid)
 	if err != nil {
+		log.Println(err)
 		return err
 	}
 
@@ -109,7 +204,7 @@ func (s *State) LinkArchIDsToBattle(battleid int, archIDs []int) error {
 
 	_, err = s.db.Exec(query)
 	if err != nil {
-		log.Println("LinkArchIDsToBattle err: ", err)
+		log.Println(err)
 		return err
 	} else {
 		return nil
@@ -118,8 +213,9 @@ func (s *State) LinkArchIDsToBattle(battleid int, archIDs []int) error {
 
 func (s *State) LinkBitIDsToBattle(battleid int, bitIDs []int) error {
 	// delete preexisting links
-	_, err := s.db.Exec("DELETE FROM bit_battle_rel WHERE battle_id=?;", battleid)
+	_, err := s.db.Exec("DELETE FROM bit_battle_rel WHERE battle_id=?", battleid)
 	if err != nil {
+		log.Println(err)
 		return err
 	}
 
@@ -137,7 +233,36 @@ func (s *State) LinkBitIDsToBattle(battleid int, bitIDs []int) error {
 
 	_, err = s.db.Exec(query)
 	if err != nil {
-		log.Println("LinkBitIDsToBattle err: ", err)
+		log.Println(err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+func (s *State) LinkOwnerIDsToBattle(battleid int, ownerIDs []int) error {
+	// delete preexisting links
+	_, err := s.db.Exec("DELETE FROM owner_battle_rel WHERE battle_id=?", battleid)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	// yes, we're building this by hand, but as we only insert int's I'm just confident that whoever
+	// gets some sqli here just deserves it :D
+	query := "INSERT INTO owner_battle_rel (user_id, battle_id) VALUES"
+	for idx, id := range ownerIDs {
+		query += fmt.Sprintf("(%d, %d)", id, battleid)
+		if idx != len(ownerIDs)-1 {
+			query += ", "
+		}
+	}
+	query += ";"
+	log.Println(query)
+
+	_, err = s.db.Exec(query)
+	if err != nil {
+		log.Println(err)
 		return err
 	} else {
 		return nil
@@ -148,6 +273,7 @@ func (s *State) GetAllBattles() ([]Battle, error) {
 	rows, err := s.db.Query("SELECT id, name FROM battles;")
 	defer rows.Close()
 	if err != nil {
+		log.Println(err)
 		return nil, err
 	}
 
@@ -171,6 +297,9 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 	var battleid int
 	var battlename string
 	var battlepublic bool
+	var battlerawoutput string
+	var battlemaxrounds int
+	var battlearenasize int
 
 	var botids string
 	var botnames string
@@ -184,21 +313,41 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 	var bitids string
 	var bitnames string
 
+	var ownerids string
+	var ownernames string
+
 	// battles have associated bots and users, we're fetching 'em all!
 
 	// This fetches the battles and relates the associated bots, users, archs and bits
 
+	// TODO(emile): go deeper! we could fetch battle -> bot -> arch (so fetching the linked arch
+	//              for the given bot)
+
+	// COALESCE is used to set default values
+	// TODO(emile): do fancy migrations instead of the COALESCE stuff for setting defaults if
+	// no value is set beforehand
+
 	err := s.db.QueryRow(`
 	SELECT DISTINCT
-		ba.id, ba.name, ba.public,
+		ba.id, ba.name, ba.public, 
+		COALESCE(ba.raw_output, ""),
+		COALESCE(ba.max_rounds, 100),
+		COALESCE(ba.arena_size, 4096),
+
 		COALESCE(group_concat(DISTINCT bb.bot_id), ""),
 		COALESCE(group_concat(DISTINCT bo.name), ""),
+
 		COALESCE(group_concat(DISTINCT ub.user_id), ""),
 		COALESCE(group_concat(DISTINCT us.name), ""),
+
 		COALESCE(group_concat(DISTINCT ab.arch_id), ""),
 		COALESCE(group_concat(DISTINCT ar.name), ""),
+
 		COALESCE(group_concat(DISTINCT bitbat.bit_id), ""),
-		COALESCE(group_concat(DISTINCT bi.name), "")
+		COALESCE(group_concat(DISTINCT bi.name), ""),
+
+		COALESCE(group_concat(DISTINCT ownerbat.user_id), ""),
+		COALESCE(group_concat(DISTINCT owner.name), "")
 	FROM battles ba
 
 	LEFT JOIN bot_battle_rel bb ON bb.battle_id = ba.id
@@ -213,26 +362,17 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 	LEFT JOIN bit_battle_rel bitbat ON bitbat.battle_id = ba.id
 	LEFT JOIN bits bi ON bi.id = bitbat.bit_id
 
+	LEFT JOIN owner_battle_rel ownerbat ON ownerbat.battle_id = ba.id
+	LEFT JOIN users owner ON owner.id = ownerbat.user_id
+
 	WHERE ba.id=?
 	GROUP BY ba.id;
-	`, id).Scan(&battleid, &battlename, &battlepublic, &botids, &botnames, &userids, &usernames, &archids, &archnames, &bitids, &bitnames)
+	`, id).Scan(&battleid, &battlename, &battlepublic, &battlerawoutput, &battlemaxrounds, &battlearenasize, &botids, &botnames, &userids, &usernames, &archids, &archnames, &bitids, &bitnames, &ownerids, &ownernames)
 	if err != nil {
-		log.Println("Err making GetBattleByID query: ", err)
+		log.Println(err)
 		return Battle{}, err
 	}
 
-	log.Println("battleid: ", battleid)
-	log.Println("battlename: ", battlename)
-	log.Println("battlepublic: ", battlepublic)
-	log.Println("botids: ", botids)
-	log.Println("botnames: ", botnames)
-	log.Println("userids: ", userids)
-	log.Println("usernames: ", usernames)
-	log.Println("archids: ", archids)
-	log.Println("archnames: ", archnames)
-	log.Println("bitids: ", bitids)
-	log.Println("bitnames: ", bitnames)
-
 	// The below is a wonderful examle of how golang could profit from macros
 	// I should just have done this all in common lisp tbh.
 
@@ -246,10 +386,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var bots []Bot
 	if botIDList[0] != "" {
-		for i, _ := range botIDList {
+		for i := range botIDList {
 			id, err := strconv.Atoi(botIDList[i])
 			if err != nil {
-				log.Println("Err handling bots: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			bots = append(bots, Bot{id, botNameList[i], "", []User{}, []Arch{}, []Bit{}})
@@ -264,10 +404,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var users []User
 	if userIDList[0] != "" {
-		for i, _ := range userIDList {
+		for i := range userIDList {
 			id, err := strconv.Atoi(userIDList[i])
 			if err != nil {
-				log.Println("Err handling users: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			users = append(users, User{id, userNameList[i], []byte{}})
@@ -282,10 +422,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var archs []Arch
 	if archIDList[0] != "" {
-		for i, _ := range archIDList {
+		for i := range archIDList {
 			id, err := strconv.Atoi(archIDList[i])
 			if err != nil {
-				log.Println("Err handling archs: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			archs = append(archs, Arch{id, archNameList[i], true})
@@ -300,10 +440,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var bits []Bit
 	if bitIDList[0] != "" {
-		for i, _ := range bitIDList {
+		for i := range bitIDList {
 			id, err := strconv.Atoi(bitIDList[i])
 			if err != nil {
-				log.Println("Err handling bits: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			bits = append(bits, Bit{id, bitNameList[i], true})
@@ -312,22 +452,74 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 		bits = []Bit{}
 	}
 
-	// return it all!
-	switch {
-	case err != nil:
-		log.Println("Overall err in the GetBattleByID func: ", err)
-		return Battle{}, err
-	default:
-		return Battle{
-			ID:     battleid,
-			Name:   battlename,
-			Bots:   bots,
-			Owners: users,
-			Public: battlepublic,
-			Archs:  archs,
-			Bits:   bits,
-		}, nil
+	// assemble the owners
+	ownerIDList := strings.Split(ownerids, ",")
+	ownerNameList := strings.Split(ownernames, ",")
+
+	var owners []User
+	if ownerIDList[0] != "" {
+		for i := range ownerIDList {
+			id, err := strconv.Atoi(ownerIDList[i])
+			if err != nil {
+				log.Println(err)
+				return Battle{}, err
+			}
+			owners = append(owners, User{id, ownerNameList[i], nil})
+		}
+	} else {
+		owners = []User{}
+	}
+
+	return Battle{
+		ID:        battleid,
+		Name:      battlename,
+		Bots:      bots,
+		Owners:    owners,
+		Public:    battlepublic,
+		Archs:     archs,
+		Bits:      bits,
+		RawOutput: battlerawoutput,
+		MaxRounds: battlemaxrounds,
+		ArenaSize: battlearenasize,
+	}, nil
+}
+
+func (s *State) UpdateBattleRawOutput(battleid int, rawOutput string) error {
+	_, err := s.db.Exec("UPDATE battles SET raw_output=? WHERE id=?", rawOutput, battleid)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+	return nil
+}
+
+// This deletes a battle and all links to users, bots, architectures and bits
+func (s *State) DeleteBattleByID(battleid int) error {
+	_, err := s.db.Exec(`
+	DELETE FROM battles WHERE battleid = ?;
+
+	DELETE FROM user_battle_rel WHERE battleid = ?;
+	DELETE FROM bot_battle_rel WHERE battleid = ?;
+	DELETE FROM arch_battle_rel WHERE battleid = ?;
+	DELETE FROM bit_battle_rel WHERE battleid = ?;
+	`, battleid, battleid, battleid, battleid, battleid)
+
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	_, err = s.db.Exec(`
+	DELETE FROM battles
+	WHERE battleid = ?
+	`, battleid)
+
+	if err != nil {
+		log.Println(err)
+		return err
 	}
+
+	return nil
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -346,18 +538,25 @@ func battlesHandler(w http.ResponseWriter, r *http.Request) {
 		}
 		data["pagelinknext"] = []Link{
 			{Name: "new", Target: "/new"},
+			{Name: "quick", Target: "/quick"},
 		}
 
 		// sessions
 		session, _ := globalState.sessions.Get(r, "session")
-		username := session.Values["username"].(string)
+		username := session.Values["username"]
 
-		// get the user
-		user, err := UserGetUserFromUsername(username)
-		if err != nil {
+		if username == nil {
 			http.Redirect(w, r, "/login", http.StatusSeeOther)
 			return
 		} else {
+			// get the user
+			user, err := UserGetUserFromUsername(username.(string))
+			if err != nil {
+				log.Println(err)
+				http.Redirect(w, r, "/login", http.StatusSeeOther)
+				return
+			}
+
 			data["user"] = user
 		}
 
@@ -368,7 +567,7 @@ func battlesHandler(w http.ResponseWriter, r *http.Request) {
 		// get the template
 		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
 		if err != nil {
-			log.Printf("Error reading the template Path: %s/*.html", templatesPath)
+			log.Println(err)
 			w.WriteHeader(http.StatusInternalServerError)
 			w.Write([]byte("500 - Error reading template file"))
 			http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -400,6 +599,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		data["pagelink2"] = Link{Name: "new", Target: "/new"}
 		data["pagelink2options"] = []Link{
 			{Name: "list", Target: ""},
+			{Name: "quick", Target: "/quick"},
 		}
 
 		// display errors passed via query parameters
@@ -411,6 +611,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		// get data needed
 		user, err := UserGetUserFromUsername(username)
 		if err != nil {
+			log.Println(err)
 			data["err"] = "Could not fetch the user"
 		} else {
 			data["user"] = user
@@ -418,6 +619,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 
 		archs, err := ArchGetAll()
 		if err != nil {
+			log.Println(err)
 			data["err"] = "Could not fetch the archs"
 		} else {
 			data["archs"] = archs
@@ -425,15 +627,24 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 
 		bits, err := BitGetAll()
 		if err != nil {
+			log.Println(err)
 			data["err"] = "Could not fetch the bits"
 		} else {
 			data["bits"] = bits
 		}
 
+		users, err := UserGetAll()
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch all users"
+		} else {
+			data["users"] = users
+		}
+
 		// get the template
 		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
 		if err != nil {
-			log.Printf("Error reading the template Path: %s/*.html", templatesPath)
+			log.Println(err)
 			w.WriteHeader(http.StatusInternalServerError)
 			w.Write([]byte("500 - Error reading template file"))
 			http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -441,12 +652,47 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// exec!
-		t.ExecuteTemplate(w, "battleNew", data)
+		err = t.ExecuteTemplate(w, "battleNew", data)
+		if err != nil {
+			log.Println(err)
+		}
 
 	case "POST":
+		data := map[string]interface{}{}
+
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+
+		// get data needed
+		user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
 		// parse the post parameters
 		r.ParseForm()
 		name := r.Form.Get("name")
+		arenasize, err := strconv.Atoi(r.Form.Get("arena-size"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+		maxrounds, err := strconv.Atoi(r.Form.Get("max-rounds"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
 
 		var public bool
 		query_public := r.Form.Get("public")
@@ -458,10 +704,11 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		var archIDs []int
 		var bitIDs []int
 
-		for k, _ := range r.Form {
+		for k := range r.Form {
 			if strings.HasPrefix(k, "arch-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "arch-"))
 				if err != nil {
+					log.Println(err)
 					msg := "ERROR: Invalid arch id"
 					http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 					return
@@ -471,6 +718,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 			if strings.HasPrefix(k, "bit-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "bit-"))
 				if err != nil {
+					log.Println(err)
 					msg := "ERROR: Invalid bit id"
 					http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 					return
@@ -482,9 +730,21 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		if name != "" {
 			// create the battle itself
 			log.Println("Creating battle")
-			battleid, err := BattleCreate(name, public)
+			newbattle := Battle{
+				0,
+				name,
+				nil,
+				nil,
+				public,
+				nil,
+				nil,
+				"",
+				maxrounds,
+				arenasize,
+			}
+			battleid, err := BattleCreate(newbattle, user)
 			if err != nil {
-				log.Println("Error creating the battle using BattleCreate(): ", err)
+				log.Println(err)
 				msg := "ERROR: Could not create due to internal reasons"
 				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 				return
@@ -493,7 +753,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 			// link archs to battle
 			err = BattleLinkArchIDs(battleid, archIDs)
 			if err != nil {
-				log.Println("Error linking the arch ids to the battle: ", err)
+				log.Println(err)
 				msg := "ERROR: Could not create due to internal reasons"
 				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 				return
@@ -502,7 +762,16 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 			// link bits to battle
 			err = BattleLinkBitIDs(battleid, bitIDs)
 			if err != nil {
-				log.Println("Error linking the bit ids to the battle: ", err)
+				log.Println(err)
+				msg := "ERROR: Could not create due to internal reasons"
+				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+				return
+			}
+
+			// link owner to battle
+			err = BattleLinkOwnerIDs(battleid, []int{user.ID})
+			if err != nil {
+				log.Println(err)
 				msg := "ERROR: Could not create due to internal reasons"
 				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 				return
@@ -520,14 +789,171 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-// TODO(emile): add user creating battle as default owner
-// TODO(emile): allow adding other users as owners to battles
-// TODO(emile): implement submitting bots
-// TODO(emile): implement running the battle
-// TODO(emile): add a "start battle now" button
-// TODO(emile): add a "battle starts at this time" field into the battle
-// TODO(emile): figure out how time is stored and restored with the db
-// TODO(emile): do some magic to display the current fight backlog with all info
+func battleQuickHandler(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		// define data
+		data := map[string]interface{}{}
+		data["version"] = os.Getenv("VERSION")
+
+		// breadcrumb foo
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+		data["pagelink1"] = Link{Name: "battle", Target: "/battle"}
+		data["pagelink1options"] = []Link{
+			{Name: "user", Target: "/user"},
+			{Name: "bot", Target: "/bot"},
+		}
+		data["pagelink2"] = Link{Name: "quick", Target: "/quick"}
+		data["pagelink2options"] = []Link{
+			{Name: "new", Target: "/new"},
+			{Name: "list", Target: ""},
+		}
+
+		// display errors passed via query parameters
+		queryres := r.URL.Query().Get("err")
+		if queryres != "" {
+			data["res"] = queryres
+		}
+
+		// get data needed
+		user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
+		// essentiall... ...the list of all bots from which the user can select two that shall
+		// battle!
+		bots, err := globalState.GetAllBotsWithUsers()
+		data["bots"] = bots
+
+		// get the template
+		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
+		if err != nil {
+			log.Println(err)
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Error reading template file"))
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// exec!
+		t.ExecuteTemplate(w, "battleQuick", data)
+
+	case "POST":
+		data := map[string]interface{}{}
+
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+
+		// get data needed
+		user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
+		// parse the post parameters
+		r.ParseForm()
+
+		var public bool
+		query_public := r.Form.Get("public")
+		if query_public == "on" {
+			public = true
+		}
+
+		arenasize, err := strconv.Atoi(r.Form.Get("arena-size"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+		maxrounds, err := strconv.Atoi(r.Form.Get("max-rounds"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		// gather the information from the arch and bit selection
+		var botIDs []int
+
+		for k := range r.Form {
+			if strings.HasPrefix(k, "bot-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "bot-"))
+				if err != nil {
+					log.Println(err)
+					msg := "ERROR: Invalid bot id"
+					http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+					return
+				}
+				botIDs = append(botIDs, id)
+			}
+		}
+
+		// create the battle itself
+		log.Println("Creating battle")
+		newbattle := Battle{
+			0,
+			fmt.Sprintf("quick-%d", rand.Intn(10000)),
+			nil,
+			nil,
+			public,
+			nil,
+			nil,
+			"",
+			maxrounds,
+			arenasize,
+		}
+		battleid, err := BattleCreate(newbattle, user)
+		if err != nil {
+			log.Println(err)
+			msg := "ERROR: Could not create due to internal reasons"
+			http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		// allow all archs and all bits
+
+		// link bots to battle
+
+		http.Redirect(w, r, fmt.Sprintf("/battle/%d", battleid), http.StatusSeeOther)
+
+		//  // link archs to battle
+		//  err = BattleLinkArchIDs(battleid, archIDs)
+		//  if err != nil {
+		//  	log.Println(err)
+		//  	msg := "ERROR: Could not create due to internal reasons"
+		//  	http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+		//  	return
+		//  }
+
+		//  // link bits to battle
+		//  err = BattleLinkBitIDs(battleid, bitIDs)
+		//  if err != nil {
+		//  	log.Println(err)
+		//  	msg := "ERROR: Could not create due to internal reasons"
+		//  	http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+		//  	return
+		//  }
+
+		//  http.Redirect(w, r, "/battle", http.StatusSeeOther)
+		return
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
 
 func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 	vars := mux.Vars(r)
@@ -539,6 +965,9 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	// A partially filled format string (the reason for the redirect is still to be filled later)
+	redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid)
+
 	switch r.Method {
 	case "GET":
 		// define data
@@ -557,16 +986,33 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		session, _ := globalState.sessions.Get(r, "session")
-		username := session.Values["username"].(string)
+		username := session.Values["username"]
 
-		viewer, err := UserGetUserFromUsername(username)
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+
+		viewer, err := UserGetUserFromUsername(username.(string))
 		if err != nil {
-			data["err"] = "Could not get the id four your username... Please contact an admin"
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the id for your username")
+			return
 		}
 		data["user"] = viewer
 
+		users, err := UserGetAll()
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the users")
+			return
+		}
+		data["users"] = users
+
 		// get the battle including it's users, bots, archs, bits
 		battle, err := BattleGetByIdDeep(int(battleid))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the battle given the id provided")
+			return
+		}
 		data["battle"] = battle
 		data["botAmount"] = len(battle.Bots)
 		data["battleCount"] = (len(battle.Bots) * len(battle.Bots)) * 2
@@ -582,10 +1028,9 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		data["pagelink2options"] = opts
 
 		// get the bots of the user viewing the page, as they might want to submit them
-		myBots, err := UserGetBotsUsingUsername(username)
+		myBots, err := UserGetBotsUsingUsername(username.(string))
 		if err != nil {
-			log.Println("err: ", err)
-			http.Redirect(w, r, fmt.Sprintf("/battle/%d", battleid), http.StatusSeeOther)
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get your bots")
 			return
 		}
 		data["myBots"] = myBots
@@ -593,7 +1038,8 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		// get all architectures and set the enable flag on the ones that are enabled in the battle
 		archs, err := ArchGetAll()
 		if err != nil {
-			data["err"] = "Could not fetch the archs"
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get your bots")
+			return
 		} else {
 			data["archs"] = archs
 		}
@@ -609,7 +1055,8 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		// get all bits and set the enable flag on the ones that are enabled in the battle
 		bits, err := BitGetAll()
 		if err != nil {
-			data["err"] = "Could not fetch the bits"
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not fetch the bits")
+			return
 		} else {
 			data["bits"] = bits
 		}
@@ -644,7 +1091,10 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// exec!
-		t.ExecuteTemplate(w, "battleSingle", data)
+		err = t.ExecuteTemplate(w, "battleSingle", data)
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "err rendering template")
+		}
 
 	case "POST":
 		log.Println("POST!")
@@ -687,10 +1137,29 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 
 		// at this point, we're sure the user is allowed to edit the battle
 
+		data := map[string]interface{}{}
+
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+
+		// get data needed
+		user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
 		r.ParseForm()
 
 		log.Println("r.Form: ", r.Form)
 		form_name := r.Form.Get("name")
+		arenasize, err := strconv.Atoi(r.Form.Get("arena-size"))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Invalid Arena size")
+			return
+		}
 
 		var public bool
 		if r.Form.Get("public") == "on" {
@@ -700,13 +1169,15 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		// gather the information from the arch and bit selection
 		var archIDs []int
 		var bitIDs []int
+		var ownerIDs []int
 
-		for k, _ := range r.Form {
+		log.Println(r.Form)
+
+		for k := range r.Form {
 			if strings.HasPrefix(k, "arch-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "arch-"))
 				if err != nil {
-					msg := "ERROR: Invalid arch id"
-					http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+					log_and_redir_with_msg(w, r, err, redir_target, "Invalid Arch ID")
 					return
 				}
 				archIDs = append(archIDs, id)
@@ -714,41 +1185,62 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 			if strings.HasPrefix(k, "bit-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "bit-"))
 				if err != nil {
-					msg := "ERROR: Invalid bit id"
-					http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+					log_and_redir_with_msg(w, r, err, redir_target, "Invalid Bit ID")
 					return
 				}
 				bitIDs = append(bitIDs, id)
 			}
+			if strings.HasPrefix(k, "owner-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "owner-"))
+				if err != nil {
+					log_and_redir_with_msg(w, r, err, redir_target, "Invalid Owner ID")
+					return
+				}
+				ownerIDs = append(ownerIDs, id)
+			}
+		}
+
+		// CHECK THAT THE USER REQUESTING CHANGES IS ALREADY PART OF THE OWNERS
+		allowedToEdit := false
+		for _, ownerID := range ownerIDs {
+			if user.ID == ownerID {
+				allowedToEdit = true
+			}
 		}
+		if allowedToEdit == false {
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "You aren't an owner and aren't allowed to edit the settings")
+			return
+		}
+
+		// DATABASE MANIPUTLATION BELOW
 
 		// link archs to battle
 		err = BattleLinkArchIDs(battleid, archIDs)
 		if err != nil {
-			log.Println("Error linking the arch ids to the battle: ", err)
-			msg := "ERROR: Could not create due to internal reasons"
-			http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not link arch id to battle")
 			return
 		}
 
 		// link bits to battle
 		err = BattleLinkBitIDs(battleid, bitIDs)
 		if err != nil {
-			log.Println("Error linking the bit ids to the battle: ", err)
-			msg := "ERROR: Could not create due to internal reasons"
-			http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not link bit id to battle")
+			return
+		}
+
+		// link bits to battle
+		err = BattleLinkOwnerIDs(battleid, ownerIDs)
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not link owner id to battle")
 			return
 		}
 
-		new_battle := Battle{int(battleid), form_name, []Bot{}, []User{}, public, []Arch{}, []Bit{}}
+		new_battle := Battle{int(battleid), form_name, []Bot{}, []User{user}, public, []Arch{}, []Bit{}, "", 100, arenasize}
 
 		log.Println("Updating battle...")
 		err = BattleUpdate(new_battle)
 		if err != nil {
-			log.Println("err: ", err)
-			w.WriteHeader(http.StatusInternalServerError)
-			w.Write([]byte("500 - Error inserting battle into db"))
-			http.Error(w, err.Error(), http.StatusInternalServerError)
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not insert battle into db")
 			return
 		}
 
@@ -769,16 +1261,32 @@ func battleSubmitHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid)
+
 	switch r.Method {
 	case "POST":
 		r.ParseForm()
 
-		log.Println("Adding bot to battle", battleid)
+		log.Println("Someone submitted the following form:")
 		log.Println(r.Form)
 
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"]
+
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+
+		user, err := UserGetUserFromUsername(username.(string))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the id for your username")
+			return
+		}
+
 		// get all the form values that contain the bot that shall be submitted
 		var botIDs []int
-		for k, _ := range r.Form {
+		for k := range r.Form {
 			if strings.HasPrefix(k, "bot-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "bot-"))
 				if err != nil {
@@ -790,15 +1298,15 @@ func battleSubmitHandler(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 
-		log.Println(botIDs)
-
 		battle, err := BattleGetByIdDeep(battleid)
 		if err != nil {
 			msg := "ERROR: Couln't get the battle with the given id"
 			http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s", battleid, msg), http.StatusSeeOther)
 			return
 		}
-		log.Println(battle)
+
+		// clear all bots from that user for that battle before readding them here
+		BattleUnlinkAllBotsForUser(user.ID, battleid)
 
 		// for all bots, get their bits and arch and compare them to the one of the battle
 		for _, id := range botIDs {
@@ -851,3 +1359,326 @@ func battleSubmitHandler(w http.ResponseWriter, r *http.Request) {
 		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
 	}
 }
+
+// actually run the battle
+func battleRunHandler(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)
+	battleid, err := strconv.Atoi(vars["id"])
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("500 - Invalid battle id"))
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid)
+
+	switch r.Method {
+	case "POST":
+		r.ParseForm()
+
+		log.Printf("running the battle with the id %d", battleid)
+		log.Println("Someone submitted the following form:")
+		log.Println(r.Form)
+
+		// fetch the session and get the user
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"]
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+		user, err := UserGetUserFromUsername(username.(string))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the id for your username")
+			return
+		}
+
+		// Fetch the battle information
+		// This includes all bots linked to the battle
+		log.Printf("user %+v wants to run the battle", user)
+		fullDeepBattle, err := BattleGetByIdDeep(battleid)
+
+		// open radare without input for building the bot
+		// TODO(emile): configure a variable memsize for the arena
+		cmd := fmt.Sprintf("malloc://%d", fullDeepBattle.ArenaSize)
+		r2p1, err := r2pipe.NewPipe(cmd)
+		if err != nil {
+			panic(err)
+		}
+		defer r2p1.Close()
+
+		var botSources []string
+		var rawOutput string
+
+		cmd = fmt.Sprintf("pxc %d @ 0x0", fullDeepBattle.ArenaSize)
+		output, _ := r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+
+		// TODO(emile): currently hardcoded to two bots, extract this anonymous struct into a named struct and make this work with > 2 bots
+		runtimeBots := []struct {
+			Name     string
+			Regs     string
+			BaseAddr int
+			ArchName string
+			BitsName string
+		}{
+			{Name: "", Regs: "", BaseAddr: 0, ArchName: "", BitsName: ""},
+			{Name: "", Regs: "", BaseAddr: 0, ArchName: "", BitsName: ""},
+		}
+
+		rawOutput += "[0x00000000]> # Assembling the bots\n"
+
+		// for each bot involved within the battle, we need to fetch it again, as the deep battle
+		// fech doesn't fetch that deep (it fetches the batle and the corresponding bots, but only
+		// their ids and names and not the archs and bits associated)
+		for i, b := range fullDeepBattle.Bots {
+			bot, err := BotGetById(b.ID)
+			if err != nil {
+				log.Println(err)
+			}
+
+			runtimeBots[i].Name = bot.Name
+
+			// TODO(emile): a bot can have multiple archs/bits, figure out what to do then
+			// I've just gone and used the first one, as a bot alwas has at least one...
+			// ...it has right?
+			runtimeBots[i].ArchName = bot.Archs[0].Name
+			runtimeBots[i].BitsName = bot.Bits[0].Name
+
+			// define the command used to assemble the bot
+			src := strings.ReplaceAll(bot.Source, "\r\n", "; ")
+			radareCommand := fmt.Sprintf("rasm2 -a %s -b %s \"%+v\"", bot.Archs[0].Name, bot.Bits[0].Name, src)
+			rawOutput += fmt.Sprintf("; %s\n", radareCommand)
+
+			// assemble the bot
+			bytecode, err := r2cmd(r2p1, radareCommand)
+			if err != nil {
+				http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s", battleid, "err building bot"), http.StatusSeeOther)
+				return
+			}
+
+			botSources = append(botSources, bytecode)
+		}
+
+		// TODO(emile): [L] implement some kind of queue
+
+		rawOutput += "[0x00000000]> # initializing the vm and the stack\n"
+		cmd = "aei"
+		output, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+		cmd = "aeim"
+		output, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+		// TODO(emile): random offsets
+		// place bots
+		for i, s := range botSources {
+
+			// the address to write the bot to
+			addr := 50 * (i + 1)
+
+			// store it
+			runtimeBots[i].BaseAddr = addr
+
+			msg := fmt.Sprintf("# writing bot %d to 0x%d", i, addr)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", msg)
+			cmd := fmt.Sprintf("wx %s @ 0x%d", s, addr)
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			// define the instruction point and the stack pointer
+			rawOutput += "[0x00000000]> # Setting the program counter and the stack pointer\n"
+			cmd = fmt.Sprintf("aer PC=0x%d", addr)
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			cmd = fmt.Sprintf("aer SP=SP+0x%d", addr)
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			// dump the registers of the bot for being able to switch inbetween them
+			// This is done in order to be able to play one step of each bot at a time,
+			// but sort of in parallel
+			rawOutput += "[0x00000000]> # Storing registers\n"
+			cmd = "aerR"
+			regs, _ := r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			initialRegisers := strings.Replace(regs, "\n", ";", -1)
+			runtimeBots[i].Regs = initialRegisers
+		}
+
+		for i := range botSources {
+			// print the memory for some pleasing visuals
+			cmd = fmt.Sprintf("pxc 100 @ 0x%d", runtimeBots[i].BaseAddr)
+			output, _ = r2cmd(r2p1, cmd) // print
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+		}
+
+		output, _ = r2cmd(r2p1, "pxc 100 @ 0x50") // print
+		fmt.Println(output)
+
+		// define end conditions
+		rawOutput += "[0x00000000]> # Defining the end conditions\n"
+		cmd = "e cmd.esil.todo=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+		cmd = "e cmd.esil.trap=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+		cmd = "e cmd.esil.intr=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+		cmd = "e cmd.esil.ioer=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+		// set the end condition to 0 initially
+		rawOutput += "[0x00000000]> # Initializing the end condition variable\n"
+		cmd = "f theend=0"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+		currentBotId := 0
+
+		// TODO(emile): find a sensible default for the max amount of rounds
+		for i := 0; i < fullDeepBattle.MaxRounds; i++ {
+
+			currentBotId = i % 2
+
+			rawOutput += fmt.Sprintf("[0x00000000]> ########################################################################\n")
+
+			rawOutput += "[0x00000000]> # Loading the registers\n"
+			r2cmd(r2p1, runtimeBots[currentBotId].Regs)
+
+			// this is architecture agnostic and just gets the program counter
+			pc, _ := r2cmd(r2p1, "aer~$(arn PC)~[1]")
+
+			arch, _ := r2cmd(r2p1, "e asm.arch")
+			bits, _ := r2cmd(r2p1, "e asm.bits")
+			rawOutput += fmt.Sprintf("[0x00000000]> # ROUND %d, BOT %d (%s), PC=%s, arch=%s, bits=%s\n", i, currentBotId, runtimeBots[currentBotId].Name, pc, arch, bits)
+
+			rawOutput += "[0x00000000]> # setting the architecture accordingly\n"
+			cmd = fmt.Sprintf("e asm.arch=%s", runtimeBots[currentBotId].ArchName)
+			output, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+			cmd = fmt.Sprintf("e asm.bits=%s", runtimeBots[currentBotId].BitsName)
+			output, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+			// load registers
+			//  rawOutput += fmt.Sprintf("%+v\n", runtimeBots[currentBotId].Regs)
+
+			//  cmd = "dr"
+			//  output, _ = r2cmd(r2p1, cmd)
+			//  rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+
+			//  _, _ = r2cmd(r2p1, "aes") // step
+			rawOutput += "[0x00000000]> # Stepping\n"
+			cmd = "aes"
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			// store the regisers
+			rawOutput += "[0x00000000]> # Storing the registers\n"
+			registers, _ := r2cmd(r2p1, "aerR")
+			registersStripped := strings.Replace(registers, "\n", ";", -1)
+			runtimeBots[currentBotId].Regs = registersStripped
+
+			// print the arena
+			rawOutput += "[0x00000000]> # Printing the arena\n"
+			cmd := fmt.Sprintf("pxc 100 @ 0x%d", runtimeBots[currentBotId].BaseAddr)
+			output, _ := r2cmd(r2p1, cmd) // print
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+			//  fmt.Println(output)
+
+			// predicate - the end?
+			rawOutput += "[0x00000000]> # Checking if we've won\n"
+			pend, _ := r2cmd(r2p1, "?v theend")
+			status := strings.TrimSpace(pend)
+			// fixme: on Windows, we sometimes get output *from other calls to r2*
+
+			if status == "0x1" {
+				log.Printf("[!] Bot %d has died", currentBotId)
+			}
+			if status != "0x0" {
+				log.Printf("[!] Got invalid status '%s' for bot %d", status, currentBotId)
+			}
+		}
+
+		BattleSaveRawOutput(battleid, rawOutput)
+
+		msg := "Success!"
+		http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#output", battleid, msg), http.StatusSeeOther)
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
+
+// delete a battle
+// TODO(emile): finish implementing the deletion of battles
+func battleDeleteHandler(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)
+	battleid, err := strconv.Atoi(vars["id"])
+	if err != nil {
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("500 - Invalid battle id"))
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid)
+
+	switch r.Method {
+	case "POST": // can't send a DELETE with pure HTML...
+
+		// get the current user
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"]
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+		viewer, err := UserGetUserFromUsername(username.(string))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the id for your username")
+			return
+		}
+
+		// get the battle
+		battle, err := BattleGetByIdDeep(int(battleid))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the battle given the id provided")
+			return
+		}
+
+		battle_owned_by_requesting_user := false
+		for _, owner := range battle.Owners {
+
+			// if the requesting users id is equal to an owners id, we're allowed to delete
+			// the battle
+			if viewer.ID == owner.ID {
+				battle_owned_by_requesting_user = true
+				break
+			}
+		}
+
+		// check that the user that created the battle is the current user, if not, return
+		if battle_owned_by_requesting_user == false {
+			msg := "You aren't in the owners list of the battle, so you can't delete this battle"
+			log_and_redir_with_msg(w, r, err, redir_target, msg)
+			return
+		}
+
+		BattleDeleteID(battleid)
+
+		msg := "Successfully deleted the battle"
+		http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s", battleid, msg), http.StatusSeeOther)
+	default:
+		log.Println("expected POST, got ", r.Method)
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
diff --git a/src/bot.go b/src/bot.go
index a2e8c99..65c1c29 100644
--- a/src/bot.go
+++ b/src/bot.go
@@ -111,22 +111,15 @@ func (s *State) GetBotById(id int) (Bot, error) {
 
 	WHERE bo.id=?
 	GROUP BY bo.id;
-	`, id).Scan(&botid, &botname, &botsource, &ownerids, &ownernames, &archids, &archnames, &bitids, &bitnames)
+	`, id).Scan(&botid, &botname, &botsource,
+		&ownerids, &ownernames,
+		&archids, &archnames,
+		&bitids, &bitnames)
 	if err != nil {
 		log.Println(err)
 		return Bot{}, err
 	}
 
-	// log.Println("botid: ", botid)
-	// log.Println("botname: ", botname)
-	// log.Println("botsource: ", botsource)
-	// log.Println("ownerids: ", ownerids)
-	// log.Println("ownernames: ", ownernames)
-	// log.Println("archid: ", archids)
-	// log.Println("archname: ", archnames)
-	// log.Println("bitid: ", bitids)
-	// log.Println("bitname: ", bitnames)
-
 	ownerIDList := strings.Split(ownerids, ",")
 	ownerNameList := strings.Split(ownernames, ",")
 
@@ -181,6 +174,7 @@ func (s *State) GetBotById(id int) (Bot, error) {
 		log.Println("ERR4: ", err)
 		return Bot{}, err
 	default:
+		//  log.Printf("returning bot with archs %+v and bits %+v", archs, bits)
 		return Bot{botid, botname, botsource, users, archs, bits}, nil
 	}
 }
@@ -430,6 +424,7 @@ func botSingleHandler(w http.ResponseWriter, r *http.Request) {
 			data["res"] = queryres
 		}
 
+		// fetch the session and get the user that made the request
 		session, _ := globalState.sessions.Get(r, "session")
 		username := session.Values["username"].(string)
 
@@ -438,6 +433,7 @@ func botSingleHandler(w http.ResponseWriter, r *http.Request) {
 			data["err"] = "Could not get the id four your username... Please contact an admin"
 		}
 
+		// get the bot that was requested
 		bot, err := BotGetById(int(botid))
 		data["bot"] = bot
 		data["user"] = viewer
@@ -449,6 +445,9 @@ func botSingleHandler(w http.ResponseWriter, r *http.Request) {
 		}
 		defer r2p1.Close()
 
+		// TODO(emile): improve the archs and bit handling here. I'll use the first one for now,
+		// but it would be nice to loop over all of them (would be a matrix with archs and bits
+		// on the axes)
 		src := strings.ReplaceAll(bot.Source, "\r\n", "; ")
 		radareCommand := fmt.Sprintf("rasm2 -a %s -b %s \"%+v\"", bot.Archs[0].Name, bot.Bits[0].Name, src)
 		bytecode, err := r2cmd(r2p1, radareCommand)
diff --git a/src/db.go b/src/db.go
index 47d8158..8983df9 100644
--- a/src/db.go
+++ b/src/db.go
@@ -22,7 +22,10 @@ CREATE TABLE IF NOT EXISTS battles (
 	id INTEGER NOT NULL PRIMARY KEY,
 	created_at DATETIME NOT NULL,
 	name TEXT,
-	public BOOLEAN
+	public BOOLEAN,
+	raw_output TEXT,
+	max_rounds INTEGER,
+	arena_size INTEGER
 );
 CREATE TABLE IF NOT EXISTS archs (
 	id INTEGER NOT NULL PRIMARY KEY,
@@ -89,6 +92,11 @@ CREATE TABLE IF NOT EXISTS user_battle_rel (
 	battle_id INTEGER,
 	PRIMARY KEY(user_id, battle_id)
 );
+CREATE TABLE IF NOT EXISTS owner_battle_rel (
+	user_id INTEGER,
+	battle_id INTEGER,
+	PRIMARY KEY(user_id, battle_id)
+);
 CREATE TABLE IF NOT EXISTS bot_battle_rel (
 	bot_id INTEGER,
 	battle_id INTEGER,
diff --git a/src/main.go b/src/main.go
index 65a3212..c789cf8 100644
--- a/src/main.go
+++ b/src/main.go
@@ -30,7 +30,7 @@ func initFlags() {
 
 	flag.StringVar(&logFilePath, "logfilepath", "./server.log", "The path to the log file")
 	flag.StringVar(&databasePath, "databasepath", "./main.db", "The path to the main database")
-	flag.StringVar(&sessiondbPath, "sessiondbpath", "./sesions.db", "The path to the session database")
+	flag.StringVar(&sessiondbPath, "sessiondbpath", "./sessions.db", "The path to the session database")
 	flag.StringVar(&templatesPath, "templates", "./templates", "The path to the templates used")
 }
 
@@ -86,11 +86,30 @@ func main() {
 	auth_needed.HandleFunc("/user/{id}", userHandler)
 	auth_needed.HandleFunc("/user/{id}/profile", profileHandler)
 
-	auth_needed.HandleFunc("/battle", battlesHandler)
+	r.HandleFunc("/battle", battlesHandler)
+	r.HandleFunc("/battle/{id}", battleSingleHandler)
 	auth_needed.HandleFunc("/battle/new", battleNewHandler)
-	auth_needed.HandleFunc("/battle/{id}", battleSingleHandler)
+	auth_needed.HandleFunc("/battle/quick", battleQuickHandler)
 	auth_needed.HandleFunc("/battle/{id}/submit", battleSubmitHandler)
+	auth_needed.HandleFunc("/battle/{id}/run", battleRunHandler)
+	auth_needed.HandleFunc("/battle/{id}/delete", battleDeleteHandler)
 
 	log.Printf("[i] HTTP Server running on %s:%d\n", host, port)
 	log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", host, port), r))
 }
+
+/* Convenience functions */
+
+// log_and_redir_with_msg takes a few args, let's go through them one by one:
+//   - w: the response writer
+//   - r: the initial request
+//   - err: the error that occurred, this one will be logged
+//   - target: the target of the redirect, this must be a format string with some format parameter
+//     receiving a string, for example `/battles/?err=%s`, the `%s` format string will then be
+//     filled with the message
+//   - msg: the message to print after being redirected
+func log_and_redir_with_msg(w http.ResponseWriter, r *http.Request, err error, target string, msg string) {
+	log.Println(err)
+	http.Redirect(w, r, fmt.Sprintf(target, msg), http.StatusSeeOther)
+	return
+}
diff --git a/src/r2.go b/src/r2.go
index 6ecd24b..d736f59 100644
--- a/src/r2.go
+++ b/src/r2.go
@@ -7,10 +7,7 @@ import (
 )
 
 func r2cmd(r2p *r2pipe.Pipe, input string) (string, error) {
-
-	log.Println("---")
 	log.Printf("> %s\n", input)
-	log.Println("---")
 
 	// send a command
 	buf1, err := r2p.Cmd(input)
diff --git a/src/user.go b/src/user.go
index 48bc299..cbedf03 100644
--- a/src/user.go
+++ b/src/user.go
@@ -71,6 +71,10 @@ func UserGetAll() ([]User, error) {
 	return globalState.GetAllUsers()
 }
 
+func UserGetUsernameCount(username string) (int, error) {
+	return globalState.GetUsernameCount(username)
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // DATABASE
 
@@ -119,7 +123,9 @@ func (s *State) UpdateUserUsername(id int, new_username string) error {
 
 // Links the given bot to the given user in the user_bot_rel table
 func (s *State) LinkUserBot(username string, botid int) error {
-	_, err := s.db.Exec("INSERT INTO user_bot_rel VALUES ((SELECT id FROM users WHERE name=?), ?)", username, botid)
+	_, err := s.db.Exec(`
+		INSERT INTO user_bot_rel
+		VALUES ((SELECT id FROM users WHERE name=?), ?)`, username, botid)
 	if err != nil {
 		return err
 	} else {
@@ -151,8 +157,13 @@ func (s *State) GetUserFromUsername(username string) (User, error) {
 }
 
 // Returns the bots belonging to the given user
+// TODO(emile): Also fetch the bits and the archs for displaying in the single battle page. In order to do so, join in both those tables
 func (s *State) GetUserBotsUsername(username string) ([]Bot, error) {
-	rows, err := s.db.Query("SELECT id, name, source FROM bots b LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id WHERE ub.user_id=(SELECT id FROM users WHERE name=?)", username)
+	rows, err := s.db.Query(`
+		SELECT id, name, source
+		FROM bots b
+		LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id
+		WHERE ub.user_id=(SELECT id FROM users WHERE name=?)`, username)
 	defer rows.Close()
 	if err != nil {
 		return nil, err
@@ -174,7 +185,11 @@ func (s *State) GetUserBotsUsername(username string) ([]Bot, error) {
 
 // Returns the bots belonging to the given user
 func (s *State) GetUserBotsId(id int) ([]Bot, error) {
-	rows, err := s.db.Query("SELECT id, name, source FROM bots b LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id WHERE ub.user_id=?", id)
+	rows, err := s.db.Query(`
+		SELECT id, name, source
+		FROM bots b
+		LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id
+		WHERE ub.user_id=?`, id)
 	defer rows.Close()
 	if err != nil {
 		return nil, err
@@ -216,15 +231,36 @@ func (s *State) GetAllUsers() ([]User, error) {
 	return users, nil
 }
 
+func (s *State) GetUsernameCount(username string) (int, error) {
+	rows, err := s.db.Query(`
+		SELECT COUNT(*)
+		FROM users
+		WHERE name=?`, username)
+	defer rows.Close()
+	if err != nil {
+		return -1, err
+	}
+
+	var count int
+	rows.Next()
+	if err := rows.Scan(&count); err != nil {
+		return -1, err
+	}
+	if err = rows.Err(); err != nil {
+		return -1, err
+	}
+	return count, nil
+}
+
+//  return globalState.GetUsernameCount(username)
+
 //////////////////////////////////////////////////////////////////////////////
 // HTTP
 
 func loginHandler(w http.ResponseWriter, r *http.Request) {
 	switch r.Method {
 	case "GET":
-		log.Println("GET /login")
 		// define data
-		log.Println("[d] Defining breadcrumbs")
 		data := map[string]interface{}{}
 		data["version"] = os.Getenv("VERSION")
 		data["pagelink1"] = Link{"login", "/login"}
@@ -236,7 +272,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// session foo
-		log.Println("[d] Getting session")
 		session, _ := globalState.sessions.Get(r, "session")
 		username := session.Values["username"]
 
@@ -245,7 +280,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 			log.Printf("[d] Getting the user %s\n", username.(string))
 			user, err := UserGetUserFromUsername(username.(string))
 			if user.Name == "" {
-				log.Println("no user found")
 			} else if err != nil {
 				log.Println(err)
 				msg := "Error: could not get the user for given username"
@@ -257,14 +291,12 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// display errors passed via query parameters
-		log.Println("[d] Getting previous results")
 		queryres := r.URL.Query().Get("res")
 		if queryres != "" {
 			data["res"] = queryres
 		}
 
 		// get the template
-		log.Println("[d] Getting the template")
 		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
 		if err != nil {
 			log.Printf("Error reading the template Path: %s/*.html", templatesPath)
@@ -275,7 +307,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// exec!
-		log.Println("[d] Executing the template")
 		t.ExecuteTemplate(w, "login", data)
 
 	case "POST":
@@ -337,8 +368,6 @@ func registerHandler(w http.ResponseWriter, r *http.Request) {
 			{Name: "login/", Target: "/login"},
 		}
 
-		log.Println(username)
-
 		if username != nil {
 			data["logged_in"] = true
 		}
@@ -381,6 +410,13 @@ func registerHandler(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
+		// Fetch all users and check that there isn't another user with the name here
+		if _, err := UserGetUsernameCount(username); err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Oi', Backend here! That username has already been taken!"))
+			return
+		}
+
 		// if we've got a password, hash it and store it and create a User
 		if password1 != "" {
 			passwordHash := argon2.IDKey([]byte(password1), []byte(os.Getenv("SALT")), 1, 64*1024, 4, 32)
diff --git a/templates/battleNew.html b/templates/battleNew.html
index 0460dc7..1992e1d 100644
--- a/templates/battleNew.html
+++ b/templates/battleNew.html
@@ -7,8 +7,9 @@
   <span id="newbattle"></span>
   <h1><a href="#newbattle">New battle</a></h1>
   
-  <p>This is the page on which you can create a battle. Select the values you find appropriate.
-   Bots can be added to the battle later.</p>
+  <p>A battle is a <b>collection</b> of fights intended to be fought with multiple bots. In case you just want to try out two bots, create a <a href="/battle/quick">quick</a> battle!</p>
+  <br>
+  <p>Select the values you find appropriate. Bots can be added to the battle later.</p>
 
   <br>
 
@@ -49,7 +50,21 @@
           <label class="label-for-check" for="bit-{{$bit.ID}}">{{$bit.Name}}</label>
           {{- end }}
         </td>
-      </td>
+      </tr>
+
+      <tr>
+        <td>Arena size:</td>
+        <td>
+          <input class="border" type="number" name="arena-size" id="arena-size" value="4096"/>
+        </td>
+      </tr>
+
+      <tr>
+        <td>Max Rounds:</td>
+        <td>
+          <input class="border" type="number" name="max-rounds" id="max-rounds" value="100"/>
+        </td>
+      </tr>
 
       <tr>
         <td>Public:</td>
@@ -62,6 +77,23 @@
       </td>
 
       <tr>
+        <td>Owners</td>
+        <td>
+          {{ $viewerID := .user.ID }}
+          {{ range $idx, $u := .users}}{{if $idx}},{{- end}}
+            <input
+              type="checkbox"
+              class="check-with-label"
+              name="owner-{{ $u.ID }}"
+              id="owner-{{ $u.ID }}"
+              {{if eq $u.ID $viewerID}}checked{{end}}
+              />
+            <label class="label-for-check" for="owner-{{ $u.ID }}">{{$u.Name}}</label>
+          {{- end }}
+        </td>
+      </tr>
+
+      <tr>
         <td></td>
         <td><input class="border" type="submit" value="Create"></td>
       </tr>
@@ -69,11 +101,16 @@
       {{ if .res }}
       <tr>
         <td></td>
-        <td>{{ .res }}</td>
+        <td><div style="border: 1px solid blue; padding: 1ex">{{ .res }}</div></td>
       </tr>
       {{ end }}
     </form>
   </table>
+
+  <span id="debug"></span>
+  <h2><a href="#debug">Debug</a></h2>
+
+  <pre>{{ . }}</pre>
 </body>
 {{ template "footer" . }}
 {{ end }}
diff --git a/templates/battleQuick.html b/templates/battleQuick.html
new file mode 100644
index 0000000..e309346
--- /dev/null
+++ b/templates/battleQuick.html
@@ -0,0 +1,57 @@
+{{ define "battleQuick" }}
+
+{{ template "head" . }}
+<body>
+  {{ template "nav" . }}
+
+  <span id="quickbattle"></span>
+  <h1><a href="#quickbattle">Quick battle</a></h1>
+  
+  <p>Just quickly want to try out two bots? Select them here and we'll let them fight quickly!</p>
+
+  <br>
+
+  <form id="battle" method="POST" action="/battle/quick">
+    <table class="trhover">
+    {{ range $bot := .bots }}
+      <tr>
+
+        <!-- The name of the bot with the link to the bot's page -->
+        <td>
+          <a href="/bot/{{ $bot.ID }}">{{ $bot.Name }}</a>
+        </td>
+
+        <!-- A checkbox allowing the user to select the bot -->
+              <!-- class="check-with-label" -->
+        <td>
+            <input
+              type="checkbox"
+              name="bot-{{$bot.ID}}"
+              id="bot-{{$bot.ID}}"
+              />
+            <label class="label-for-check" for="bot-{{$bot.ID}}"></label>
+        <td>
+
+        <!-- The list of users the bot belongs to-->
+        <td>
+          {{ range $idx, $usr := $bot.Users }}{{if $idx}},{{end}}<a href="/user/{{ $usr.ID }}">{{ $usr.Name }}</a>{{ end }}
+        </td>
+
+      </tr>
+    {{ end }}
+      <tr>
+        <td></td>
+        <td>{{ .res }}</td>
+      </tr>
+    </table>
+
+    <br>
+    <div class=".w-100"><input class="border" type="submit" value="Fight!"></div>
+    
+  </form>
+
+  <!-- {{ . }} -->
+
+</body>
+{{ template "footer" . }}
+{{ end }}
diff --git a/templates/battleSingle.html b/templates/battleSingle.html
index fb53fc2..b074a75 100644
--- a/templates/battleSingle.html
+++ b/templates/battleSingle.html
@@ -9,218 +9,217 @@
 
   <pre>
 <a href="#settings">Settings</a>
-<a href="#elimination-ladder">Elimination Ladder</a>
-  <a href="#round-1">Round 1</a>
-  <a href="#round-2">Round 2</a>
-  <a href="#round-3">Round 3</a>
-<a href="#current-standings">Current Standings</a>
+<a href="#registered-bots">Registered Bots</a>
+<a href="#output">Output</a>
+<a href="#debug">Debug</a>
   </pre>
 
   <span id="settings"></span>
   <h2><a href="#settings">Settings</a></h2>
 
-  <form id="delete" method="POST" action="/battle/{{ .battle.ID }}/delete">
-  </form>
-
   <table>
-    <form id="battle" method="POST" action="/battle/{{ .battle.ID }}">
-      <tr>
-        <td><label for="name">Name:</label></td>
-        <td><input class="border" type="text" id="name" name="name" value="{{ .battle.Name }}"></td>
-      </tr>
-
-      <tr>
-        <td><label for="latestBotSubmission">Latest Bot Submission</label></td>
-        <td><input
-              class="border"
-              type="datetime-local"
-              id="latestBotSubmission"
-              name="latestBotSubmission"
-              value="2024-11-08T12:00"
-              ></td>
-      </tr>
-
-      <tr>
-        <td><label for="battleStart">Battle Start</label></td>
-        <td><input
-              class="border"
-              type="datetime-local"
-              id="battleStart"
-              name="battleStart"
-              value="2024-11-08T16:00"
-              ></td>
-      </tr>
-
-<!--
-      <tr>
-        <td><label for="owners">Owners:</label></td>
-        <td>
-          {{ range $idx, $usr := .battle.Owners }}{{if $idx}},{{end}}<a href="/user/{{ $usr.ID }}">{{ $usr.Name }}</a>{{ end }}
+    <tbody>
+      <form id="save" method="POST" action="/battle/{{ .battle.ID }}">
+        <tr>
+          <td><label for="name">Name:</label></td>
+          <td><input class="border" type="text" id="name" name="name" value="{{ .battle.Name }}"></td>
+        </tr>
+
+        <!--
+        <tr>
+          <td><label for="latestBotSubmission">Latest Bot Submission</label></td>
+          <td><input
+                class="border"
+                type="datetime-local"
+                id="latestBotSubmission"
+                name="latestBotSubmission"
+                value="2024-11-08T12:00"
+                ></td>
+        </tr>
+
+        <tr>
+          <td><label for="battleStart">Battle Start</label></td>
+          <td><input
+                class="border"
+                type="datetime-local"
+                id="battleStart"
+                name="battleStart"
+                value="2024-11-08T16:00"
+                ></td>
+        </tr>
+
+        <tr>
+          <td><label for="owners">Owners:</label></td>
+          <td>
+            {{ range $idx, $usr := .battle.Owners }}{{if $idx}},{{end}}<a href="/user/{{ $usr.ID }}">{{ $usr.Name }}</a>{{ end }}
+          </td>
+        </tr>
+        -->
+
+        <!--
+        <tr>
+          <td><label for="public">Public?</label></td>
+          <td><input type="checkbox" id="public" name="public" {{ if .battle.Public }}checked{{end}}/></td>
+        </tr>
+        -->
+
+        <tr>
+          <td>Archs</td>
+          <td>
+            {{ range $idx, $arch := .archs }}{{if $idx}},{{end}}
+              <input
+                type="checkbox"
+                class="check-with-label"
+                name="arch-{{$arch.ID}}"
+                id="arch-{{$arch.ID}}"
+                {{if $arch.Enabled}}checked{{end}}/>
+              <label class="label-for-check" for="arch-{{$arch.ID}}">{{$arch.Name}}</label>
+            {{- end }}
+          </td>
         </td>
-      </tr>
-
-      <tr>
-        <td><label for="bots">Bots:</label></td>
-        <td>
-          {{ range $idx, $bot := .battle.Bots }}{{if $idx}},{{end}}<a href="/bot/{{ $bot.ID }}">{{ $bot.Name }}</a>{{ end }}
-        </td>
-      </tr>
-      -->
 
-      <tr>
-        <td><label for="public">Public?</label></td>
-        <td><input type="checkbox" id="public" name="public" {{ if .battle.Public }}checked{{end}}/></td>
-      </tr>
-
-      <tr>
-        <td>Archs</td>
-        <td>
-          {{ range $idx, $arch := .archs }}{{if $idx}},{{end}}
+        <tr>
+          <td>Bits</td>
+          <td>{{ range $idx, $bit := .bits }}{{if $idx}},{{end}}
             <input
               type="checkbox"
               class="check-with-label"
-              name="arch-{{$arch.ID}}"
-              id="arch-{{$arch.ID}}"
-              {{if $arch.Enabled}}checked{{end}}/>
-            <label class="label-for-check" for="arch-{{$arch.ID}}">{{$arch.Name}}</label>
-          {{- end }}
-        </td>
-      </td>
+              id="bit-{{$bit.ID}}"
+              name="bit-{{$bit.ID}}"
+              {{if $bit.Enabled}}checked{{end}}/>
+            <label class="label-for-check" for="bit-{{$bit.ID}}">{{$bit.Name}}</label>
+            {{- end }}
+          </td>
+        </tr>
+
+        <tr>
+          <td>Arena size:</td>
+          <td>
+            <input class="border" type="number" name="arena-size" id="arena-size" value="{{ .battle.ArenaSize }}"/>
+          </td>
+        </tr>
+
+        <tr>
+          <td>Max Rounds:</td>
+          <td>
+            <input class="border" type="number" name="max-rounds" id="max-rounds" value="100"/>
+          </td>
+        </tr>
+
+        <tr>
+          <td>Owners</td>
+          <td>
+            {{ $viewerID := .user.ID }}
+            {{ $owners := .battle.Owners }}
+            {{ range $idx, $u := .users}}{{if $idx}},{{- end}}
+              <input
+                type="checkbox"
+                class="check-with-label"
+                name="owner-{{ $u.ID }}"
+                id="owner-{{ $u.ID }}"
+                {{if eq $u.ID $viewerID}}{{end}}
+
+                {{ range $idx, $own := $owners }}
+                  {{if eq $u.ID $own.ID}}checked{{end}}
+                {{ end }}
+                />
+              <label class="label-for-check" for="owner-{{ $u.ID }}">{{$u.Name}}</label>
+            {{- end }}
+          </td>
+        </tr>
+      </form>
 
       <tr>
-        <td>Bits</td>
-        <td>{{ range $idx, $bit := .bits }}{{if $idx}},{{end}}
-          <input
-            type="checkbox"
-            class="check-with-label"
-            id="bit-{{$bit.ID}}"
-            name="bit-{{$bit.ID}}"
-            {{if $bit.Enabled}}checked{{end}}/>
-          <label class="label-for-check" for="bit-{{$bit.ID}}">{{$bit.Name}}</label>
-          {{- end }}
+        <td></td>
+        <td width="100%">
+          <div style="display: grid; grid-template-columns: 32% 32% 32%; justify-content: space-between;">
+            <input class="border" type="submit" value="Save Settings" form="save" style="padding: 0 1ex; width: 100%">
+            <input class="border" type="submit" value="Run Battle" form="run" style="border: width: 100%">
+            <input class="border" type="submit" value="Delete this battle" form="delete" style="border: 1px solid red; background: red; color: white; width: 100%">
+          </div>
         </td>
-      </td>
+      </tr>
 
+      {{ if .res }}
       <tr>
         <td></td>
-        <td>
-          <table>
-            <tr>
-              <td style="width: 33%;"><input class="border" type="submit" value="Save"></td>
-              <td style="width: 33%;"></td>
-              <td style="width: 33%; ">
-                <input type="submit" value="Delete this battle" form="delete" style="border: 1px solid red; ">
-              </td>
-            </tr>
-          </table>
-        </td>
+        <td><div style="border: 1px solid blue; padding: 1ex">{{ .res }}</div></td>
       </tr>
+      {{ end }}
 
-    </form>
-
-    {{ if .res }}
-    <tr>
-      <td></td>
-      <td>{{ .res }}</td>
-    </tr>
-    {{ end }}
-
-    <tr>
-      <td><br><hr><br></td>
-      <td><br><hr><br></td>
-    </tr>
+      <tr>
+        <td><br><hr><br></td>
+        <td><br><hr><br></td>
+      </tr>
 
-    {{ if .myBots }}
+      {{ if .myBots }}
+
+      <form id="submit" method="POST" action="/battle/{{ .battle.ID }}/submit">
+        <tr>
+          <td><label for="name">My Bots</label></td>
+          <td style="width: 100%;">
+            <table style="width: 100%;">
+                {{ range $bot := .myBots  }}
+                <tr class="trhover">
+                  <td style="text-align: center; vertical-align: middle; width: 2ex;">
+                    <input
+                      type="checkbox"
+                      id="bot-{{$bot.ID}}"
+                      name="bot-{{$bot.ID}}"
+                      value="{{$bot.ID}}"
+                      {{ range $bbot := $.battle.Bots }}
+                      {{ if eq $bot.ID $bbot.ID }}checked{{ end }}
+                      {{ end }}
+                      />
+                    <label for="bot-{{$bot.ID}}">
+                      <a href="/bot/{{$bot.ID}}">{{$bot.Name}}</a>
+                    </label>
+                  </td>
+                  <td style="vertical-align: middle">
+                  </td>
+                </tr>
+                {{ end }}
+            </table>
+          </td>
+        </tr>
+      </form>
+
+      <form id="run" method="POST" action="/battle/{{ .battle.ID }}/run"> </form>
+      <form id="delete" method="POST" action="/battle/{{ .battle.ID }}/delete"></form>
 
-    <form method="POST" action="/battle/{{ .battle.ID }}/submit">
       <tr>
-        <td><label for="name">My Bots</label></td>
-        <td style="width: 100%;">
-          <table class="trhover">
-            {{ range $bot := .myBots  }}
-            <tr>
-              <td style="text-align: center; vertical-align: middle; width: 2ex;">
-                <input
-                  type="checkbox"
-                  id="bot-{{$bot.ID}}"
-                  name="bot-{{$bot.ID}}"
-                  value="{{$bot.ID}}" />
-              </td>
-              <td style="vertical-align: middle">
-                <label for="bot-{{$bot.ID}}">
-                  <a href="/bot/{{$bot.ID}}">{{$bot.Name}}</a>
-                </label>
-              </td>
-            </tr>
-            {{ end }}
-          </table>
+        <td></td>
+        <td width="100%">
+          <div style="display: grid; grid-template-columns: 100%; justify-content: space-between;">
+            <input class="border" type="submit" value="Submit Bots" form="submit" style="width: 100%">
+          </div>
         </td>
       </tr>
 
+      {{ else }}
       <tr>
         <td></td>
-        <td><input class="border" type="submit" value="Submit"></td>
+        <td><a href='/bot/new'>Upload a bot</a> to get started!</td>
       </tr>
-    </form>
-
-    {{ else }}
-
-    <tr>
-      <td></td>
-      <td><a href='/bot/new'>Upload a bot</a> to get started!</td>
-    </tr>
+      {{ end }}
 
-    {{ end }}
+    </tbody>
   <table>
 
-  <span id="elimination-ladder"></span>
-  <h2><a href="#elimination-ladder">Elimination Ladder</a></h2>
-
-  <span id="round-1"></span>
-  <h3><a href="#round-1">Round 1</a></h2>
-
-  <br><a href="">Round 1.1</a>: <a href="">bot1</a> vs <a href="">bot2</a>
-  <br><a href="">Round 1.2</a>: <a href="">bot3</a> vs <a href="">bot4</a>
-  <br>
-  <br><a href="">Round 1.3</a>: <a href="">bot1</a> vs <a href="">bot2</a>
-  <br><a href="">Round 1.4</a>: <a href="">bot3</a> vs <a href="">bot4</a>
-
-  <span id="round-2"></span>
-  <h3><a href="#round-2">Round 2</a></h2>
-
-  <br><a href="">Round 2.1</a>: winner of <a href="">round 1.1</a> vs winner of <a href="">round 1.2</a>
-  <br><a href="">Round 2.2</a>: winner of <a href="">round 1.3</a> vs winner of <a href="">round 1.4</a>
-
-  <span id="round-3"></span>
-  <h3><a href="#round-3">Round 3</a></h2>
-
-  <br><a href="">Round 3.1</a>: winner of <a href="">round 2.1</a> vs winner of <a href="">round 2.2</a>
-
-  <span id="current-standings"></span>
-  <h2><a href="#current-standings">Current Standings</a></h2>
-
-  <p>There are {{ .botAmount }} Bots in this battle, as we're executing each battle two times with all permutations, we're executing {{ .battleCount }} battles.</p>
-
-  <br>What is Lorem Ipsum?
-  <br>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
-
-  <br>Why do we use it?
-  <br>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
+  <span id="registered bots"></span>
+  <h2><a href="#registered-bots">Registered Bots</a></h2>
 
+  {{ range $idx, $bot := .battle.Bots}}{{if $idx}}, {{end}}<a href="/bot/{{ $bot.ID }}">{{ $bot.Name }}</a>{{ end -}}
 
-  <br>Where does it come from?
-  <br>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.
+  <span id="output"></span>
+  <h2><a href="#output">Output</a></h2>
+  <!--<details>-->
+  <pre>{{ .battle.RawOutput }}</pre>
+  <!--</details>-->
 
-  <br>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.
+  <span id="debug"></span>
+  <h2><a href="#debug">Debug</a></h2>
+  <details> <pre>{{ . }}</pre> </details> </body>
 
-  <br>Where can I get some?
-  <br>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.
-  <br>Where can I get some?
-  <br>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.
-  <br>Where can I get some?
-  <br>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.
-  <br>Where can I get some?
-  <br>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.
-</body>
 {{ template "footer" . }}
 {{ end }}
diff --git a/templates/battles.html b/templates/battles.html
index bdc4d4b..d3f85da 100644
--- a/templates/battles.html
+++ b/templates/battles.html
@@ -10,9 +10,9 @@
   <p>A battle is a collection of matches. It plays through all matches in the elimination ladder in order to determine an overall winner.</p>
   <br>
 
-  <table class="trhover">
+  <table>
   {{ range $battle := .battles }}
-    <tr>
+    <tr class="trhover">
       <td>
         - <a href="/battle/{{ $battle.ID }}">{{ $battle.Name }}</a>
       </td>
diff --git a/templates/botSingle.html b/templates/botSingle.html
index dcb874f..024e2c1 100644
--- a/templates/botSingle.html
+++ b/templates/botSingle.html
@@ -75,10 +75,14 @@
       <tr><td><hr></td><td><hr></td></tr>
 
       <tr>
-        <td>CMD</td>
-        <td>{{ .bytecode_r2cmd }}</td>
+        <td></td>
+        <td>Command converting your source into bytes:</td>
       </tr>
-      <tr>
+      <tr class="trhover">
+        <td style="width: 100ex; ">CMD</td>
+        <td style="width: 100ex; ">{{ .bytecode_r2cmd }}</td>
+      </tr>
+      <tr class="trhover">
         <td>Bytecode</td>
         <td>{{ .bytecode }}</td>
       </tr>
@@ -86,10 +90,14 @@
       <tr><td><hr></td><td><hr></td></tr>
 
       <tr>
+        <td></td>
+        <td>The disassembly of your source:</td>
+      </tr>
+      <tr class="trhover">
         <td>CMD</td>
         <td>{{ .disasm_r2cmd }}</td>
       </tr>
-      <tr>
+      <tr class="trhover">
         <td>Disasm</td>
         <td><pre>{{ .disasm }}</pre></td>
       </tr>
diff --git a/templates/bots.html b/templates/bots.html
index 34fa0c2..70018dd 100644
--- a/templates/bots.html
+++ b/templates/bots.html
@@ -7,7 +7,11 @@
   <span id="allbots"></span>
   <h1><a href="#allbots">All Bots</a></h1>
 
-  <table class="trhover">
+  <table>
+    <tr>
+      <td>Bot</td>
+      <td>User</td>
+    <tr>
   {{ range $bot := .bots }}
     <tr>
       <td>
diff --git a/templates/footer.html b/templates/footer.html
index cb7b0c9..7c8682f 100644
--- a/templates/footer.html
+++ b/templates/footer.html
@@ -3,4 +3,5 @@
 <br><br><hr><br>
 {{ . }}
 {{ end }}
+</div>
 {{ end }}
diff --git a/templates/head.html b/templates/head.html
index 42d569c..75c3d21 100644
--- a/templates/head.html
+++ b/templates/head.html
@@ -8,7 +8,7 @@
   <title>r2wa.rs</title>
 
   <style>
-* { word-wrap:break-word !important; font-family: monospace; margin: 0; padding: 0; }
+* { word-wrap:break-word; font-family: monospace; margin: 0; padding: 0; }
 
 /* light/darktheme specific foo */
 @media (prefers-color-scheme: light) {
@@ -26,7 +26,7 @@
   h5 { margin: 1ex 0 1ex 0; width: 100%; font-size: 1em; /*background-color: #fafafa*/}
   .code { border-left: 1px solid #040404; margin-left: 2ex; padding-left: 1ex; }
   .codeline:hover { background: #eeeeee; color: #040404; }
-  .trhover tr:hover { border-bottom: 1px solid #dddddd; }
+  .trhover:hover { background: #c0c0c0; color: #040404; }
 
   /* add an outline while hovering, the !important makes hovering on checked elements still visible */
   .check-with-label:checked + .label-for-check { background-color: #040404; color: #eeeeee !important; }
@@ -50,14 +50,14 @@
   .code { border-left: 1px solid #c0c0c0; margin-left: 2ex;  padding-left: 1ex; }
   .codeline:hover { background: #c0c0c0; color: #040404; }
   .webring { -webkit-filter: invert(100%); filter: invert(100%); }
-  .trhover tr:hover { background: #c0c0c0; color: #040404; }
+  .trhover:hover { background: #c0c0c0; color: #040404; }
 
   /* add an outline while hovering, the !important makes hovering on checked elements still visible */
   .check-with-label:checked + .label-for-check { background-color: #c0c0c0; color: #040404 !important; }
   .check-with-label:hover + .label-for-check { outline: 1px solid #c0c0c0; color: #c0c0c0; }
 
   input, textarea { background-color: #c0c0c0; }
-  .border { outline: 1px solid #c0c0c0; border: none; }
+  .border { outline: 1px solid #000000; border: none; }
 }
 
 /* settings for mobile devices*/
@@ -65,6 +65,12 @@
   body { margin: 1ex; width: calc(100% - 2ex) !important; }
   img { max-width: 100% !important; max-height: 500px; }
 }
+
+/* only display the hover dropdown on non-mobile devices */
+@media only screen and (min-width: 768px) {
+  nav ul li:hover a + ul { display: inherit; white-space: nowrap; }
+}
+
 img { max-width: 100ex; max-height: 500px; }
 
 body { margin-left: auto; margin-right: auto; margin-top: 1ex; margin-bottom: 1ex; width: 100ex; }
@@ -78,7 +84,7 @@ body a:not(h1 a, h2 a, h3 a,h4 a):not([href*="webring.xxiivv.com"]):not([class*=
 a[href*="//"]:not([href*="r2wa.rs"]):not([class*="icon"]):before { content: '{'; }
 a[href*="//"]:not([href*="r2wa.rs"]):not([class*="icon"]):after { content: '}'; }
 
-table { width: 100%; }
+/* table { width: 100ex; } */
 input, textarea { width: 100%; }
 textarea { padding: 0.5ex; }
 
@@ -92,11 +98,6 @@ nav ul ul { display: none; position: absolute; outline: 1px solid #040404; backg
 nav ul ul li { width: 100%; padding-right: 1ex; float:none; display:list-item; position: relative; }
 nav + ul li { display: inline-block;}
 
-/* only display the hover dropdown on non-mobile devices */
-@media only screen and (min-width: 768px) {
-  nav ul li:hover a + ul { display: inherit; white-space: nowrap; }
-}
-
 /* nav bar spacing char */
 nav ul li > a::after { content: " /"; }
 nav ul li > a:only-child::after { content: ""; }
@@ -113,10 +114,13 @@ nav + ul.vert li { display: block; }
 
 .w-100 { width: 100%; }
 
-.check-with-label { display: none; }
+.check-with-label { display: none; } /* checkbox with a label */
 
-body table tbody tr td { padding-bottom: 0.5ex; vertical-align: top; }
-body table tbody tr td:not(:last-child) { padding-right: 1ex; }
+/* In tables, make the first column fit the content and the reset be relaxed */
+body table tbody { width: 100%; word-wrap: break-word; }
+/* body table tbody tr>td { padding: 0.5ex 0 0.5ex !important; } */
+body table tbody tr td:nth-child(1) { width: auto; white-space: nowrap; padding-right: 1ex; }
+body table tbody tr td:not(:nth-child(1)) { width: 100%; max-width: 100%; word-wrap: anywhere; }
 
 tr { text-wrap: wrap;}
 
diff --git a/templates/index.html b/templates/index.html
index ab869da..5d033c5 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -50,18 +50,6 @@
   <br>
   <br>
 
-  <pre>
-╭──╮    ╭──────────────────────╮
-│ _│_   │                      │
-│ O O  <  LET THE GAMES BEGIN! │
-│  │╷   │                      │
-│  ││   ╰──────────────────────╯
-│ ─╯│
-╰───╯
-  </pre>
-
-
-
 </body>
 {{ template "footer" . }}
 {{ end }}
diff --git a/templates/nav.html b/templates/nav.html
index ea1e1af..bdad48d 100644
--- a/templates/nav.html
+++ b/templates/nav.html
@@ -1,7 +1,7 @@
 {{ define "nav" }}
   <header>
-    <p style="margin: 1ex 0; display: block; width: 100%; background-color: red; color: white;">
-      EARLY BETA - Data can be deleted at random!
+    <p style="margin: 1ex 0; display: block; width: 100%; background-color: #ffaa00; color: white;">
+      v0.0.0.0.0.0.1 EARLY BETA - Data can be deleted at random!
     </p>
 
     <a href="/">r2wa.rs</a>
@@ -16,9 +16,11 @@
         <ul>
           {{ if .pagelink1options }}
           {{ range $opt := .pagelink1options }}
+          {{ if eq $opt.Name $.pagelink1.Name }}{{ else }}
           <li><a class="local" href="{{ $opt.Target }}">{{ $opt.Name }}</a></li>
           {{ end }}
           {{ end }}
+          {{ end }}
         </ul>
       </li>
       {{ end }}
@@ -28,9 +30,11 @@
         <ul>
           {{ if .pagelink2options }}
           {{ range $opt := .pagelink2options }}
+          {{ if eq $opt.Name $.pagelink2.Name }}{{ else }}
           <li><a class="local" href="{{ $.pagelink1.Target }}{{ $opt.Target }}">{{ $opt.Name }}</a></li>
           {{ end }}
           {{ end }}
+          {{ end }}
         </ul>
       </li>
       {{ end }}
@@ -40,16 +44,18 @@
         <ul>
           {{ if .pagelink3options }}
           {{ range $opt := .pagelink3options }}
+          {{ if eq $opt.Name $.pagelink3.Name }}{{ else }}
           <li><a class="local" href="{{ $.pagelink1.Target }}{{ $.pagelink2.Target }}{{ $opt.Target }}">{{ $opt.Name }}</a></li>
           {{ end }}
           {{ end }}
+          {{ end }}
         </ul>
       </li>
       {{ end }}
     </ul>
     <ul style="float: right">
         <li>
-            <a href="https://github.com/HanEmile/r2wars-web">{{ .version }} src</a>
+            <a href="https://github.com/HanEmile/r2wars-web">{{if .version}}{{ .version }} src{{else}}src{{end}}</a>
         </li>
     </ul>
   </nav>
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 7f035d7..e5c09e7 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -36,8 +36,6 @@ github.com/radareorg/r2pipe-go
 # github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec
 ## explicit; go 1.12
 github.com/remyoudompheng/bigfft
-# github.com/xiaoqidun/entps v1.32.0
-## explicit; go 1.20
 # golang.org/x/crypto v0.26.0
 ## explicit; go 1.20
 golang.org/x/crypto/argon2