diff --git a/agt/ballotagent/ballotagent.go b/agt/ballotagent/ballotagent.go
new file mode 100644
index 0000000000000000000000000000000000000000..8d23345d407b2c047d1117bcf06eb32a356d192b
--- /dev/null
+++ b/agt/ballotagent/ballotagent.go
@@ -0,0 +1,76 @@
+package ballotagent
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"log"
+	"net/http"
+	"sync"
+	"time"
+
+	rad "gitlab.utc.fr/gvandevi/ia04binome2a" // à remplacer par le nom du dossier actuel
+)
+
+type BallotServerAgent struct {
+	sync.Mutex
+	id       string
+	reqCount int
+	addr     string
+	ballots  map[rad.Ballot]BallotInfo
+}
+
+func NewBallotServerAgent(addr string) *BallotServerAgent {
+	return &BallotServerAgent{id: addr, addr: addr}
+}
+
+// Test de la méthode
+func (rsa *BallotServerAgent) checkMethod(method string, w http.ResponseWriter, r *http.Request) bool {
+	if r.Method != method {
+		w.WriteHeader(http.StatusMethodNotAllowed)
+		fmt.Fprintf(w, "method %q not allowed", r.Method)
+		return false
+	}
+	return true
+}
+
+func decodeRequest[Req rad.Request](r *http.Request) (req Req, err error) {
+	buf := new(bytes.Buffer)
+	buf.ReadFrom(r.Body)
+	err = json.Unmarshal(buf.Bytes(), &req)
+	return
+}
+
+func (rsa *BallotServerAgent) doReqcount(w http.ResponseWriter, r *http.Request) {
+	if !rsa.checkMethod("GET", w, r) {
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+	rsa.Lock()
+	defer rsa.Unlock()
+	serial, _ := json.Marshal(rsa.reqCount)
+	w.Write(serial)
+}
+
+func (rsa *BallotServerAgent) Start() {
+	// création du multiplexer
+	mux := http.NewServeMux()
+	mux.HandleFunc("/new_ballot", rsa.createBallot)
+	mux.HandleFunc("/vote", rsa.doReqcount)
+	mux.HandleFunc("/result", rsa.doReqcount)
+
+	rsa.ballots = make(map[rad.Ballot]BallotInfo)
+
+	// création du serveur http
+	s := &http.Server{
+		Addr:           rsa.addr,
+		Handler:        mux,
+		ReadTimeout:    10 * time.Second,
+		WriteTimeout:   10 * time.Second,
+		MaxHeaderBytes: 1 << 20}
+
+	// lancement du serveur
+	log.Println("Listening on", rsa.addr)
+	go log.Fatal(s.ListenAndServe())
+}
diff --git a/agt/ballotagent/new_ballot.go b/agt/ballotagent/new_ballot.go
new file mode 100644
index 0000000000000000000000000000000000000000..e0121b2a7c47f00407789e8298af578fa39b32b5
--- /dev/null
+++ b/agt/ballotagent/new_ballot.go
@@ -0,0 +1,182 @@
+package ballotagent
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"time"
+
+	rad "gitlab.utc.fr/gvandevi/ia04binome2a"
+	cs "gitlab.utc.fr/gvandevi/ia04binome2a/comsoc"
+)
+
+type BallotInfo struct {
+	profile  cs.Profile
+	options  [][]int
+	votersId []string
+	nbAlts   int
+	isOpen   bool
+	results  rad.ResultResponse
+}
+
+func (rsa *BallotServerAgent) createBallot(w http.ResponseWriter, r *http.Request) {
+	// mise à jour du nombre de requêtes
+	rsa.Lock()
+	defer rsa.Unlock()
+	rsa.reqCount++
+
+	// vérification de la méthode de la requête
+	if !rsa.checkMethod("POST", w, r) {
+		return
+	}
+
+	// décodage de la requête
+	req, err := decodeRequest[rad.BallotRequest](r)
+	if err != nil {
+		w.WriteHeader(http.StatusBadRequest)
+		fmt.Fprint(w, err.Error())
+		return
+	}
+	// Check for valid deadline formatting
+	deadline, errTime := time.Parse(time.RFC3339, req.Deadline)
+	if errTime != nil {
+		w.WriteHeader(http.StatusBadRequest)
+		msg := fmt.Sprintf("'%s' n'utilise pas le bon format, merci d'utiliser RFC3339 ", req.Deadline)
+		w.Write([]byte(msg))
+		return
+	}
+	// Check if the deadline is in the future
+	if deadline.Before(time.Now()) {
+		w.WriteHeader(http.StatusBadRequest)
+		msg := fmt.Sprintf("'%s' est déjà passé ", req.Deadline)
+		w.Write([]byte(msg))
+		return
+	}
+
+	// traitement de la requête
+	var resp rad.Ballot
+
+	resp.BallotID = fmt.Sprintf("scrutin%d", len(rsa.ballots)+1)
+	rsa.ballots[resp] = BallotInfo{
+		profile:  make(cs.Profile, 0),
+		options:  make([][]int, 0),
+		votersId: req.VotersID,
+		nbAlts:   req.NbAlts,
+		isOpen:   true,
+		results:  rad.ResultResponse{}}
+
+	tb := make([]cs.Alternative, 0)
+	for _, alt := range req.TieBreak {
+		tb = append(tb, cs.Alternative(alt))
+	}
+
+	switch req.Rule {
+	case "majority":
+		go rsa.handleBallot(resp, cs.MajoritySWF, cs.MajoritySCF, tb, deadline)
+	case "borda":
+		go rsa.handleBallot(resp, cs.BordaSWF, cs.BordaSCF, tb, deadline)
+	case "approval":
+		go rsa.handleBallotWithSingleOption(resp, cs.ApprovalSWF, cs.ApprovalSCF, tb, deadline)
+	default:
+		w.WriteHeader(http.StatusNotImplemented)
+		msg := fmt.Sprintf("Unkonwn rule '%s'", req.Rule)
+		w.Write([]byte(msg))
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+	serial, _ := json.Marshal(resp)
+	w.Write(serial)
+}
+
+func (rsa *BallotServerAgent) handleBallot(
+	ballot rad.Ballot,
+	swf func(cs.Profile) (cs.Count, error),
+	scf func(cs.Profile) ([]cs.Alternative, error),
+	orderedTBAlts []cs.Alternative,
+	deadline time.Time,
+) {
+	time.Sleep(time.Until(deadline))
+	targetBallot := rsa.ballots[ballot]
+	profile := targetBallot.profile
+
+	// If profile is empty, set winner as 0 and ranking as empty list
+	if len(profile) == 0 {
+		targetBallot.results = rad.ResultResponse{Winner: 0, Ranking: make([]int, 0)}
+		fmt.Println(ballot.BallotID, "n'a pas reçu de votes.")
+		return
+	}
+
+	tb := cs.TieBreakFactory(orderedTBAlts)
+	ballotSWF := cs.SWFFactory(swf, tb)
+	ballotSCF := cs.SCFFactory(scf, tb)
+	ranking, _ := ballotSWF(profile)
+	winner, err := ballotSCF(profile)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	intRanking := make([]int, 0)
+	for _, alt := range ranking {
+		intRanking = append(intRanking, int(alt))
+	}
+
+	rsa.ballots[ballot] = BallotInfo{
+		profile:  profile,
+		options:  targetBallot.options,
+		votersId: targetBallot.votersId,
+		nbAlts:   targetBallot.nbAlts,
+		isOpen:   false,
+		results:  rad.ResultResponse{Winner: int(winner), Ranking: intRanking},
+	}
+}
+
+func (rsa *BallotServerAgent) handleBallotWithSingleOption(
+	ballot rad.Ballot,
+	swf func(cs.Profile, []int) (cs.Count, error),
+	scf func(cs.Profile, []int) ([]cs.Alternative, error),
+	orderedTBAlts []cs.Alternative,
+	deadline time.Time,
+) {
+	time.Sleep(time.Until(deadline))
+	targetBallot := rsa.ballots[ballot]
+	targetBallot.isOpen = false
+	profile := targetBallot.profile
+	options := targetBallot.options
+
+	// If profile is empty, set winner as 0 and ranking as empty list
+	if len(profile) == 0 {
+		targetBallot.results = rad.ResultResponse{Winner: 0, Ranking: make([]int, 0)}
+		fmt.Println(ballot.BallotID, "n'a pas reçu de votes.")
+		return
+	}
+
+	// Only the fist element of the agents' options is filled/matters
+	singleOptions := make([]int, len(options))
+	for i, option := range options {
+		singleOptions[i] = option[0]
+	}
+
+	tb := cs.TieBreakFactory(orderedTBAlts)
+	ballotSWF := cs.SWFFactoryWithOptions(swf, tb)
+	ballotSCF := cs.SCFFactoryWithOptions(scf, tb)
+	ranking, _ := ballotSWF(profile, singleOptions)
+	winner, err := ballotSCF(profile, singleOptions)
+	if err != nil {
+		fmt.Println(err)
+		return
+	}
+	intRanking := make([]int, 0)
+	for _, alt := range ranking {
+		intRanking = append(intRanking, int(alt))
+	}
+
+	rsa.ballots[ballot] = BallotInfo{
+		profile:  profile,
+		options:  targetBallot.options,
+		votersId: targetBallot.votersId,
+		nbAlts:   targetBallot.nbAlts,
+		isOpen:   false,
+		results:  rad.ResultResponse{Winner: int(winner), Ranking: intRanking},
+	}
+}
diff --git a/agt/voteragent/voteragent.go b/agt/voteragent/voteragent.go
new file mode 100644
index 0000000000000000000000000000000000000000..f59b497f47bbecf4e4aa782648be3e66e0822c30
--- /dev/null
+++ b/agt/voteragent/voteragent.go
@@ -0,0 +1,60 @@
+package voteragent
+
+type RestClientAgent struct {
+	id       string
+	url      string
+	operator string
+	arg1     int
+	arg2     int
+}
+
+func NewRestClientAgent(id string, url string, op string, arg1 int, arg2 int) *RestClientAgent {
+	return &RestClientAgent{id, url, op, arg1, arg2}
+}
+
+//func (rca *RestClientAgent) treatResponse(r *http.Response) int {
+//	buf := new(bytes.Buffer)
+//	buf.ReadFrom(r.Body)
+//
+//	var resp rad.Response
+//	json.Unmarshal(buf.Bytes(), &resp)
+//
+//	return resp.Result
+//}
+//
+//func (rca *RestClientAgent) doRequest() (res int, err error) {
+//	req := rad.Request{
+//		Operator: rca.operator,
+//		Args:     [2]int{rca.arg1, rca.arg2},
+//	}
+//
+//	// sérialisation de la requête
+//	url := rca.url + "/calculator"
+//	data, _ := json.Marshal(req)
+//
+//	// envoi de la requête
+//	resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
+//
+//	// traitement de la réponse
+//	if err != nil {
+//		return
+//	}
+//	if resp.StatusCode != http.StatusOK {
+//		err = fmt.Errorf("[%d] %s", resp.StatusCode, resp.Status)
+//		return
+//	}
+//	res = rca.treatResponse(resp)
+//
+//	return
+//}
+
+//func (rca *RestClientAgent) Start() {
+//	log.Printf("démarrage de %s", rca.id)
+//	res, err := rca.doRequest()
+//
+//	if err != nil {
+//		log.Fatal(rca.id, "error:", err.Error())
+//	} else {
+//		log.Printf("[%s] %d %s %d = %d\n", rca.id, rca.arg1, rca.operator, rca.arg2, res)
+//	}
+//}
diff --git a/cmd/launch-all-rest-agents/launch-all-agents.go b/cmd/launch-all-rest-agents/launch-all-agents.go
new file mode 100644
index 0000000000000000000000000000000000000000..776283d249820aa7e0d07710e97dc1037173e1cc
--- /dev/null
+++ b/cmd/launch-all-rest-agents/launch-all-agents.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"math/rand"
+
+	ba "gitlab.utc.fr/gvandevi/ia04binome2a/agt/ballotagent"
+	va "gitlab.utc.fr/gvandevi/ia04binome2a/agt/voteragent"
+)
+
+func main() {
+	const n = 100
+	const url1 = ":8080"
+	const url2 = "http://localhost:8080"
+	ops := [...]string{"+", "-", "*"}
+
+	clAgts := make([]va.RestClientAgent, 0, n)
+	servAgt := ba.NewBallotServerAgent(url1)
+
+	log.Println("démarrage du serveur...")
+	go servAgt.Start()
+
+	log.Println("démarrage des clients...")
+	for i := 0; i < n; i++ {
+		id := fmt.Sprintf("id%02d", i)
+		op := ops[rand.Intn(3)]
+		op1 := rand.Intn(100)
+		op2 := rand.Intn(100)
+		agt := va.NewRestClientAgent(id, url2, op, op1, op2)
+		clAgts = append(clAgts, *agt)
+	}
+
+	for _, agt := range clAgts {
+		// attention, obligation de passer par cette lambda pour faire capturer la valeur de l'itération par la goroutine
+		func(agt va.RestClientAgent) {
+			go agt.Start()
+		}(agt)
+	}
+
+	fmt.Scanln()
+}
diff --git a/cmd/launch-bagt/launch-bagt.go b/cmd/launch-bagt/launch-bagt.go
new file mode 100644
index 0000000000000000000000000000000000000000..5c8a75d8b5e238232f3f77da4587d34b293bce2c
--- /dev/null
+++ b/cmd/launch-bagt/launch-bagt.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+	"fmt"
+
+	ba "gitlab.utc.fr/gvandevi/ia04binome2a/agt/ballotagent"
+)
+
+func main() {
+	server := ba.NewBallotServerAgent(":8080")
+	server.Start()
+	fmt.Scanln()
+}
diff --git a/cmd/launch-vagt/launch-vagt.go b/cmd/launch-vagt/launch-vagt.go
new file mode 100644
index 0000000000000000000000000000000000000000..11556351cfedfe33ed9dd61f642129cae0f99d16
--- /dev/null
+++ b/cmd/launch-vagt/launch-vagt.go
@@ -0,0 +1,13 @@
+package main
+
+import (
+	"fmt"
+
+	va "gitlab.utc.fr/gvandevi/ia04binome2a/agt/voteragent"
+)
+
+func main() {
+	ag := va.NewRestClientAgent("id1", "http://localhost:8080", "+", 11, 1)
+	ag.Start()
+	fmt.Scanln()
+}
diff --git a/comsoc/TieBreak.go b/comsoc/TieBreak.go
index 78f89aa64ddf60c47b88a60a654b52d3a2bf7781..814c3064a995d6ebdf7b860c8ff0afd698d8a2f0 100644
--- a/comsoc/TieBreak.go
+++ b/comsoc/TieBreak.go
@@ -62,6 +62,47 @@ func SWFFactory(swf func(Profile) (Count, error), tb func([]Alternative) (Altern
 	}
 }
 
+func SWFFactoryWithOptions(
+	swf func(Profile, []int) (Count, error),
+	tb func([]Alternative) (Alternative, error),
+) func(Profile, []int) ([]Alternative, error) {
+
+	return func(p Profile, o []int) ([]Alternative, error) {
+		//récupération du décompte
+		count, errSWF := swf(p, o)
+		if errSWF != nil {
+			return nil, errSWF
+		}
+		//préparation de la sortie
+		var sortedAlts []Alternative
+
+		//PARCOURS DU DECOMPTE
+		for len(count) > 0 {
+			//On prend les meilleures alternatives (avant tie break)
+			bestAlts := maxCount(count)
+			//On supprime les meilleures alternatives du décompte
+			for alt := range bestAlts {
+				delete(count, Alternative(alt))
+			}
+			//Départage
+			for len(bestAlts) > 0 {
+				bestAlt, errTB := tb(bestAlts)
+				if errTB != nil {
+					return nil, errTB
+				}
+				//ajout de la meilleure alternative post-tie break
+				sortedAlts = append(sortedAlts, bestAlt)
+				//suppression de l'alternative dans bestAlts
+				indice := rank(bestAlt, bestAlts)
+				bestAlts = append(bestAlts[:indice], bestAlts[indice+1:]...)
+				//suppression de l'alternativ dans le compte
+				delete(count, Alternative(bestAlt))
+			}
+		}
+		return sortedAlts, nil
+	}
+}
+
 func Test_sWFFactory() {
 	//Définition de l'Ordre strict
 	orderedAlts := []Alternative{8, 9, 6, 1, 3, 2}
@@ -94,6 +135,23 @@ func SCFFactory(scf func(p Profile) ([]Alternative, error), tb func([]Alternativ
 		return bestAlt, errTB
 	}
 }
+
+func SCFFactoryWithOptions(
+	scf func(Profile, []int) ([]Alternative, error),
+	tb func([]Alternative) (Alternative, error),
+) func(Profile, []int) (Alternative, error) {
+	return func(p Profile, o []int) (Alternative, error) {
+		//récupération des meilleures alternatives
+		bestAlts, errSCF := scf(p, o)
+		if errSCF != nil {
+			return Alternative(0), errSCF
+		}
+		//récupération de la meilleure alternative
+		bestAlt, errTB := tb(bestAlts)
+		return bestAlt, errTB
+	}
+}
+
 func Test_sCFFactory() {
 	//Définition de l'Ordre strict
 	orderedAlts := []Alternative{8, 9, 6, 1, 3, 2}
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..75cb7767e82625f465c891759035ff649b26f661
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,11 @@
+# Exemple de serveur Rest en Go
+
+Un agent permet de faire de petites opérations arithmétiques (`+`, `-`, `*`) sur 2 entiers si on lui demande en REST.
+
+Techniquement le serveur n'est pas pur REST (à vous de trouver pourquoi), mais il est fonctionnel et peut tenir la charge.
+
+3 exécutables (indépendants) sont fournis :
+
+* `launch-all-rest-agents` permet de lancer une démo avec un seul exécutable
+* `lanch-rsagt` permet de lancer un agent de type serveur
+* `lanch-rsagt` permet de lancer un agent de type client
\ No newline at end of file
diff --git a/types.go b/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..387efff38ec8d42122cbe2a54b86cca02e2fa589
--- /dev/null
+++ b/types.go
@@ -0,0 +1,29 @@
+package ia04binome2a
+
+type BallotRequest struct {
+	Rule     string   `json:"rule"`
+	Deadline string   `json:"deadline"`
+	VotersID []string `json:"voters-id"`
+	NbAlts   int      `json:"#alts"`
+	TieBreak []int    `json:"tie-break"`
+}
+
+type Vote struct {
+	AgentID  string `json:"agent-id"`
+	BallotID string `json:"ballot-id"`
+	Prefs    []int  `json:"prefs"`
+	Options  []int  `json:"options"`
+}
+
+type Ballot struct {
+	BallotID string `json:"ballot-id"`
+}
+
+type ResultResponse struct {
+	Winner  int   `json:"winner"`
+	Ranking []int `json:"ranking"`
+}
+
+type Request interface {
+	BallotRequest | Ballot | Vote
+}