diff --git a/.gitignore b/.gitignore
index 7ece5fbacc5cb647f56e4b10e0320b5bcad6b4f1..e7f54c1f2d11142d30369965f6987f1d317d4700 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ target
# dependencies
node_modules
+node
# IDEs and editors
/.idea
@@ -17,6 +18,8 @@ node_modules
*.launch
.settings/
*.sublime-workspace
+.java-version
+*.iml
# IDE - VSCode
.vscode/*
diff --git a/README.adoc b/README.adoc
index c5c655fc49b901811df513c1a5dbdfb3a052c495..4a31eac84355fb461fe03892dba45ad64567fe04 100644
--- a/README.adoc
+++ b/README.adoc
@@ -23,4 +23,10 @@ service. Après avoir lancé un SOS, le capitaine ordonne l’évacuation du vai
l’inévitable crash.
Sains et saufs, vous entamez l’exploration des environs lorsque vous entendez les cris
d’agonie de votre capitaine. Au loin, vous distinguez une silhouette qui vous observe.
-Vous n’êtes pas seul …
\ No newline at end of file
+Vous n’êtes pas seul...
+
+== Project Layout
+
+The current source code organization is based on the following article:
+
+https://frakton.com/utilizing-maven-front-end-plugin-for-angular-spring-boot/
\ No newline at end of file
diff --git a/not-alone-core/.gitignore b/not-alone-core/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..81325b3d8200e98905917c1c244bd7c9c23841bd
--- /dev/null
+++ b/not-alone-core/.gitignore
@@ -0,0 +1,2 @@
+/bin/
+
diff --git a/not-alone-core/pom.xml b/not-alone-core/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f7ebef956b4eaaf5ac3325e01d94b8e9b2ce0ea1
--- /dev/null
+++ b/not-alone-core/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ not-alone
+ fr.univnantes.alma
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ not-alone-core
+ Not Alone Core
+
+
+
+
+ org.apache.thrift.tools
+ maven-thrift-plugin
+
+ java
+
+
+
+ thrift-compile
+ generate-sources
+
+ compile
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ build-helper-add-source
+ generate-sources
+
+ add-source
+
+
+
+ ${project.build.directory}/generated-sources/thrift/
+
+
+
+
+
+
+
+
+
+
+ org.apache.thrift
+ libthrift
+
+
+
diff --git a/not-alone-core/src/main/thrift/common.thrift b/not-alone-core/src/main/thrift/common.thrift
new file mode 100644
index 0000000000000000000000000000000000000000..03e419022d874fecc1e99ecc2540c4b01f5c3344
--- /dev/null
+++ b/not-alone-core/src/main/thrift/common.thrift
@@ -0,0 +1,138 @@
+namespace java fr.univnantes.alma.thrift
+namespace js common
+
+exception InvalidOperationException {
+ 1: i32 code,
+ 2: string message
+}
+
+exception GameNotFound {
+ 1: i32 code,
+ 2: string message
+}
+
+struct Response{
+ 1: bool state,
+ 2: string message
+}
+
+struct TCard {
+ 1: string cardType,
+ 2: string cardName,
+ 3: list attributes
+}
+
+struct TJeton{
+ 1: string symbol
+}
+
+
+struct TBoard {
+ 1: string board
+}
+
+struct TColor {
+ 1: string color
+}
+
+struct TPositionJeton{
+ 1: list position
+}
+
+struct TPlacedJeton{
+ 1: TJeton jeton,
+ 2: TPositionJeton position
+}
+
+struct TPhase {
+ 1: string name
+}
+
+struct TPair {
+ 1: string key,
+ 2: string value
+}
+
+struct TAction {
+ 1: string type,
+ 2: list params
+}
+
+struct TAskAction {
+ 1: string type,
+ 2: string message,
+ 3: list choices
+}
+
+
+struct TPlayerTeam{
+ 1: string type
+}
+
+struct THand{
+ 1: list cards,
+ 2: list visibleCards,
+ 3: list jetons,
+ 4: i32 numberPionVolonte,
+ 5: list defausse,
+}
+
+struct TScore{
+ 1: i32 traqueScore,
+ 2: i32 creatureScore,
+ 3: TBoard boardDistribution,
+ 4: TColor boardColor
+}
+
+struct TPlacedCard{
+ 1: TCard card,
+ 2: string place
+}
+
+struct TBalise{
+ 1: string type,
+ 2: i32 state
+}
+
+struct TPlanet{
+ 1: list placedCard,
+ 2: list jetons,
+ 3: TBalise balise
+}
+
+struct TCardReserve{
+ 1: TCard card,
+ 2: i32 number
+}
+
+struct TTraque{
+ 1: string name,
+ 2: list visibleCards,
+ 3: i32 hiddenPlaceCardNumber,
+ 4: list defausse,
+ 5: i32 hiddenSurvivalCardNumber,
+ 6: i32 numberPionVolonte
+}
+
+struct TCreature{
+ 1: string name,
+ 2: list visibleCards,
+ 3: i32 hiddenTrackingCardNumber,
+ 4: list jetons
+}
+
+struct TGameVariable{
+ 1: string name,
+ 2: list values
+}
+
+struct TDescription{
+ 1: TPlayerTeam team,
+ 2: THand hand,
+ 3: TScore score,
+ 4: TPlanet planet
+ 5: list reserve,
+ 6: list variables,
+ 7: list traquesInformation,
+ 8: TCreature creatureInformation
+}
\ No newline at end of file
diff --git a/not-alone-core/src/main/thrift/game-service.thrift b/not-alone-core/src/main/thrift/game-service.thrift
new file mode 100644
index 0000000000000000000000000000000000000000..d3810b87c9ecce0d580c45b47f14d747214a3f7e
--- /dev/null
+++ b/not-alone-core/src/main/thrift/game-service.thrift
@@ -0,0 +1,45 @@
+include "common.thrift"
+
+namespace java fr.univnantes.alma.thrift
+namespace js common
+
+// Types
+
+struct JoinRequest {
+ 1: string name
+}
+
+struct TPlayer {
+ 1: string token,
+ 2: string name,
+ 3: string address,
+ 4: i32 port
+}
+
+struct TRoomId {
+ 1: string token
+}
+
+
+//Service
+
+service GameService {
+
+ TRoomId createRoom(TPlayer player) throws (1:common.InvalidOperationException e)
+
+ common.Response sendStartGame(TPlayer player, i32 creatureId, common.TBoard board, common.TColor color, list placeCards)
+
+ common.Response joinRoom(TPlayer player, TRoomId roomId)
+
+ common.TDescription getGameDescription(TPlayer player)
+
+ void sendFinishPhase(TPlayer player, common.TPhase phase)
+
+ void sendPlayCards(TPlayer player, list playerCards)
+
+ void sendPlaceJetons(TPlayer player, list placedJetons)
+
+ void sendResist(TPlayer player, i32 number)
+
+ void sendGiveUp(TPlayer player)
+}
diff --git a/not-alone-core/src/main/thrift/player-service.thrift b/not-alone-core/src/main/thrift/player-service.thrift
new file mode 100644
index 0000000000000000000000000000000000000000..e0f9e4b6764bc25a9c4494539a36a46eb8d2b6dd
--- /dev/null
+++ b/not-alone-core/src/main/thrift/player-service.thrift
@@ -0,0 +1,29 @@
+include "common.thrift"
+
+namespace java fr.univnantes.alma.thrift
+namespace js common
+
+
+//Service
+
+service PlayerService {
+ bool ping() throws (1:common.InvalidOperationException e)
+
+ void sendGameDescription(common.TDescription gameDescription)
+
+ void sendGameStart()
+
+ void sendGameIsFinished(common.TPlayerTeam winner)
+
+ void sendFirstRoundStart()
+
+ void sendStartPhase(common.TPhase phase, common.TDescription gameDescription)
+
+ common.TAction askAction(common.TAskAction askedAction)
+
+ void sendAction(common.TAskAction askedAction)
+
+ void sendResponse(common.Response response)
+}
+
+
diff --git a/not-alone-doc/pom.xml b/not-alone-doc/pom.xml
index 0c715837b43c59f9e8dc631d920a07d29f3e0e52..b15cbb6fb415c0c1483e5a740ccb17e36bd7050c 100644
--- a/not-alone-doc/pom.xml
+++ b/not-alone-doc/pom.xml
@@ -47,10 +47,8 @@
pdf
-
+ coderay
font
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc b/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc
index b0d8ddacd2755706c48b59d0daa4c3f576dacf57..476f3ec72e58f96948bc5ef6fc01e2a6d7af6396 100644
--- a/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc
+++ b/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc
@@ -1,36 +1,1262 @@
= Analyse du domaine
+== Présentation des entités
+=== Objets
-[plantuml, exemple-mind-map, png]
+==== Plateau
+Un plateau est composé de 31 cases, des cases Traqué, des cartes Créature et une case Victoire.
+Sur les cases Traqués, il peut y avoir le symbole Artemia.
+Le Plateau est également composé d'un pion Assimilation et d'un pion Secours.
+Chaque pion est respectivement placé sur une case Créature et une case Traqué.
+Deux types de Plateau sont possibles : recto et verso.
+la seule différence entre ces deux plateaux est la répartition des symboles Artemia.
+
+
+[plantuml, obj-plateau, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+ pionAssimilation : int
+ pionSecours : int
+ avancerAssimilation() : void
+ avancerSecours() : void
+ reculerAssimilation() : void
+ reculerSecours() : void
+ isCaseArtemia() : boolean
+}
+
+class PlateauRecto
+
+class PlateauVerso
+
+Plateau <|-- PlateauRecto
+Plateau <|-- PlateauVerso
+....
+
+
+==== Joueur, Traqué et Créature
+Un joueur représente une entité participant à une partie du jeu.
+Les joueurs sont répartis en deux catégories : les Traqués (1-6 joueurs), la Créature (1 joueur).
+
+Les Traqués ont des pions Volontés (entre 0 et 3), des cartes Survie (0 ou plus) et des cartes Lieu (entre 0 et 10).
+La Créature a des jetons Traque (3) et des cartes Traques (3).
+
+[plantuml, obj-joueur, png]
+....
+hide circle
+skinparam monochrome true
+
+class Joueur{
+ nom : String
+}
+
+class Traqué{
+ pionVolonté : int
+}
+
+class Créature
+
+Joueur <|-- Traqué
+Joueur <|-- Créature
+....
+
+==== Réserve
+La réserve représente une pioche pour Carte Lieu.
+Elle contient un certains nombre d'exemplaires des Cartes Lieu numérotées de 6 à 10.
+
+[plantuml, obj-reserve, png]
+....
+hide circle
+skinparam monochrome true
+
+class Réserve{
+ piocher(Entier) : Carte
+}
+
+Réserve o- CarteLieu
+....
+
+==== Pioche
+La pioche représente une pioche de cartes (Traque ou Survie).
+Elle permet des actions comme mélanger les cartes et piocher aléatoirement une carte.
+Elle sert également de défausse. Les cartes défaussées sont alors mises en fin de pioche.
+
+[plantuml, obj-pioche, png]
+....
+hide circle
+skinparam monochrome true
+class Pioche{
+ piocher() : Carte
+ mélanger() : void
+}
+
+Pioche <|-- PiocheSurvie
+Pioche <|-- PiocheTraque
+PiocheSurvie o-- CarteSurvie
+PiocheTraque o-- CarteTraque
+....
+
+==== Planète
+La planète possède des lieux.
+Ces lieux sont ceux représentés par les cartes Lieu.
+Chaque lieu peut accueillir tous les Traqués (0-6) et tous les jetons Traques (0-3).
+
+[plantuml, obj-planete]
+....
+hide circle
+skinparam monochrome true
+
+Planète -- CarteLieu
+Planète -- JetonTraque
+Planète -- Traqué
+....
+
+==== Défausse et Main
+La défausse représente la défausse personnelle de chaque Traqué pour ses cartes Lieu.
+Les cartes défaussées sont visibles par tous les joueurs.
+La défausse d'un Traqué peut contenir entre 0 à 10 cartes.
+Un Traqué peut reprendre plusieurs cartes Lieu et peut défausser plusieurs cartes Lieu.
+
+La main représente les cartes Lieu que le Traqué peut jouer.
+Les cartes présentes dans la main ne sont visibles que par le Traqué les possédant.
+La main d'un Traqué peut contenir entre 0 à 10 cartes.
+
+[plantuml, obj-defausse-main, png]
+....
+hide circle
+skinparam monochrome true
+
+Main o-- "lieux[0..10]" CarteLieu
+Défausse o-- "lieux[0..10]" CarteLieu
+Main "main[1]" - "défausse[1]" Défausse : \t\t\t\t
+....
+
+==== Carte, CarteLieu, CarteJoueur, CarteSurvie et CarteTraque
+L'entité Carte définit la représentation virtuelle d'une carte de jeu.
+Une carte a un *Pouvoir* qui peuvent être modifiés,
+appliqués, ou non appliqués.
+Il existe plusieurs types de cartes : CarteLieu, CarteSurvie,
+CarteTraque. Une carte peut être défaussée, piochée, jouée.
+
+
+L'entité CarteLieu hérite de Carte.
+Il existe 10 CarteLieu différentes, et chacune d'entre elle est numérotée.
+Une *CarteLieu* peut être détenue par un *Traqué*,
+être dans la défausse d'un joueur, être dans la *Réserve*,
+ou encore sur la *Planète*.
+Une CarteLieu ne peut être jouée que dans la phase 1.
+
+
+L'entité CarteJoueur représente une Carte pouvant être présente
+dans la "main" du *Joueur* et possédant une *Phase*.
+Chaque CarteJoueur ne peut être jouée que lors de leur *Phase*.
+Ces cartes peuvent être soit dans la "main" d'un *Joueur*,
+soit dans la *Pioche*.
+
+
+L'entité CarteSurvie caractérise une CarteJoueur
+qui ne peut être possédée que par un Traqué.
+Dans le jeu, elles peuvent donner un avantage situationnel aux *Traqués*.
+
+
+L'entité CarteTraque est une CarteJoueur
+qui ne peut être possédée que par la Créature.
+Elle peut posséder des Symboles (Cible ou Artemia).
+ Dans le jeu elles peuvent donner un avantage situationnel à la *Créature*.
+
+[plantuml, obj-carte, png]
+....
+hide circle
+skinparam monochrome true
+
+class Carte{
+ nom : String
+ activerPouvoir() : void
+}
+
+class CarteLieu{
+ numero : int
+}
+
+class CarteJoueur{
+ phase : Phase
+}
+
+Carte <|-- CarteLieu
+Carte <|-- CarteJoueur
+Carte o- Pouvoir
+CarteJoueur <|-- CarteSurvie
+CarteJoueur <|-- CarteTraque
+CarteTraque -- "symboles [0-2]" Symbole
+Symbole <|-- SymboleArtemia
+Symbole <|-- SymboleCible
+....
+
+==== JetonTraque, JetonCible, JetonArtemia et JetonCreature
+
+Le JetonTraque définit une pièce de jeu virtuelle, qui est posée
+par la Créature durant la Phase 3.
+Un jeton peut être posé sur une plusieurs CarteLieu de la Planète.
+Un jeton symbolise un *Pouvoir*.
+
+Le JetonCible qualifie un JetonTraque qui a le pouvoir
+d'une carteTraque.
+Cette dernière décide si le JetonCible est jouable ou non.
+
+Le JetonArtemia définit un JetonTraque qui a toujours
+au moins un *Pouvoir* constant : bloquer le *Pouvoir* de la *CarteLieu*
+sur laquelle il est posé.
+Le JetonArtemia n'est jouable que si la case du *Plateau* est Artemia
+ou si la CarteTraque contient le symbole Artemia.
+
+Le JetonCréature caractérise un JetonTraque jouable à tous
+les tours par la *Créature*.
+Il détient au moins un *Pouvoir* : annuler l'effet de la *CarteLieu*
+sur laquelle il est posé et retirer un pion de volonté à tout joueur
+se trouvant sur la même *CarteLieu*.
+
+[plantuml, obj-jeton-traque, png]
+....
+hide circle
+skinparam monochrome true
+
+JetonTraque <|-- JetonCréature
+JetonTraque <|-- JetonCible
+JetonTraque <|-- JetonArtemia
+....
+
+==== Système
+
+Représentation du système dans son ensemble.
+
+[plantuml, obj-ensemble, png]
+....
+hide circle
+skinparam monochrome true
+
+class Joueur{
+ nom : String
+}
+
+class Traqué{
+ pionVolonté : int
+}
+
+class Créature
+
+class Plateau{
+ pionAssimilation : int
+ pionSecours : int
+ avancerAssimilation() : void
+ avancerSecours() : void
+ reculerAssimilation() : void
+ reculerSecours() : void
+ isCaseArtemia() : boolean
+}
+
+class PlateauRecto
+
+class PlateauVerso
+
+class Carte{
+ nom : String
+ activerPouvoir() : void
+}
+
+class CarteLieu{
+ numero : int
+}
+
+class CarteJoueur{
+ phase : Phase
+}
+
+
+class Réserve{
+ piocher() : Carte
+ remettre(Carte) : void
+}
+
+class Pioche{
+ piocher() : Carte
+ mélanger() : void
+}
+
+Main o-- "lieux[1..10]" CarteLieu
+Défausse o-- "lieux[1..10]" CarteLieu
+Main "main[1]" - "défausse[1]" Défausse : \t\t\t\t
+Pioche <|-- PiocheSurvie
+Pioche <|-- PiocheTraque
+PiocheSurvie o-- CarteSurvie
+PiocheTraque o-- CarteTraque
+Réserve o- CarteLieu
+Partie -> "tours [1..*]" Tour : \t\t
+Tour -> "phases[4]" Phase : \t\t
+Partie o-- "joueurs[2..7]" Joueur
+Partie o-- Réserve
+Partie o-- Plateau
+Partie o-- Planète
+Carte <|-- CarteLieu
+Carte <|-- CarteJoueur
+Carte o- Pouvoir
+CarteJoueur <|-- CarteSurvie
+CarteJoueur <|-- CarteTraque
+Plateau <|-- PlateauRecto
+Plateau <|-- PlateauVerso
+Joueur <|-- Traqué
+Joueur <|-- Créature
+Traqué o-- Main
+Traqué o-- Défausse
+Traqué -- PiocheSurvie
+Créature -- PiocheTraque
+JetonTraque <|-- JetonCréature
+JetonTraque <|-- JetonCible
+JetonTraque <|-- JetonArtemia
+Créature -- JetonTraque
+....
+
+=== Actions
+
+==== Piocher
+
+===== Variante CarteSurvie
+
+Un Traqué prend une CarteSurvie dans la PiocheSurvie.
+
+.Avant de piocher
+[plantuml, action-piocher-survie-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+class "Détecteur : CarteSurvie" as Detecteur{}
+class "Drone : CarteSurvie" as Drone{}
+class "Cavale : CarteSurvie" as Cavale{}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Anna -- Detecteur
+Pioche -- Drone
+Pioche -- Cavale
+....
+
+.Après avoir piocher
+[plantuml, action-piocher-survie-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+class "Détecteur : CarteSurvie" as Detecteur{}
+class "Drone : CarteSurvie" as Drone{}
+class "Cavale : CarteSurvie" as Cavale{}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Anna -- Detecteur
+Anna -- Drone
+Pioche -- Cavale
+....
+
+===== Variante CarteTraque
+
+La Créture prend une CarteTraque dans la PiocheTraque.
+
+.Avant de piocher
+[plantuml, action-piocher-traque-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Anticipation : CarteTraque" as Anticipation{}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Pioche -- Angoisse
+Pioche -- Anticipation
+....
+
+.Après avoir piocher
+[plantuml, action-piocher-traque-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Anticipation : CarteTraque" as Anticipation{}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Bob -- Angoisse
+Pioche -- Anticipation
+....
+
+==== Mélanger
+
+La Pioche est mélangée : l'ordre des cartes est modifié aléatoirement.
+
+===== Variante PiocheSurvie
+
+.Avant avoir mélanger
+[plantuml, action-mélanger-survie-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Cavale : CarteSurvie" as Cavale{
+ ordre : 1
+}
+
+class "Détecteur : CarteSurvie" as Detecteur{
+ ordre : 2
+}
+class "Drone : CarteSurvie" as Drone{
+ ordre : 3
+}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Pioche -- Cavale
+Pioche -- Drone
+Pioche -- Detecteur
+....
+
+.Après avoir mélanger
+[plantuml, action-mélanger-survie-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Détecteur : CarteSurvie" as Detecteur{
+ ordre : 1
+}
+class "Drone : CarteSurvie" as Drone{
+ ordre : 2
+}
+class "Cavale : CarteSurvie" as Cavale{
+ ordre : 3
+}
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Pioche -- Cavale
+Pioche -- Detecteur
+Pioche -- Drone
+....
+
+===== Variante PiocheTraque
+
+.Avant avoir mélanger
+[plantuml, action-mélanger-traque-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Acharnement : CarteTraque" as Acharnement{
+ ordre : 1
+}
+
+class "Angoisse : CarteTraque" as Angoisse{
+ ordre : 2
+}
+class "Anticipation : CarteTraque" as Anticipation{
+ ordre : 3
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Pioche -- Acharnement
+Pioche -- Angoisse
+Pioche -- Anticipation
+....
+
+.Après avoir mélanger
+[plantuml, action-mélanger-traque-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Angoisse : CarteTraque" as Angoisse{
+ ordre : 1
+}
+class "Acharnement : CarteTraque" as Acharnement{
+ ordre : 2
+}
+class "Anticipation : CarteTraque" as Anticipation{
+ ordre : 3
+}
+class "Pioche : PiocheTraque" as Pioche{}
+
+Pioche -- Acharnement
+Pioche -- Angoisse
+Pioche -- Anticipation
+....
+
+==== Résister
+
+Un Traqué peut décider de résister.
+Il va perdre des pions Volontés mais récupérer des cartes Lieu.
+
+===== Variante 1
+
+.Avant résister
+[plantuml, action-resister-1-avant, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+ pionVolonté : 3
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+defausse -- plage
+defausse -- jungle
+defausse -- riviere
+defausse -- rover
+....
+
+.Après résister
+[plantuml, action-resister-1-apres, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+ pionVolonté : 2
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+main -- plage
+defausse -- jungle
+main -- riviere
+defausse -- rover
+....
+
+===== Variante 2
+
+.Avant résister
+[plantuml, action-resister-2-avant, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+ pionVolonté : 3
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+defausse -- plage
+defausse -- jungle
+defausse -- riviere
+defausse -- rover
+....
+
+.Après résister
+[plantuml, action-resister-2-apres, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+ pionVolonté : 1
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+main -- plage
+main -- jungle
+main -- riviere
+main -- rover
+....
+
+==== Jouer Carte Lieu
+
+Un Traqué doit durant le tour jouer une carte lieu.
+
+===== Variante 1
+Un traqué joue 1 carte face cachée
+
+.Avant de jouer une carte lieu
+
+[plantuml, action-jouer-1-carte-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+class "Cachée : Carte face cachée" as Caché{}
+
+Anna -- antre
+Anna -- plage
+Anna -- jungle
+Anna -- riviere
+Anna -- rover
+....
+
+.Après avoir joué une carte lieu
+
+[plantuml, action-jouer-1-carte-après, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+class "Cachée : Carte face cachée" as Caché{}
+
+Anna -- antre
+Anna -- plage
+Anna -- jungle
+Anna -- riviere
+Caché -- rover
+....
+
+===== Variante 2
+Un traqué joue 2 cartes faces cachées
+
+.Avant de jouer une carte lieu
+
+[plantuml, action-jouer-2-carte-avant, png]
....
-@startmindmap
-* Debian
-** Ubuntu
-*** Linux Mint
-*** Kubuntu
-*** Lubuntu
-*** KDE Neon
-** LMDE
-** SolydXK
-** SteamOS
-** Raspbian with a very long name
-*** Raspmbc => OSMC
-*** Raspyfi => Volumio
-@endmindmap
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+class "Cachées : Cartes faces cachées" as Caché{}
+
+Anna -- antre
+Anna -- plage
+Anna -- jungle
+Anna -- riviere
+Anna -- rover
....
+.Après avoir joué une carte lieu
-[plantuml, class-diagram-example, png]
+[plantuml, action-jouer-2-carte-apres, png]
....
hide circle
skinparam monochrome true
-class Joueur
+class "Anna : Traqué" as Anna{}
+
-class Partie
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
-Partie -> "creature [1]" Joueur : \t\t
+class "Cachées : Cartes faces cachées" as Caché{}
-Partie -> "traques [1-6]" Joueur : \t\t
+Anna -- antre
+Anna -- plage
+Anna -- jungle
+Caché -- riviere
+Caché -- rover
....
+
+==== Jouer Carte Traque
+La créature doit jouer une carte Traque durant le tour.
+
+===== Variante 1
+
+
+.Avant de jouer
+[plantuml, action-jouer-carte-traque-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Anticipation : CarteTraque" as Anticipation{}
+
+class "Mutation : CarteTraque" as Mutation{
+ordre : 1
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Bob -- Angoisse
+Bob -- Anticipation
+Pioche -- Mutation
+....
+
+.Après avoir joué
+[plantuml, action-jouer-carte-traque-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Mutation : CarteTraque" as Mutation{
+ordre : 1
+}
+class "Anticipation : CarteTraque" as Anticipation{
+ordre : 2
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Bob -- Angoisse
+Pioche -- Mutation
+Pioche -- Anticipation
+....
+
+
+===== Variante 2
+La créature pose deux cartes.
+
+.Avant de jouer
+[plantuml, action-jouer-carte-traque-avant2, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Anticipation : CarteTraque" as Anticipation{}
+
+class "Mutation : CarteTraque" as Mutation{
+ordre : 1
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Bob -- Angoisse
+Bob -- Anticipation
+Pioche -- Mutation
+....
+
+.Après avoir joué
+[plantuml, action-jouer-carte-traque-apres2, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{
+ordre : 3
+}
+class "Mutation : CarteTraque" as Mutation{
+ordre : 1
+}
+class "Anticipation : CarteTraque" as Anticipation{
+ordre : 2
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Pioche -- Angoisse
+Pioche -- Mutation
+Pioche -- Anticipation
+....
+
+==== Jouer carte Survie
+
+Un Traqué met une CarteSurvie dans la PiocheSurvie.
+
+.Avant de jouer une carte survie
+[plantuml, action-jouer-carte-survie-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+class "Détecteur : CarteSurvie" as Detecteur{}
+class "Drone : CarteSurvie" as Drone{
+ordre = 1
+}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Anna -- Detecteur
+Pioche -- Drone
+....
+
+.Après avoir piocher
+[plantuml, action-jouer-carte-survie-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+
+class "Drone : CarteSurvie" as Drone{
+ordre = 1
+}
+class "Détecteur : CarteSurvie" as Detecteur{
+ordre = 2
+}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Pioche -- Detecteur
+Pioche -- Drone
+....
+
+==== Lâcher-prise
+
+Un Traqué lâche prise quand il n'a plus de pionVolonté.
+Il va récupérer ses pions Volontés et ses cartes Lieu dans la défausse.
+Le pion assimilation va avancer de 1 en appelant AvancerPionAssimilation.
+
+.Avant Lâcher-prise
+[plantuml, action-Lâcher-prise-1-avant, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+ pionVolonté : 0
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+defausse -- plage
+defausse -- jungle
+defausse -- riviere
+defausse -- rover
+....
+
+.Après Lâcher-prise
+[plantuml, action-Lâcher-prise-1-apres, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+ pionVolonté : 3
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+main -- plage
+main -- jungle
+main -- riviere
+main -- rover
+....
+
+==== Défausser carte Survie
+
+Un Traqué peut défausser une CarteSurvie dans la PiocheSurvie.
+
+.Avant de défausser une carte survie
+[plantuml, action-defausser-carte-survie-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+class "Détecteur : CarteSurvie" as Detecteur{}
+class "Drone : CarteSurvie" as Drone{
+ordre = 1
+}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Anna -- Detecteur
+Pioche -- Drone
+....
+
+.Après avoir défausser une carte Survie
+[plantuml, action-defausser-carte-survie-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+
+
+class "Drone : CarteSurvie" as Drone{
+ordre = 1
+}
+class "Détecteur : CarteSurvie" as Detecteur{
+ordre = 2
+}
+
+class "Pioche : PiocheSurvie" as Pioche{}
+
+Pioche -- Detecteur
+Pioche -- Drone
+....
+
+==== Défausser Carte Lieu
+
+Un Traqué peut devoir défausser une carte lieu.
+
+
+
+.Avant de défausser une carte lieu
+
+[plantuml, action-defausse-1-carte-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+class "main" as main{}
+
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+class "Defausse " as Defausse{}
+Anna -- Defausse
+Anna -- main
+main -- antre
+main -- plage
+main -- jungle
+main -- riviere
+main -- rover
+....
+
+.Après avoir défaussé une carte lieu
+
+[plantuml, action-defausse-1-carte-après, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Anna : Traqué" as Anna{}
+class "main" as main{}
+
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+class "Defausse " as Defausse{}
+
+Anna -- Defausse
+Anna -- main
+Defausse -- antre
+main -- plage
+main -- jungle
+main -- riviere
+main -- rover
+....
+
+==== Défausser Carte Traque
+La créature peut devoir défausser une carte Traque durant le tour
+
+
+.Avant de défausser
+[plantuml, action-defausser-carte-traque-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Anticipation : CarteTraque" as Anticipation{}
+
+class "Mutation : CarteTraque" as Mutation{
+ordre : 1
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Bob -- Angoisse
+Bob -- Anticipation
+Pioche -- Mutation
+....
+
+.Après avoir défaussé
+[plantuml, action-defausser-carte-traque-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class "Bob : Créature" as Bob{}
+
+class "Acharnement : CarteTraque" as Acharnement{}
+class "Angoisse : CarteTraque" as Angoisse{}
+class "Mutation : CarteTraque" as Mutation{
+ordre : 1
+}
+class "Anticipation : CarteTraque" as Anticipation{
+ordre : 2
+}
+
+class "Pioche : PiocheTraque" as Pioche{}
+
+Bob -- Acharnement
+Bob -- Angoisse
+Pioche -- Mutation
+Pioche -- Anticipation
+....
+
+==== Avancer pion assimilation
+
+Après avoir gagné un point, la créature a son pion assimilation avancé de 1
+
+.Avant d'avancer
+[plantuml, action-avancer-pion-assimilation-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+ pionAssimilation : 2
+}
+
+....
+
+.Apres avoir avancé
+[plantuml, action-avancer-pion-assimilation-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+ pionAssimilation : 3
+}
+....
+
+==== Reculer pion assimilation
+
+Après avoir perdu un point, la créature a son pion assimilation reculé de 1
+
+.Avant de reculer
+[plantuml, action-reculer-pion-assimilation-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+pionAssimilation : 3
+
+}
+
+....
+
+.Apres avoir reculé
+[plantuml, action-reculer-pion-assimilation-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+pionAssimilation : 2
+}
+
+....
+
+==== Avancer pion secours
+
+Après avoir gagné un point, l'équipe des Traqués a son pion secours avancé de 1
+
+.Avant d'avancer
+[plantuml, action-avancer-pion-secours-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+ pionSecours : 2
+}
+
+....
+
+.Apres avoir avancé
+[plantuml, action-avancer-pion-secours-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+ pionSecours : 3
+}
+....
+
+==== Reculer pion assimilation
+
+Après avoir perdu un point, l'équipe des Traqués a son pion secours reculé de 1
+
+.Avant de reculer
+[plantuml, action-reculer-pion-secours-avant, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+pionSecours : 3
+
+}
+
+....
+
+.Apres avoir reculé
+[plantuml, action-reculer-pion-secours-apres, png]
+....
+hide circle
+skinparam monochrome true
+
+class Plateau{
+pionSecours : 2
+}
+
+....
+
+==== RécupérerDéfausseCartesLieu
+
+Un Traqué peut récupérer de la défausse une carte lieu .
+
+.Avant de récupérer
+[plantuml, action-recupérer-carte-lieu-avant, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+defausse -- plage
+defausse -- jungle
+defausse -- riviere
+defausse -- rover
+....
+
+.Après avoir récuperé
+[plantuml, action-recupérer-carte-lieu-apres, png]
+....
+hide circle
+
+skinparam monochrome true
+class "Anna : Traqué" as anna{
+}
+
+class "Antre : CarteLieu" as antre{}
+class "Plage : CarteLieu" as plage{}
+class "Jungle : CarteLieu" as jungle{}
+class "Rivière : CarteLieu" as riviere{}
+class "Rover : CarteLieu" as rover{}
+
+anna - main
+anna - defausse
+main -- antre
+main -- plage
+defausse -- jungle
+defausse -- riviere
+defausse -- rover
+....
+
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc b/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc
index bdf3d391d8fd4211a533fb7359162c6eebcfd3ed..bbdcad8396a004e522f29fbbf00b0a3a394bf3b1 100644
--- a/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc
+++ b/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc
@@ -1 +1,254 @@
= Conception préliminaire
+
+== Liste des fonctions de l'interface Client-Serveur
+
+=== Game Service
+- createRoom(player : TPlayer) : TRoomId
+- joinRoom(player : TPlayer, roomId : TRoomId) : Response
+- sendStartGame(player : TPlayer, creatureId : Integer, board : TBoard, color : TColor, placeCards : Tcards[*]) : Response
+- getGameDescription(player : TPlayer) : TDescription
+- sendFinishPhase(player : TPlayer, phase : TPhase) : void
+- sendPlayCards(player : TPlayer, playerCards : TCard[*]) : void
+- sendPlaceJetons(player : TPlayer, placedJetons : TPlacedJeton[*]) : void
+- sendResist(player : TPlayer, number : Integer) : void
+- sendGiveUp(player : TPlayer) : void
+
+=== Player Service
+
+- sendGameDescription(gameDescription : TDescription) : void
+- sendGameStart(): void
+- sendGameIsFinished(common.TPlayerTeam winner) : void
+- sendFirstRoundStart() : void
+- sendStartPhase(phase : TPhase, gameDescription : TDescription) : void
+- askAction(askedAction : TAskAction) : TAction
+- sendAction(askedAction : TAskAction) : void
+- sendResponse(response : Response) : void
+
+== Components diagram
+
+- Not alone (Joueur, Créature, Traqué, Main, Carte, Pioche, Réserve, Planète, Partie, Pouvoir)
+- Base de données (Sauvegarde de joueurs)
+- Authentificateur (SecurityWrapper)
+- Client
+
+== Components diagram
+
+[plantuml, components-diagram, png]
+....
+hide circle
+skinparam monochrome true
+
+component GameService as na
+
+component GameClient as c
+
+database DataBase as db
+
+component SecurityWrapper as sw
+
+interface Data as dbi
+
+interface GameService as nai
+
+interface Security as swi
+
+interface PlayerService as ci
+
+c - ci
+nai - na
+na .> "use" swi
+c .> "use" nai
+na ..> "use" ci
+
+dbi - db
+
+swi - sw
+sw .> "use" dbi
+
+....
+
+=== Interface
+
+[plantuml, interface-diagrams, png]
+....
+hide circle
+skinparam monochrome true
+
+class "«interface» \n Data" as dbi{
+ existUser(id : String):Boolean
+ findUser(id : String):User
+ findPlaceCard(id : String):PlaceCard
+ findPlaceCards(ids : String[*]):PlaceCard[*]
+ findSurvivalCard(id : String):SurvivalCard
+ findSurvivalCards(ids : String[*]):SurvivalCard[*]
+ findAllSurvivalCards():SurvivalCard[*]
+ findTrackingCard(id : String):TrackingCard
+ findTrackingCards(ids : String[*]):TrackingCard[*]
+ findAllTrackingCards():TrackingCard[*]
+}
+
+class "«interface» \n Security" as swi{
+ verifyUser(id : String, password : String):Boolean
+ generateToken(id : String , gameId : String):String
+ getUser(id : String):User
+}
+
+class "«interface» \n GameService" as si{
+ createRoom(player : TPlayer) : TRoomId
+ joinRoom(player : TPlayer, roomId : TRoomId) : Response
+ sendStartGame(player : TPlayer, creatureId : Integer, board : TBoard, color : TColor, placeCards : Tcards[*]) : Response
+ getGameDescription(player : TPlayer) : TDescription
+ sendFinishPhase(player : TPlayer, phase : TPhase) : void
+ sendPlayCards(player : TPlayer, playerCards : TCard[*]) : void
+ sendPlaceJetons(player : TPlayer, placedJetons : TPlacedJeton[*]) : void
+ sendResist(player : TPlayer, number : Integer) : void
+ sendGiveUp(player : TPlayer) : void
+}
+
+class "«interface» \n PlayerService" as csi{
+ sendGameDescription(gameDescription : TDescription) : void
+ sendGameStart(): void
+ sendGameIsFinished(common.TPlayerTeam winner) : void
+ sendFirstRoundStart() : void
+ sendStartPhase(phase : TPhase, gameDescription : TDescription) : void
+ askAction(askedAction : TAskAction) : TAction
+ sendAction(askedAction : TAskAction) : void
+ sendResponse(response : Response) : void
+}
+....
+
+
+== Diagrammes de séquence
+
+== Diagramme de séquence de mise en place
+
+- TPlayer tPlayer1 = {"Jean", "192.168.1.12:4200"}
+- TPlayer tPlayer2 = {"Sébastien", "192.168.1.13:4200"}
+
+Couleur partie : Bleu
+[plantuml]
+----
+hide circle
+skinparam monochrome true
+
+C1Client -> S1Serveur : createRoom(tPlayer1)
+C1Client <-- S1Serveur : 1001
+C2Client -> S1Serveur : joinGame(tPlayer2, 1001)
+C2Client <-- S1Serveur : {true, ""}
+C1Client -> S1Serveur : sendStartGame(tPlayer1, 1, "PLATEAU_RECTO_ID", "Bleu", [Nexus, Jungle, Rivière, Dôme, Plage, Mangrove , Abri, Epave, Fungi, Portail])
+C1Client <-- S1Serveur : {true, ""}
+S1Serveur ->> C1Client : sendFirstRoundStart()
+S1Serveur ->> C2Client : sendFirstRoundStart()
+C1Client -> S1Serveur : getGameDescription(tPlayer1)
+C1Client <-- S1Serveur : gameDescription
+C2Client -> S1Serveur : getGameDescription(tPlayer2)
+C2Client <-- S1Serveur : gameDescription
+----
+
+=== Diagramme de séquence du déroulement d'une manche
+
+- TPlayer tPlayerTraque = {"Jean", "192.168.1.12:4200"}
+- TPlayer tPlayerCreature = {"Sébastien", "192.168.1.13:4200"}
+
+[plantuml]
+----
+hide circle
+skinparam monochrome true
+
+C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_1", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_1", {GameDescription})
+C1Client --> S1Serveur : sendResist(tPlayerTraque, 1)
+C1Client <-- S1Serveur : {true, ""}
+C1Client --> S1Serveur : sendPlayCards(tPlayerTraque, ["Adrenaline"])
+C1Client <-- S1Serveur : {true, ""}
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_1")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_1")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PHASE_1", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PHASE_1", {GameDescription})
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_1")
+C2Client <-- S1Serveur : {true, ""}
+C1Client --> S1Serveur : sendPlayCards(tPlayerTraque, ["La_Plage"])
+C1Client <-- S1Serveur : {true, ""}
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_1")
+C1Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_1", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_1", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_1")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_1")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_2", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_2", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_2")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendPlayCards(tPlayerCreature, ["Soif_de_sang"])
+C2Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_2")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PHASE_2", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PHASE_2", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_2")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendPlaceJetons(tPlayerCreature, "{{"Creature", "Place_1"}, {"Cible", "Place_7"}}")
+C2Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_2")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_2", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_2", {GameDescription})
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_2")
+C2Client <-- S1Serveur : {true, ""}
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_2")
+C1Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_3", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_3", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_3")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_3")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PHASE_3", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PHASE_3", {GameDescription})
+C1Client <- S1Serveur : askAction({"CHOOSE_POWER" ,"Choose a power",[{"1", "Power 1"}, {"2", "Power 2"}]})
+C1Client --> S1Serveur : {"CHOOSE_POWER", ["1"]}
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_3")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_3")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_3", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_3", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_3")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_3")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_4", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_4", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_4")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_4")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("PHASE_4", {GameDescription})
+C2Client <<-- S1Serveur : sendStartPhase("PHASE_4", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_4")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_4")
+C2Client <-- S1Serveur : {true, ""}
+
+C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_4", "GameDescription")
+C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_4", {GameDescription})
+C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_4")
+C1Client <-- S1Serveur : {true, ""}
+C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_4")
+C2Client <-- S1Serveur : {true, ""}
+
+----
\ No newline at end of file
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc b/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc
index de9c910e42ee8871937c5ec8a470f959e6d84d90..e343e05b2f10130cf614b34ef08ed92060e38e34 100644
--- a/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc
+++ b/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc
@@ -1 +1,1568 @@
= Conception détaillée
+
+== Game
+
+[plantuml]
+....
+class Room{
+ - requests : BlockingQueue
+ - playersCounter : AtomicInteger
+ - roomId : String
+ - creator : User
+ - players : Map
+ - users : Map
+ - isStart : Boolean
+ - isClose : Boolean
+ - play : Thread
+ - game : Game
+ - static(MAX_PLAYER : Integer)
+ - static(MIN_PLAYER : Integer)
+ + getRoomId() : String
+ + getNumberPlayers() : AtomicInteger
+ + isCreator(user : User) : Boolean
+ + setGame(game : Game)
+ + join(user : User) : Response
+ + start(user : User, creatureNumber : Integer, board : Board, planet : Planet) : Response
+ + getGameDescription(user : User) : TDescription
+ - requestManagement()
+ - handleRequest(request : GameRequest)
+ + sendFinishPhase(user : User, phase : Phase)
+ + sendPlayCards(user : User, playerCards : PlayerCards[*])
+ + sendPlaceJetons(user : User, placedJetons : PlacedJeton[*])
+ + sendResist(user : User, number : Integer)
+ + sendGiveUp(user : User)
+ + askAction(inGameIdPlayer : Integer, askedAction : TAskAction ) : Action
+ + sendAction(inGameIdPlayer : Integer, askedAction : TAskAction )
+ + sendFirstRoundStart()
+ + sendStartPhase(idPlayer : Integer, tPhase : TPhase, description : TDescription )
+ + sendDescription(idPlayer : Integer, description : TDescription )
+ + sendGameIsFinished(winner : TPlayerTeam )
+ - inGameIdToUser(id : Integer ) : User
+ - inGameIdToUser(user : User ) : Integer
+ - playersToIdNamePairList(user : User ) : (Pair)[*]
+ - playerToIdNamePair(inGameId : Integer )
+ - userIsInRoom(user : User ) boolean
+
+
+}
+
+
+
+ interface GameInterface{
+ + isFinish() : Boolean
+ + playerHasFinished(playerId : Integer, phase : Phase)
+ + playerPlayCard(playerId : Integer, card : Card) : Response
+ + playerPlayCard(playerId : Integer, cards : Card[*]) : Response
+
+ + playerPlaceJeton(playerId : Integer, jeton : PlacedJeton) : Response
+ + playerPlaceJeton(playerId : Integer, jetons : PlacedJeton[*]) : Response
+
+ + playerResist(playerId : Integer, number : Integer) : Response
+ + playerGiveUp(playerId : Integer): Response
+ + playerChooseAction(playerId : Integer, action : Action): Response
+ + askAction(inGameIdPlayer : Integer, askedAction : TAskAction): Action
+ + sendAction(inGameIdPlayer : Integer, askedAction : TAskAction)
+ + sendFirstRoundStart()
+ + sendStartPhase()
+ + sendDescription()
+ + sendGameIsFinished()
+ }
+
+ class Game{
+ - nextRoundPowers : Power[*]
+ - planet : Planet
+ - reserve : Reserve
+ - survivalCardPioche : Pioche
+ - trackingCardPioche : Pioche
+ - board : Board
+ - database : NotAloneDatabase
+ - creature : Creature
+ - traques : Traque[*]
+ - playersMap : Map
+ - state : Phase
+ - room : Room
+ - gameRoundVariables : GameRoundVariables
+
+ - initializePlayer(playersId : Integer[*], creatureId : Integer)
+ - initializePlayer(players : (Pair)[*], creatureId : Integer)
+ - initializeReserve(playerNumber : Integer)
+ - initializeSurvivalCardPioche()
+ - initializeTrackingCardPioche()
+ - initializeCardsOfPlayers()
+
+ + getPlanet() : Planet
+ + getReserve() : Reserve
+ + getSurvivalCardPioche() : Pioche
+ + getTrackingCardPioche() : Pioche
+ + getBoard() : Board
+ + getCreature() : Creature
+ + getTraques() : Traque[*]
+ + getPlayersMap() : Map
+ + getPlayer(idPlayer : Integer) : Player
+ + getGameRoundVariables() : GameRoundVariables
+ + getState() : Phase
+ + getRoom() : Room
+ + isJetonArtemiaIsActive() : boolean
+ + getNumberWillingnessDecrementByJetonCreature() : Integer
+ + traqueCanResist() : boolean
+ + getIdPlayerTargetByTrackingCardAnticipation() : Integer
+ + traqueCanPickSurvivalCards() : boolean
+ + addPowerForNextRound(power : Power)
+ + disableJetonArtemia()
+ + enableJetonArtemia()
+ + setNumberWillingnessDecrementByJetonCreature( number : Integer)
+ + addNumberWillingnessByJetonCreature()
+ + setTraqueCanResist(traqueCanResist : boolean)
+ + setIdPlayerTargetByTrackingCardAnticipation(idPlayerTargetByJetonCreature : Integer)
+ + setTraqueCanPickSurvivalCards(traqueCanPickSurvivalCards : Boolean)
+
+ + isFinish() : Boolean
+
+ + playerHasFinished(playerId : Integer, phase : Phase) : Response
+ + creatureHasFinished(creature : Creature, phase : Phase) : Response
+ + boolean traqueHasFinished(traque : Traque, phase : Phase )
+ + playerFinishedPhase(player : Player, phase : Phase)
+ + playerPlayCard(playerId : Integer, card : Card) : Response
+ + playerPlayCard(playerId : Integer, cards : Card[*]) : Response
+
+ + playerPlaceJeton(playerId : Integer, jeton : PlacedJeton) : Response
+ + playerPlaceJeton(playerId : Integer, jetons : PlacedJeton[*]) : Response
+
+ + playerResist(playerId : Integer; number : Integer) : Response
+ + playerGiveUp(playerId : Integer) : Response
+ + askAction(inGameIdPlayer : Integer, action : TAskAction) : Action
+ + sendAction(inGameIdPlayer : Integer, askedAction : TAskAction)
+ + sendFirstRoundStart()
+ + sendStartPhase()
+ + sendDescription()
+ + sendGameIsFinished()
+ + playerPlayPlayerCard(player : Player, card : Card ) : Response
+ + playerPlayPlayerCard(player : Player, cards : Card[*] ) : Response
+ + creaturePlayTrackingCard(creature : Creature, trackingCard : TrackingCard ) : Response
+ + creaturePlayTrackingCard(creature : Creature, trackingCards : TrackingCard[*] ) : Response
+ - applyCreaturePlayTrackingCard(creature : Creature, trackingCard : TrackingCard )
+ + creatureCanPlayThisTrackingCards(creature : Creature, trackingCard : TrackingCard ) : boolean
+ + creatureCanPlayThisTrackingCards(creature : Creature, trackingCard : TrackingCard[*] ) : boolean
+ + traquePlaySurvivalCard(traque : Traque, survivalCard : SurvivalCard) : Response
+ + traquePlaySurvivalCard(traque : Traque, survivalCard : SurvivalCard[*]) : Response
+ - applyTraquePlaySurvivalCard( traque : Traque, survivalCard : SurvivalCard)
+ + traqueCanPlayThisSurvivalCards( traque : Traque, survivalCard : SurvivalCard) : boolean
+ + traqueCanPlayThisSurvivalCards( traque : Traque, survivalCards : SurvivalCard[*]) : boolean
+ + traquePlayPlaceCard( traque : Traque, placeCard PlaceCard) : Response
+ + traquePlayPlaceCard( traque : Traque, placeCard PlaceCard[*]) : Response
+ + playerCardsPlayedPhaseAndAppliedPhaseDifferent( playerCard : PlayerCard) : boolean
+ + creaturePlaceAJeton( creature : Creature, placedJeton : PlacedJeton) : Response
+ + nextPhase(phase : Phase) : Phase
+ + allPlayersHasFinishedCurrentPhase() : boolean
+ + startNextPhase()
+ + managePhase3()
+ - choosePlaceCardsToReveal(traque : Traque) : PlaceCard[*]
+ + managePhase4()
+ + nextRound()
+ - applyNextRoundPowers()
+ - applyModificatorPower(power : PowerModificator)
+ - useWillingnessOnBoard()
+ + choosePlaceCardsAction(idPlayer : Integer, max : Integer, placesCards : PlaceCard[*]) : PlaceCard[*]
+ + chooseSurvivalCardsAction(idPlayer : Integer, max : Integer, survivalCards : SurvivalCard[*]) : SurvivalCard[*]
+ + chooseTrackingCardsAction(idPlayer : Integer, max : Integer, trackingCards : TrackingCard[*]) : TrackingCard[*]
+ + chooseCardsAction(idPlayer : Integer, max : Integer, cardsToChoose : Card[*]) : Card[*]
+ - createTActionForChooseCardsAction( max : Integer, cardsToChoose : Card[*]) : TAskAction
+ + sendPlaceCardsAction( idPlayer : Integer, cardsToShow : PlaceCard[*])
+ + sendCardsAction( idPlayer : Integer, cardsToShow : Card[*])
+ - createTActionForSendCardsAction(cardsToShow : Card[*]) : TAskAction
+ - computeCardListFromCardNames( cardNames : CardName[*], cardsToChoose : Card[*]) : Card[*]
+ + choosePower(idPlayer : Integer, powersDescription : String[*]) : Integer
+ + targetPlayer(idPlayer : Integer) : Integer
+ + choosePlace(idPlayer : Integer, number : Integer) : Place[*]
+ + choosePlace(idPlayer : Integer, number : Integer, message : String) : Place[*]
+ + movePlayer(idPlayer : Integer) : Pair
+ + swapJetons(idPlayer : Integer) : Pair
+ + associateCardNamesToPlaces(idPlayer : Integer, cardsToAssociate : Card[*]) : Map
+ - createTActionForAssociateCardNamesToPlaces( cardsToAssociate : Card[*]) : TAskAction
+ - computeMapCardToPlaceFromMapCardNamesToPlace( cardNamePlaceMap : Map, cards : Card[*]) : Map
+ - isJetonCibleOnThisPlace(place : Place[*]) : boolean
+ + createDescription(playerId : Integer) : TDescription
+
+
+ }
+
+
+class RoomFactory{
+ - {static} idCounter : AtomicInteger
+ - {static} createRoom(playerId : String) : Room
+}
+class RoomServiceController{
+ - rooms : Map
+ - players : Map
+ - getRooms() : Map
+ - getPlayers() : Map
+ + addRoom(room : Room) : boolean
+ + createRoom(playerId : String) : String
+ + joinRoom(playerId : String, roomId : String) : Response
+ + startGame(playerId : String, creatureId : Integer, board : Board, planet : Planet) : Response
+ + getGameDescription(user : User) : TDescription
+ + sendFinishPhase(user : User, phase : Phase)
+ + sendPlayCards(user : User, cards : Card[*])
+ + sendPlaceJetons(user : User, placedJetons : PlacedJeton[*])
+ + sendResist(user : User, number : Integer)
+ + sendGiveUp(user : User)
+}
+class PowerApplicator{
+ - database : NotAloneDatabase
+ + applyPlayerCard(game : Game, idPlayer : Integer, playerCard : PlayerCard)
+ + resolvePlace(game : Game, idPlayer : Integer, playerCard : PlayerCard)
+ - filterSpecialCaseBlockPlace(game : Game, idPlayer : Integer, playerCard : PlayerCard) : Boolean
+ - filterJetonBlockPlace(game : Game, idPlayer : Integer, playerCard : PlayerCard) : Boolean
+ + applyPlaceCardPower(game : Game, cardName : CardName, idPlayer : Integer)
+ + applyTrackingCardPower(game : Game, cardName : CardName, idPlayer : Integer)
+ + applySurvivalCardPower(game : Game, cardName : CardName, idPlayer : Integer)
+ + applyJetonArtemia(game : Game, idPlayer : Integer)
+ + applyJetonCreature(game : Game, idPlayer : Integer, placeCard : PlaceCard)
+ + applyJetonCible(game : Game, idPlayer : Integer)
+ - applyPlaceAntre(game : Game, idPlayer : Integer)
+ - applyPlaceJungle(game : Game, idPlayer : Integer)
+ - applyPlaceRiviere(game : Game, idPlayer : Integer)
+ - applyPlacePlage(game : Game, idPlayer : Integer)
+ - applyPlaceRover(game : Game, idPlayer : Integer)
+ - applyPlaceMarais(game : Game, idPlayer : Integer)
+ - applyPlaceAbri(game : Game, idPlayer : Integer)
+ - applyPlaceEpave(game : Game, idPlayer : Integer)
+ - applyPlaceSource(game : Game, idPlayer : Integer)
+ - applyPlaceArtefact(game : Game, idPlayer : Integer)
+ - applyPlaceBlueArtefact(game : Game, idPlayer : Integer, powersDescription : String[*])
+ - applyPlaceGreenArtefact(game : Game, idPlayer : Integer, powersDescription : String[*])
+ - applyPlaceRedArtefact(game : Game, idPlayer : Integer, powersDescription : String[*])
+ - applyPlaceYellowArtefact(game : Game, idPlayer : Integer, powersDescription : String[*])
+ - applyPlaceNexus(game : Game, idPlayer : Integer)
+ - applyPlaceOasis(game : Game, idPlayer : Integer)
+ - applyPlaceFjord(game : Game, idPlayer : Integer)
+ - applyPlaceDome(game : Game, idPlayer : Integer)
+ - applyPlaceLabyrinthe(game : Game, idPlayer : Integer)
+ - applyPlaceLabyrintheNotAllRevealed(game : Game, idPlayer : Integer)
+ - applyPlaceLabyrintheAllRevealed(game : Game, idPlayer : Integer)
+ - applyPlaceMangrove(game : Game, idPlayer : Integer)
+ - applyPlaceArchipel(game : Game, idPlayer : Integer)
+ - applyPlacePole(game : Game, idPlayer : Integer)
+ - applyPlaceFungi(game : Game, idPlayer : Integer)
+ - applyPlacePortail(game : Game, idPlayer : Integer)
+ - applyTrackingAcharnement(game : Game)
+ - applyTrackingAngoisse(game : Game)
+ - applyTrackingAnticipation(game : Game, idPlayer : Integer)
+ - applyTrackingCataclysme(game : Game, idPlayer : Integer)
+ - applyTrackingChampDeForce(game : Game)
+ - applyTrackingClone(game : Game)
+ - applyTrackingDeploiement(game : Game, idPlayer : Integer)
+ - applyTrackingDesespoir(game : Game)
+ - applyTrackingDetour(game : Game, idPlayer : Integer)
+ - applyTrackingDomination(game : Game, idPlayer : Integer)
+ - applyTrackingEffroi(game : Game, idPlayer : Integer)
+ - applyTrackingEmprise(game : Game, idPlayer : Integer)
+ - applyTrackingEpidemie(game : Game, idPlayer : Integer)
+ - applyTrackingFailleTemporelle(game : Game)
+ - applyTrackingFlashback(game : Game)
+ - applyTrackingGargantua(game : Game)
+ - applyTrackingHarcelement(game : Game)
+ - applyTrackingHurlement(game : Game)
+ - applyTrackingInertie(game : Game)
+ - applyTrackingInterference(game : Game)
+ - applyTrackingIntuition(game : Game, idPlayer : Integer)
+ - applyTrackingMagnetisme(game : Game)
+ - applyTrackingMirage(game : Game)
+ - applyTrackingMutation(game : Game)
+ - applyTrackingPsychose(game : Game, idPlayer : Integer)
+ - applyTrackingReminiscence(game : Game, idPlayer : Integer)
+ - applyTrackingReperage(game : Game, idPlayer : Integer)
+ - applyTrackingSablesMouvants(game : Game)
+ - applyTrackingSoifDeSang(game : Game)
+ - applyTrackingStase(game : Game)
+ - applyTrackingTelepathie(game : Game, idPlayer : Integer)
+ - applyTrackingTornade(game : Game, idPlayer : Integer)
+ - applyTrackingToxine(game : Game)
+ - applyTrackingUbiquite(game : Game, idPlayer : Integer)
+ - applyTrackingVirus(game : Game)
+ - applyTrackingZoneInterdite(game : Game)
+ - applySurvivalAdrenaline(game : Game, idPlayer : Integer)
+ - applySurvivalAlerte(game : Game, idPlayer : Integer)
+ - applySurvivalAmplificateur(game : Game)
+ - applySurvivalBrouillage(game : Game)
+ - applySurvivalCavale(game : Game, idPlayer : Integer)
+ - applySurvivalDetecteur(game : Game, idPlayer : Integer)
+ - applySurvivalDrone(game : Game, idPlayer : Integer)
+ - applySurvivalEntrave(game : Game)
+ - applySurvivalEquipement(game : Game, idPlayer : Integer)
+ - applySurvivalEsquive(game : Game, idPlayer : Integer)
+ - applySurvivalFaussePiste(game : Game, idPlayer : Integer)
+ - applySurvivalHologramme(game : Game, idPlayer : Integer)
+ - applySurvivalLeurre(game : Game, idPlayer : Integer)
+ - applySurvivalMimetisme(game : Game, idPlayer : Integer)
+ - applySurvivalNavette(game : Game)
+ - applySurvivalPlanques(game : Game, idPlayer : Integer)
+ - applySurvivalPortail(game : Game, idPlayer : Integer)
+ - applySurvivalRalliement(game : Game)
+ - applySurvivalRefuge(game : Game, idPlayer : Integer)
+ - applySurvivalRegeneration(game : Game, idPlayer : Integer)
+ - applySurvivalResistance(game : Game, idPlayer : Integer)
+ - applySurvivalRetraite(game : Game, idPlayer : Integer)
+ - applySurvivalRiposte(game : Game)
+ - applySurvivalSacrifice(game : Game, idPlayer : Integer)
+ - applySurvivalSecondSouffle(game : Game, idPlayer : Integer)
+ - applySurvivalSixiemeSens(game : Game, idPlayer : Integer)
+ - applySurvivalSystemeD(game : Game)
+ - applySurvivalTenacite(game : Game, idPlayer : Integer)
+ - applySurvivalVaccin(game : Game)
+ - applySurvivalVolteFace(game : Game, idPlayer : Integer)
+ - applySurvivalVortex(game : Game, idPlayer : Integer)
+ + playNewPlaceCard(game : Game, idPlayer : Integer)
+ + swapHandAndDefaussePlaceCard(game : Game, idPlayer : Integer)
+ + revealAHiddenPlaceAndApplyItsPower(game : Game, idPlayer : Integer)
+ + addWillingnessToAPlayer(game : Game, idPlayer : Integer, numberWillingness : Integer)
+ + chooseCardFromReserve(game : Game, idPlayer : Integer)
+ + takeBackAllCardsFromDefausse(game : Game, idPlayer : Integer)
+ + takeBackCardsFromDefausse(game : Game, idPlayer : Integer, numberCards : Integer)
+ + takeBackCard(game : Game, idPlayer : Integer, cardName : CardName)
+ + copyPowerWhereJetonCreatureIs(game : Game, idPlayer : Integer)
+ + copyPowerOfOneCardInDefausse(game : Game, idPlayer : Integer)
+ + copyPowerOfOneCardInInterval(game : Game, idPlayer : Integer, a : Integer, b : Integer)
+ + pickSurvivalCards(game : Game, idPlayer : Integer, numberCardsToPick : Integer, numberCardToKeep : Integer)
+ + throwAwayPlaceCards(game : Game, idPlayer : Integer, numberCardsToThrowAway : Integer)
+ + throwAwaySurvivalCards(game : Game, idPlayer : Integer, numberCardsToThrowAway : Integer)
+ + moveTraqueOnAdjacentPlace(game : Game, idPlayer : Integer)
+ + moveTraqueOnAdjacentPlaceAndAddHimToRetraiteList(game : Game, idPlayer : Integer)
+ + moveJetonOnAdjacentPlace(game : Game, idPlayer : Integer, symbol : JetonSymbol)
+ + chooseTwoAdjacentPlace(game : Game, idPlayer : Integer) : Pair
+ + applyPlanetPawn(game : Game)
+ + applyBeaconPawn(game : Game)
+ + applyShieldPawn(game : Game)
+ + checkPlayerIsNotCreature(game : Game, idPlayer : Integer)
+ + checkPlayerIsNotCreature(game : Game)
+ + checkEpidemieCondition(game : Game, placeCard : PlaceCard) : boolean
+ + checkInertieCondition(game : Game) : boolean
+ + checkAlerteCondition(variables : GameRoundVariables, place : Place) : boolean
+ + isABlockedPlaceCard(game : Game, placeCard : PlaceCard) : boolean
+ + checkIfAdjacentToJetonCible(game : Game, placeCard : PlaceCard) : boolean
+ + findPlaceCardWhereTheJetonCibleIsAndAdjacent(game : Game, placeCard : PlaceCard) : PlaceCard
+ + subWillingness(game : Game, traque : Traque, numberWillingnessDecrement : Integer)
+ + subWillingness(game : Game, idTraque : Integer, numberWillingnessDecrement : Integer)
+
+}
+class GameRoundVariables{
+ - numberPawnWillingnessOnBoard : Integer
+ - actionJetonCible : BiConsumer
+ - actionAdjacentPlaceJetonCible : BiConsumer
+ - incrementScoreTraque : Integer
+ - numberWillingnessDecrementByJetonCreature : Integer
+ - numberMaxPlaceCardsGetByPlacePower : Integer
+ - idPlayerTargetByTrackingCardAnticipation : Integer
+ - idPlayerTargetByTrackingCardDomination : Integer
+ - idPlayerTargetByTrackingCardEpidemie : Integer
+ - targetByAlerte : Place
+
+ - playerWhoHaveLostAllWillingness : Integer[*]
+ - playersWhoHaveResist : Integer[*]
+ - playersCaughtByCreature : Integer[*]
+ - playersCaughtByCreatureOnNexus : Integer[*]
+ - playersWhoDodgeJetonArtemia : Integer[*]
+ - playersWhoDodgeJetonCreature : Integer[*]
+ - playersWhoDodgeJetonCible : Integer[*]
+ - playersWhoHavePlayCavale : Integer[*]
+ - playersWhoHavePlayDrone : Integer[*]
+ - playersWhoHavePlayMimetisme : Integer[*]
+ - playersWhoHavePlayPortail : Integer[*]
+ - playersWhoHavePlayRegeneration : Integer[*]
+ - playersWhoIsTargetRetraite : Integer[*]
+ - playersWhoHavePlayVolteFace : Integer[*]
+ - playersWhoUseFjordInPreviousRound : Integer[*]
+
+ - traqueCanResist : boolean
+ - traqueCanPickSurvivalCards : boolean
+ - jetonArtemiaIsActive : boolean
+ - jetonArtemiaMadeLoseOneWillingness : boolean
+ - rescuePawnCanMoveForward : boolean
+ - jetonCibleCanBeOnTwoAdjacentPlaces : boolean
+ - jetonCreatureCanBeOnTwoAdjacentPlaces : boolean
+ - jetonArtemiaCanBeOnTwoAdjacentPlaces : boolean
+ - defaussePlaceCardsAreHidden : boolean
+ - canPlaceJetonCreatureOnPlaces6To10 : boolean
+ - survivalCardRalliementIsActive : boolean
+ - survivalCardRefugeIsActive : boolean
+ - canPlayTrackingCard : boolean
+ - inertieTrackingCardIsPlayed : boolean
+ - jetonCibleBlockPlace : boolean
+ - jetonCibleBlockAdjacentPlace : boolean
+ - jetonCibleAdjacentPlaceMoveTraque : boolean
+ - ralliementIsActive : boolean
+ - refugeIsActive : boolean
+
+ + reset()
+ + resetAfterNextRoundPowersApplication()
+ + addPawnWillingnessOnBoard(number : Integer)
+ + isPawnWillingnessOnBoard() : boolean
+ + usePawnWillingnessOnBoard()
+ + getActionJetonCible() : BiConsumer
+ + setActionJetonCible(actionJetonCible : BiConsumer)
+ + getActionAdjacentPlaceJetonCible() : BiConsumer
+ + setActionAdjacentPlaceJetonCible(actionAdjacentPlaceJetonCible : BiConsumer)
+ + getIncrementScoreTraque() : Integer
+ + setIncrementScoreTraque( incrementScoreTraque : Integer)
+ + getNumberWillingnessDecrementByJetonCreature() : Integer
+ + setNumberWillingnessDecrementByJetonCreature( numberWillingnessDecrementByJetonCreature : Integer)
+ + numberMaxPlaceCardsGetByPlacePowerIsLimited() : boolean
+ + addNumberWillingnessByJetonCreature()
+ + getNumberMaxPlaceCardsGetByPlacePower() : Integer
+ + setNumberWillingnessDecrementByJetonCreature( numberMaxPlaceCardsGetByPlacePower : Integer)
+ + getIdPlayerTargetByTrackingCardAnticipation() : Integer
+ + setIdPlayerTargetByTrackingCardAnticipation( idPlayerTargetByJetonCreature : Integer)
+ + playerIsTargetByTrackingCardDomination() : boolean
+ + playerIsTargetByTrackingCardEpidemie() : boolean
+ + getIdPlayerTargetByTrackingCardDomination() : Integer
+ + setIdPlayerTargetByTrackingCardDomination( idPlayerTargetByTrackingCardDomination : Integer)
+ + getIdPlayerTargetByTrackingCardEpidemie() : Integer
+ + setIdPlayerTargetByTrackingCardEpidemie( idPlayerTargetByTrackingCardEpidemie : Integer)
+ + alerteIsActive() : boolean
+ + getTargetByAlerte() : Place
+ + setTargetByAlerte(targetByAlerte : Place)
+ + getPlayerWhoHaveLostAllWillingness() : Integer[*]
+ + addPlayerWhoHaveLostAllWillingness(idPlayer : Integer)
+ + getPlayersWhoHaveResist() : Integer[*]
+ + addPlayersWhoHaveResist(idPlayer : Integer)
+ + getPlayersWhoHasCaughtByCreature() : Integer[*]
+ + addPlayersWhoHasCaughtByCreature(idPlayer : Integer)
+ + getPlayersWhoHasCaughtByCreatureOnNexus() : Integer[*]
+
+ + addPlayersWhoHasCaughtByCreatureOnNexus(idPlayer : Integer)
+ + getPlayersWhoHavePlayCavale() : Integer[*]
+ + addPlayerWhoHavePlayCavale(idPlayer : Integer)
+ + getPlayersWhoDodgeJetonArtemia() : Integer[*]
+ + addPlayersWhoDodgeJetonArtemia(idPlayer : Integer)
+ + getPlayersWhoHavePlayDrone() : Integer[*]
+ + addPlayersWhoHavePlayDrone(idPlayer : Integer)
+ + getPlayersWhoDodgeJetonCreature() : Integer[*]
+ + addPlayersWhoDodgeJetonCreature(idPlayer : Integer)
+ + getPlayersWhoHavePlayMimetisme() : Integer[*]
+ + addPlayersWhoHavePlayMimetisme(idPlayer : Integer)
+ + getPlayersWhoHavePlayPortail() : Integer[*]
+ + addPlayersWhoHavePlayPortail(idPlayer : Integer)
+ + getPlayersWhoHavePlayRegeneration() : Integer[*]
+ + addPlayersWhoHavePlayRegeneration(idPlayer : Integer)
+ + getPlayersWhoDodgeJetonCible() : Integer[*]
+ + addPlayersWhoDodgeJetonCible(idPlayer : Integer)
+ + getPlayersWhoIsTargetRetraite() : Integer[*]
+ + addPlayersWhoIsTargetByRetraite(idPlayer : Integer)
+ + getPlayersWhoHavePlayVolteFace() : Integer[*]
+ + addPlayersWhoHavePlayVolteFace(idPlayer : Integer)
+ + getplayersWhoUseFjordInPreviousRound() : Integer[*]
+ + addplayersWhoUseFjordInPreviousRound(idPlayer : Integer)
+ + ralliementIsActive() : boolean
+ + setRalliementIsActive(ralliementIsActive : boolean)
+ + refugeIsActive() : boolean
+ + setRefugeIsActive(refugeIsActive : boolean)
+ + isJetonArtemiaIsActive() : boolean
+ + disableJetonArtemia()
+ + enableJetonArtemia()
+ + traqueCanResist() : boolean
+ + setTraqueCanResist(traqueCanResist : boolean)
+ + traqueCanPickSurvivalCards() : boolean
+ + setTraqueCanPickSurvivalCards(traqueCanPickSurvivalCards : boolean)
+ + setJetonArtemiaIsActive(jetonArtemiaIsActive : boolean)
+ + jetonArtemiaMadeLoseOneWillingness() : boolean
+ + setJetonArtemiaMadeLoseOneWillingness(jetonArtemiaMadeLoseOneWillingness : boolean)
+ + rescuePawnCanMoveForward() : boolean
+ + setRescuePawnCanMoveForward(rescuePawnCanMoveForward : boolean)
+ + jetonCibleCanBeOnTwoAdjacentPlaces() : boolean
+ + setJetonCibleCanBeOnTwoAdjacentPlaces(jetonCibleCanBeOnTwoAdjacentPlaces : boolean)
+ + jetonCreatureCanBeOnTwoAdjacentPlaces() : boolean
+ + setJetonCreatureCanBeOnTwoAdjacentPlaces(jetonCreatureCanBeOnTwoAdjacentPlaces : boolean)
+ + jetonArtemiaCanBeOnTwoAdjacentPlaces() : boolean
+ + jetonArtemiaCanBeOnTwoAdjacentPlaces(jetonArtemiaCanBeOnTwoAdjacentPlaces : boolean)
+ + defaussePlaceCardsAreHidden() : boolean
+ + setDefaussePlaceCardsAreHidden(defaussePlaceCardsAreHidden : boolean)
+ + canPlaceJetonCreatureOnPlaces6To10() : boolean
+ + setCanPlaceJetonCreatureOnPlaces6To10(canPlaceJetonCreatureOnPlaces6To10 : boolean)
+ + survivalCardRalliementIsActive() : boolean
+ + setSurvivalCardRalliementIsActive(survivalCardRalliementIsActive : boolean)
+ + survivalCardRefugeIsActive() : boolean
+ + setSurvivalCardRefugeIsActive(survivalCardRefugeIsActive : boolean)
+ + canPlayTrackingCard() : boolean
+ + setCanPlayTrackingCard(canPlayTrackingCard : boolean)
+ + inertieTrackingCardIsPlayed() : boolean
+ + setInertieTrackingCardIsPlayed(inertieTrackingCardIsPlayed : boolean)
+ + isJetonCibleBlockPlace() : boolean
+ + setJetonCibleBlockPlace(jetonCibleBlockPlace : boolean)
+ + isJetonCibleBlockAdjacentPlace() : boolean
+ + setJetonCibleBlockAdjacentPlace(jetonCibleBlockAdjacentPlace : boolean)
+ + isJetonCibleAdjacentPlaceMoveTraque() : boolean
+ + setJetonCibleAdjacentPlaceMoveTraque(jetonCibleAdjacentPlaceMoveTraque : boolean)
+
+
+ }
+Game "1" -- "1" Room
+Room *-- RoomServiceController
+Game *-- GameRoundVariables
+
+....
+
+
+
+=== Item
+
+==== Action
+
+.Package action
+[plantuml]
+....
+package action{
+ abstract class Action{
+ # {abstract} getActionType() : ActionType
+ }
+
+ class ActionAssociateCardNamesToPlaces{
+ - cardNamePlaceMap : Map
+ + getActionType() : ActionType
+ + getCardNamePlaceMap() : Map
+ + equals(obj : Object) : boolean
+ }
+
+ class ActionChooseCard{
+ - cards : Card[*]
+ + getCards : Card[*]
+ + getActionType() : ActionType
+ + equals(obj : Object) : boolean
+
+ }
+
+ class ActionChoosePlace{
+ - places : Place[*]
+ + getPlaces() : Place[*]
+ + getActionType() : ActionType
+ + equals(obj : Object) : boolean
+
+ }
+
+ class ActionChoosePower{
+ - idPowerChosen : Integer
+ + getIdPowerChosen() : Integer
+ + getActionType() : ActionType
+ + equals(obj : Object) : boolean
+
+ }
+
+ class ActionMovePlayer{
+ - idPlayer : Integer
+ - place : Place
+ + getIdPlayer() : Integer
+ + getPlace() : Place
+ + getActionType() : ActionType
+ + equals(obj : Object) : boolean
+
+ }
+
+ class ActionSwapJeton{
+ - jeton1 : JetonSymbol
+ - jeton2 : JetonSymbol
+ + getJeton1() : JetonSymbol
+ + getJeton2() : JetonSymbol
+ + getActionType() : ActionType
+ + equals(obj : Object) : boolean
+
+ }
+
+ class ActionTargetPlayer{
+ - idPlayer : Integer
+ + getIdPlayer() : Integer
+ + getActionType() : ActionType
+ + equals(obj : Object) : boolean
+
+ }
+
+ enum ActionType{
+ CHOOSE_POWER
+ TARGET_PLAYER
+ MOVE_PLAYER
+ CHOOSE_CARD
+ CHOOSE_PLACE
+ SWAP_JETONS
+ MOVE_JETON
+ ASSOCIATE_SURVIVAL_CARDS_TO_PLACES
+ SHOW_CARD
+ }
+ enum TPairType{
+ NUMBER
+ CARD
+ PLACE
+ JETON
+ PLAYER
+ }
+
+ Action <|-- ActionChooseCard
+ Action <|-- ActionChoosePlace
+ Action <|-- ActionChoosePower
+ Action <|-- ActionMovePlayer
+ Action <|-- ActionSwapJeton
+ Action <|-- ActionTargetPlayer
+ Action <|-- ActionAssociateCardNamesToPlaces
+}
+....
+
+
+==== Board
+.Package board
+[plantuml]
+....
+package board{
+
+ class Board{
+ - boardDistribution : BoardDistribution
+ - boardColor : BoardColor
+ - score : Score
+ + getScore() : Score
+ + getBoardDistribution() : BoardDistribution
+ + getBoardColor() : BoardColor
+ + isArtemiaSquare() : Boolean
+ + toString() : String
+ + initializeScore(playerNumber : Integer)
+ + isFinish() : boolean
+ + getScoreTraque() : Integer
+ + getScoreCreature() : Integer
+ + actualBestTeam() : PlayerTeam
+ + winner() : PlayerTeam
+ + moveForwardTraque(delta : Integer)
+ + moveForwardTraque()
+ + moveBackTraque(delta : Integer)
+ + moveBackTraque()
+ + moveForwardCreature(delta : Integer)
+ + moveForwardCreature()
+ + moveBackCreature(delta : Integer)
+ + moveBackCreature()
+
+ }
+ enum BoardColor{
+ BLUE
+ RED
+ GREEN
+ YELLOW
+ }
+ enum BoardDistribution{
+ FRONT
+ BACK
+ }
+
+ class Score{
+ - scoreTraque : Integer
+ - scoreCreature : Integer
+ - winner : PlayerTeam
+ - static(BASE_TRAQUE : Integer)
+ - static(BASE_CREATURE : Integer)
+ + getScoreTraque() : Integer
+ + getScoreCreature() : Integer
+ + isFinish() : Boolean
+ + actualBestTeam() : PlayerTeam
+ + winner() : PlayerTeam
+ + scoreCreatureGreaterThanBase() : Boolean
+ + scoreTraqueGreaterThanBase() : Boolean
+ + moveForwardTraque(delta : Integer)
+ + moveBackTraque(delta : Integer)
+ + moveForwardCreature(delta : Integer)
+ + moveBackCreature(delta : Integer)
+ + equals(obj : Object) : Boolean
+ + toString() : String
+ }
+
+
+ Board "1" o-- "1 score" Score
+}
+....
+
+==== Card
+.Package card
+[plantuml]
+....
+package card{
+ enum CardType{
+ SURVIVAL
+ TRACKING
+ PLACE
+ }
+
+ abstract class Card{
+
+ # name : String
+ # CardName : String
+ # description : String
+ + getName() : String
+ + getCardName() : String
+ + getDescription() : String
+ + getType() : String
+ + equals(obj : Object) : Boolean
+ + toString() : String
+ + hashCode() : Integer
+ }
+ enum CardName{
+ ANTRE, JUNGLE, RIVIERE, PLAGE, ROVER, MARAIS, ABRI, EPAVE, SOURCE, ARTEFACT,
+ NEXUS, OASIS, FJORD, DOME, LABYRINTHE, MANGROVE, ARCHIPEL, POLE, FUNGI, PORTAIL,
+
+ ACHARNEMENT, ANGOISSE, ANTICIPATION, CATACLYSME, CHAMP_DE_FORCE, CLONE, DEPLOIEMENT, DESESPOIR, DETOUR, DOMINATION, EFFROI,
+ EMPRISE, EPIDEMIE, FAILLE_TEMPORELLE, FLASHBACK, GARGANTUA, HARCELEMENT, HURLEMENTS, INERTIE, INTERFERENCES, INTUITION,
+ MAGNETISME, MIRAGE, MUTATION, PSYCHOSE, REMINISCENCE, REPERAGE, SABLES_MOUVANTS, SOIF_DE_SANG, STASE, TELEPATHIE,
+ TORNADE, TOXINE, UBIQUITE, VIRUS, ZONE_INTERDITE,
+
+ ADRENALINE, ALERTE, AMPLIFICATEUR, BROUILLAGE, CAVALE, DETECTEUR, DRONE, ENTRAVE, EQUIPEMENT, ESQUIVE,
+ FAUSSE_PISTE, HOLOGRAMME, LEURRE, MIMETISME, NAVETTE, PLANQUES, PORTAIL_SURVIVAL, RALLIEMENT, REFUGE, REGENERATION,
+ RESISTANCE, RETRAITE, RIPOSTE, SACRIFICE, SECOND_SOUFFLE, SIXIEME_SENS, SYSTEME_D, TENACITE, VACCIN, VOLTE_FACE,
+ VORTEX
+ }
+
+ class PlaceCard {
+ - number : Integer
+ - imageUrl : String
+ - color : String
+ + getNumber() : Integer
+ + getImageUrl() : String
+ + getColor() : String
+ + getType() : CardType
+ }
+
+ abstract class PlayerCard {
+ # phase : Phase
+ # phaseToApply : Phase
+ + getPhase() : Phase
+ + getPhaseToApply() : Phase
+ }
+
+ class SurvivalCard {
+ + getType() : CardType
+ }
+
+ class TrackingCard {
+ - symbols : List
+ + getType() : CardType
+ + getJetons() : List
+ + containsSymbol(type : JetonSymbol) : boolean
+
+ }
+
+ Card <|-- PlaceCard
+ Card <|-- PlayerCard
+ PlayerCard <|-- SurvivalCard
+ PlayerCard <|-- TrackingCard
+}
+....
+
+
+
+==== Jeton
+.Package jeton
+[plantuml]
+....
+package jeton{
+
+
+ enum JetonSymbol{
+ CIBLE
+ ARTEMIA
+ CREATURE
+ }
+
+ class PlacedJeton{
+ - jetonSymbol : JetonSymbol
+ - places : Place[*]
+ + getJetonSymbol() : Jeton
+ + getPlaces() : Place[*]
+ + equals(obj : object) : boolean
+ }
+}
+....
+
+==== Pioche
+.Package pioche
+[plantuml]
+....
+package pioche{
+ class Pioche {
+ - cards : T[*]
+ - trash : T[*]
+ - random : Random
+ - mix()
+ + draw() : T
+ + draw(number : Integer) : T[*]
+ + throwAway(cards : T[*])
+ + throwAway(card : T)
+ + drawLastTrashCards(number : Integer) : T[*]
+ + getTrash() : T[*]
+ + getCards() : T[*]
+ }
+}
+....
+
+==== Planet
+.Package planet
+[plantuml]
+....
+package planet{
+ class BeaconPawn{
+ - state : Integer
+ - nextState()
+ + isActive() : Boolean
+ + getType() : PawnType
+ + maxMovesInOneRound() : Integer
+ + stateToInt() : Integer
+ }
+ enum PawnType{
+ SHIELD
+ BEACON
+ }
+ enum Place{
+ PLACE_ONE
+ PLACE_TWO
+ PLACE_THREE
+ PLACE_FOUR
+ PLACE_FIVE
+ PLACE_SIX
+ PLACE_SEVEN
+ PLACE_EIGHT
+ PLACE_NINE
+ PLACE_TEN
+ }
+ class PlaceDistribution{
+ - mapCardNumberToPlaceCard : Map
+ - mapPlaceCardToPlace : Map
+ - placeIsHidden : Map
+ - initialization(placeCards : PlaceCard[*])
+ - initializePlaceCardsVisibility()
+ - initializePlaces()
+ + createPawn() : PlanetPawn
+ + isValidPlacesForJeton(adjacentPlaces Place[*]) : boolean
+ + isValidPlacesForJeton(adjacentPlacesCard : PlaceCard[*]) : Boolean
+ + placeCardToPlace(card : PlaceCard) : Place
+ + placeToPlaceCard(place : Place) : PlaceCard
+ + useCardLabyrinthe() : Boolean
+ + useCardDome() : Boolean
+ + useCardPole() : Boolean
+ + getPlaceCardsInInterval(a : Integer, b : Integer) : PlaceCard[*]
+ + getPlaceCards() : PlaceCard[*]
+ + isHiddenCards() : boolean
+ + getHiddenCards() : PlaceCard[*]
+ + getHiddenPlaces() : Place[*]
+ + revealPlace(place : Place)
+ + revealPlace(placeCard : PlaceCard)
+ + isRevealedPlace(place : Place)
+ + isRevealedPlace(placeCard : PlaceCard)
+ }
+ class Planet{
+ - static(LABYRINTHE_NUMBER : Integer)
+ - static(DOME_NUMBER : Integer)
+ - static(POLE_NUMBER : Integer)
+
+ - mapPlaceToJetons : Map
+ - blockedPlaces : Map
+ - placeSurvivalCardMap : Map
+ - numberMovesAllowInRound : Integer
+ - placeDistribution : PlaceDistribution
+ - planetPawn : PlanetPawn
+ - epaveUsedInTheRound : Boolean
+ + getPlaceDistribution() : PlaceDistribution
+ + getMapPlaceToJetons() : JetonSymbol[*]
+ + getPlacedJetons() : PlacedJeton[*]
+ + reset()
+ + placeJeton(placedJeton : PlacedJeton)
+ + findPlacesWhereJetonIs(symbol : JetonSymbol) : Place[*]
+ + findPlaceCardsWhereJetonIs(symbol : JetonSymbol) : PlaceCard[*]
+ + removeJeton(symbol : JetonSymbol)
+ + blockPlaces(places : Place[*])
+ + blockPlaces(place : Place)
+ + blockPlaces(placeCard : PlaceCard[*])
+ + isBlockedPlace(card : PlaceCard) : Boolean
+ + isJetonOnPlace(place : Place) : Boolean
+ + isJetonOnPlace(placeCard : PlaceCard) : Boolean
+ + findJetonsSymbolsOnCard(placeCard : PlaceCard) : JetonSymbol[*]
+ + isJetonSymbolOnPlaceCard(symbol : JetonSymbol,placeCard : PlaceCard) : boolean
+ + getPlanetPawn() : PlanetPawn
+ + canMovePlanetPawn() : Boolean
+ + movePlanetPawn() : Boolean
+ + forceMovePlanetPawn()
+ + moveBackPlanetPawn()
+ + resetPawn()
+ + placesWhereJetonCreatureIs() : PlaceCard[*]
+ + getPlaceCardsInInterval(a : Integer, b : Integer) : PlaceCard[*]
+ + planetPawnIsActive() : Boolean
+ + getPlanetPawnType() : PawnType
+ + canUseEpavePower() : boolean
+ + setEpavePowerToUsed()
+ + placeToPlaceCard(place : Place) : PlaceCard
+ + isASurvivalCardOnPlace(place : Place) : boolean
+ + isASurvivalCardOnPlace(placeCard : PlaceCard) : boolean
+ + takeSurvivalCardOnPlace(place : Place) : SurvivalCard
+ + takeSurvivalCardOnPlace(placeCard : PlaceCard) : SurvivalCard
+ + putSurvivalCardOnPlace(pair : Pair)
+ + putSurvivalCardOnPlace(pair : (Pair)[*])
+ + placeToNumber(place : Place) : Integer
+ + numberToPlace(number : Integer) : Place
+ + isAdjacentPlaces(place1 : Integer, place2 : Integer) : boolean
+ + isAdjacentPlaces(placeCard : PlaceCard, place : Place) : boolean
+ + isAdjacentPlaces(placeCard1 : PlaceCard, placeCard1 : PlaceCard) : boolean
+ + isAdjacentPlaces(place1 : Place, place2 : Place) : boolean
+ + isHiddenCards() : boolean
+ + getHiddenCards() : PlaceCard[*]
+ + getHiddenPlaces() : Place[*]
+ + revealPlace(place : Place)
+ + revealPlace(placeCard : PlaceCard)
+ + isRevealedPlace(place : Place): boolean
+ + isRevealedPlace(placeCard : PlaceCard): boolean
+ + swapJeton(symbol1 : JetonSymbol, symbol2 : JetonSymbol)
+ }
+
+ abstract class PlanetPawn{
+ # {abstract} getType() : PawnType
+ # {abstract} nextState()
+ + previousState()
+ # {abstract} isActive() : Boolean
+ # {abstract} maxMovesInOneRound() : Integer
+ + reset()
+ # {abstract} stateToInt() : Integer
+
+ }
+
+
+
+ class ShieldPawn{
+ - location : Integer
+ - hasReachDome : boolean
+ + getLocation() : Integer
+ + nextState()
+ + previousState()
+ + isActive() : Boolean
+ + getType() : PawnType
+ + maxMovesInOneRound() : Integer
+ + reset()
+ + stateToInt() : Integer
+
+ }
+
+
+ Planet "1" -- "1 placeDistribution" PlaceDistribution
+ Planet "1" -- "1 planetPawn" PlanetPawn
+ PlanetPawn <|-- ShieldPawn
+ PlanetPawn <|-- BeaconPawn
+ Planet *-- Place
+}
+....
+
+
+==== Player
+.Package player
+[plantuml]
+....
+package player{
+ enum PlayerTeam{
+ CREATURE
+ TRAQUE
+ }
+ abstract class Player{
+ # name : String
+ # inGameId : Integer
+ # Phase : currentPhase
+ + getName() : String
+ + getInGameId() : Integer
+ + getCurrentPhase() : Phase
+ # {abstract} getTeam() : PlayerTeam
+ + setCurrentPhase(currentPhase : Phase)
+ + teamEqualsTo(team : PlayerTeam) : boolean
+ }
+
+ class Traque{
+ - static(MAX_WILLINGNESS : Integer)
+ - numberWillingness : Integer
+ - hand : HandTraque
+ - rights : TraqueRight
+ - placeCardsPlayedAfterMoving : PlaceCard[*]
+ - placeCardsPlayedAndVisible : PlaceCard[*]
+ + getNumberWillingness() : Integer
+ + getMaxWillingness() : Integer
+ + getHand() : HandTraque
+ + getRights() : TraqueRight
+ + addWillingness(delta : Integer)
+ + subWillingness(delta : Integer)
+ + incrementWillingness()
+ + decrementWillingness()
+ + fillWillingness()
+ + addPlaceCardsAfterMoving(placeCard : PlaceCard)
+ + addPlaceCardsAfterMoving(placeCards : PlaceCard[*])
+ + getPlaceCardsPlayedAndVisible() : PlaceCard[*]
+ + addPlaceCardsPlayedAndVisible(placeCard : PlaceCard)
+ + addPlaceCardsPlayedAndVisible(placeCards : PlaceCard[*])
+ + reset()
+ + getTeam() : PlayerTeam
+ + getPlaceCards() : PlaceCard[*]
+ + getPlaceCardsPlayed() : PlaceCard[*]
+ + getDefausse() : PlaceCard[*]
+ + setPlaceCards(placeCards : PlaceCard[*])
+ + setDefausse(placeCards : PlaceCard[*])
+ + placeCardHandSize() : Integer
+ + placeCardIsEmpty() : boolean
+ + defausseSize() : Integer
+ + defausseIsEmpty() : boolean
+ + placeCardPlayedSize() : Integer
+ + placeCardPlayedIsEmpty() : boolean
+ + throwAwayPlaceCard() : boolean
+ + throwAwayPlaceCard(placeCard : PlaceCard) : boolean
+ + throwAwayPlaceCard(placeCards : PlaceCard[*]) : boolean
+ + takeBackPlaceCard(placeCard : PlaceCard) : boolean
+ + takeBackPlaceCard(placeCards : PlaceCard[*]) : boolean
+ + takeBackAllPlaceCardFromDefausse()
+ + addPlaceCard(placeCard : PlaceCard) : boolean
+ + addPlaceCard(placeCards : PlaceCard[*]) : boolean
+ + addPlaceCardInDefausse(placeCard : PlaceCard) : boolean
+ + addPlaceCardInDefausse(placeCards : PlaceCard[*]) : boolean
+ + playPlaceCard(placeCard : PlaceCard) : boolean
+ + playPlaceCard(placeCards : PlaceCard[*]) : boolean
+ + getSurvivalCardsHand() : SurvivalCard[*]
+ + getSurvivalCardsPlayed() : SurvivalCard[*]
+ + survivalCardHandSize() : Integer
+ + survivalCardPlayedSize() : Integer
+ + survivalCardIsEmpty() : boolean
+ + survivalCardPlayedIsEmpty() : boolean
+ + clearSurvivalCardPlayed()
+ + addSurvivalCard(survivalCard : SurvivalCard) : boolean
+ + addSurvivalCard(survivalCards : SurvivalCard[*]) : boolean
+ + removeSurvivalCard(survivalCard : SurvivalCard) : boolean
+ + removeSurvivalCard(survivalCards : SurvivalCard[*]) : boolean
+ + playSurvivalCard(survivalCard : SurvivalCard) : boolean
+ + playSurvivalCard(survivalCards : SurvivalCard[*]) : boolean
+ + addSurvivalCardToApplied(survivalCard : SurvivalCard)
+ + removeSurvivalCardToApplied(survivalCard : SurvivalCard)
+ + removeSurvivalCardToApplied(survivalCards : SurvivalCard[*])
+ + getSurvivalCardsToApplied() : SurvivalCard[*]
+ + resetRight()
+ + getMaxPlacesCardChoosable() : Integer
+ + setMaxPlacesCardChoosable(maxPlacesCardChoosable : Integer)
+ + getMaxPlacesCardPlayable() : Integer
+ + setMaxPlacesCardPlayable(maxPlacesCardPlayable : Integer)
+ + getMaxSurvivalCardPlayable() : Integer
+ + setMaxSurvivalCardPlayable(maxSurvivalCardPlayable : Integer)
+ + canResist() : boolean
+ + setCanResist(canResist : boolean)
+ + canGiveUp() : boolean
+ + setCanGiveUp(canGiveUp : boolean)
+ + getPlaceCardsVisible() : Integer
+ + setPlaceCardsVisible(placeCardsVisible : Integer)
+
+ }
+
+ class Creature{
+ - hand : HandCreature
+ - rights : CreatureRight
+ + getHand() : HandCreature
+ + getRights() : CreatureRight
+ + getTeam() : PlayerTeam
+ + reset()
+ + initializationJeton()
+ + jetonsSize() : Integer
+ + jetonsPlayedSize() : Integer
+ + jetonsIsEmpty() : boolean
+ + getJetons() : JetonSymbol[*]
+ + playJeton(jeton : JetonSymbol) : boolean
+ + playJeton(jetons : JetonSymbol[*]) : boolean
+ + jetonsPlayedIsEmpty() : boolean
+ + getMaxTrackingCards() : Integer
+ + getTrackingCardHand() : TrackingCard[*]
+ + getTrackingCardsPlayed() : TrackingCard[*]
+ + trackingCardHandSize() : Integer
+ + trackingCardPlayedSize() : Integer
+ + trackingCardIsEmpty() : Boolean
+ + trackingCardPlayedIsEmpty() : Boolean
+ + clearTrackingCardPlayed()
+ + addTrackingCard(trackingCard : TrackingCard) : Boolean
+ + addTrackingCard(trackingCards : TrackingCard[*]) : Boolean
+ + removeTrackingCard(trackingCard : TrackingCard) : Boolean
+ + removeTrackingCard(trackingCards : TrackingCard[*]) : Boolean
+ + playTrackingCard(trackingCard : TrackingCard) : Boolean
+ + playTrackingCard(trackingCards : TrackingCard[*]) : Boolean
+ + addTrackingCardToApplied(trackingCard : TrackingCard)
+ + addTrackingCardToApplied(trackingCards : TrackingCard[*])
+ + removeTrackingCardToApplied(trackingCard : TrackingCard)
+ + removeTrackingCardToApplied(trackingCards : TrackingCard[*])
+ + setMaxTrackingCardPlayable(maxTrackingCardPlayable : Integer)
+ + getTrackingCardToApplied() : TrackingCard[*]
+ + getMaxTrackingCardPlayable() : Integer
+
+
+
+ }
+
+ package rights{
+ class TraqueRight{
+ - maxPlacesCardChoosable : Integer
+ - placeCardsVisible : Integer
+ - maxPlacesCardPlayable : Integer
+ - maxSurvivalCardPlayable : Integer
+ - canResist : boolean
+ - canGiveUp : boolean
+ - numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist : Integer
+ + reset()
+ + getMaxPlacesCardChoosable() : Integer
+ + setMaxPlacesCardChoosable(maxPlacesCardChoosable : Integer)
+ + getMaxPlacesCardPlayable() : Integer
+ + setMaxPlacesCardPlayable(maxPlacesCardPlayable : Integer)
+ + getMaxSurvivalCardPlayable() : Integer
+ + setMaxSurvivalCardPlayable(maxSurvivalCardPlayable : Integer)
+ + getPlaceCardsVisible() : Integer
+ + setPlaceCardsVisible(placeCardsVisible : Integer)
+ + getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist() : Integer
+ + setNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(number : Integer)
+ + canResist() : boolean
+ + setCanResist(canResist : boolean)
+ + canGiveUp() : boolean
+ + setCanGiveUp(canGiveUp : boolean)
+
+ }
+
+ class CreatureRight{
+ - maxTrackingCardPlayable : Integer
+ + getMaxTrackingCardPlayable() : Integer
+ + setMaxTrackingCardPlayable(maxTrackingCardPlayable : Integer)
+ + reset()
+ }
+ }
+
+ package hand{
+ class Deck {
+ - cards : T[*]
+ - playedCards : T[*]
+ - maxCards : Integer
+ + getMaxCards(): Integer
+ + getCards(): T[*]
+ + getPlayedCards(): T[*]
+ + clear()
+ + add(card : T) : Boolean
+ + add(cardList : T[*]) : Boolean
+ + remove(card : T) : Boolean
+ + remove(cardList : T[*]) : Boolean
+ + play(card : T) : Boolean
+ + play(cardList : T[*]): Boolean
+ + handSize(): Integer
+ + playedCardSize(): Integer
+ + handIsEmpty(): boolean
+ + playedCardIsEmpty(): boolean
+
+ }
+
+ class PlaceCardDeck{
+ - placeCards : PlaceCard[*]
+ - defausse : PlaceCard[*]
+ - playedCards : PlaceCard[*]
+ + getPlayedCards() : PlaceCard[*]
+ + getPlaceCards() : PlaceCard[*]
+ + getDefausse() : PlaceCard[*]
+ + setPlaceCards(placeCards : PlaceCard[*])
+ + setDefausse(defausse : PlaceCard[*])
+ + setPlayedCards(playedCards : PlaceCard[*])
+ + throwAway() : Boolean
+ + throwAway(card : PlaceCard) : Boolean
+ + throwAway(cards : PlaceCard[*]) : Boolean
+ + takeBack(card : PlaceCard) : Boolean
+ + takeBack(cards : PlaceCard[*]) : Boolean
+ + takeBackAllFromDefausse()
+ + takeBackPlayedPlaceCards()
+ + add(card : PlaceCard) : Boolean
+ + add(cards : PlaceCard[*]) : Boolean
+ + addInDefausse(card : PlaceCard) : Boolean
+ + addInDefausse(cards : PlaceCard[*]) : Boolean
+ + play(card : PlaceCard) : Boolean
+ + play(cards : PlaceCard) : Boolean
+ + handSize() : Integer
+ + handIsEmpty() : boolean
+ + defausseSize() : Integer
+ + defausseIsEmpty() : boolean
+ + playedCardSize() : Integer
+ + playedCardIsEmpty() : boolean
+ }
+
+ class HandCreature{
+ - trackingCards : Deck
+ - jetons : JetonSymbol[*]
+ - jetonSymbolsPlayed : JetonSymbol[*]
+ - trackingCardsToApplied : TrackingCard[*]
+ + initializationJeton()
+ + addTrackingCardToApplied(trackingCard : TrackingCard)
+ + addTrackingCardToApplied(trackingCards : TrackingCard[*])
+ + removeTrackingCardToApplied(trackingCard : TrackingCard)
+ + removeTrackingCardToApplied(trackingCards : TrackingCard[*])
+ + getTrackingCardToApplied() : TrackingCard[*]
+ + getJetonSymbolsPlayed() : JetonSymbol[*]
+ + getJetonSymbols() : JetonSymbol[*]
+ + playJeton(jeton : Jeton) : Boolean
+ + playJeton(jetons : Jeton[*]) : Boolean
+ + jetonsSize() : Integer
+ + jetonsPlayedSize() : Integer
+ + jetonsIsEmpty() : boolean
+ + jetonsPlayedIsEmpty() : boolean
+ + getMaxTrackingCards() : Integer
+ + getTrackingCardsDeck() : Deck
+ + getTrackingCardHand() : TrackingCard[*]
+ + getTrackingCardsPlayed() : TrackingCard[*]
+ + trackingCardHandSize() : Integer
+ + trackingCardPlayedSize() : Integer
+ + trackingCardIsEmpty() : boolean
+ + trackingCardPlayedIsEmpty() : boolean
+ + clearTrackingCardPlayed()
+ + addTrackingCard(trackingCard : TrackingCard) : boolean
+ + addTrackingCard(cardList : TrackingCard[*]) : boolean
+ + removeTrackingCard(trackingCard : TrackingCard) : boolean
+ + removeTrackingCard(cardList : TrackingCard[*]) : boolean
+ + playTrackingCard(trackingCard : TrackingCard) : boolean
+ + playTrackingCard(cardList : TrackingCard[*]) : boolean
+
+ }
+
+ class HandTraque{
+ - survivalCards : Deck
+ - placeCards : PlaceCardDeck
+ - survivalCardsToApplied : SurvivalCard[*]
+ + addSurvivalCardToApplied(survivalCard : SurvivalCard)
+ + addSurvivalCardToApplied(survivalCards : SurvivalCard[*])
+ + removeSurvivalCardToApplied(survivalCard : SurvivalCard)
+ + removeSurvivalCardToApplied(survivalCards : SurvivalCard[*])
+ + getSurvivalCardsToApplied() : SurvivalCard[*]
+ + getPlaceCards() : PlaceCard[*]
+ + getPlaceCardsPlayed() : PlaceCard[*]
+ + getDefausse() : PlaceCard[*]
+ + setPlaceCards(placeCards : PlaceCard[*])
+ + setDefausse(placeCards : PlaceCard[*])
+ + getPlaceCardsDeck() : PlaceCardDeck
+ + placeCardHandSize() : Integer
+ + placeCardIsEmpty() : boolean
+ + defausseSize() : Integer
+ + defausseIsEmpty() : boolean
+ + placeCardPlayedSize() : Integer
+ + placeCardPlayedIsEmpty() : boolean
+ + throwAwayPlaceCard() : boolean
+ + throwAwayPlaceCard(card : PlaceCard) : boolean
+ + throwAwayPlaceCard(cards : PlaceCard[*]) : boolean
+ + takeBackPlaceCard(card : PlaceCard) : boolean
+ + takeBackPlaceCard(cards : PlaceCard[*]) : boolean
+ + takeBackPlayedPlaceCards(card : PlaceCard) : boolean
+ + takeBackPlaceCard(cards : PlaceCard[*]) : boolean
+ + takeBackPlayedPlaceCards()
+ + takeBackAllPlaceCardFromDefausse()
+ + addPlaceCard(card : PlaceCard) : boolean
+ + addPlaceCard(cards : PlaceCard[*]) : boolean
+ + addPlaceCardInDefausse(card : PlaceCard) : boolean
+ + addPlaceCardInDefausse(cards : PlaceCard[*]) : boolean
+ + playPlaceCard(card : PlaceCard) : boolean
+ + playPlaceCard(cards : PlaceCard[*]) : boolean
+ + getSurvivalCardsDeck() : Deck
+ + getSurvivalCardsHand() : SurvivalCard[*]
+ + getSurvivalCardsPlayed() : SurvivalCard[*]
+ + survivalCardHandSize() : Integer
+ + survivalCardPlayedSize() : Integer
+ + survivalCardIsEmpty() : boolean
+ + survivalCardPlayedIsEmpty() : boolean
+ + clearSurvivalCardPlayed()
+ + addSurvivalCard(card : SurvivalCard) : boolean
+ + addSurvivalCard(cards : SurvivalCard[*]) : boolean
+ + removeSurvivalCard(card : SurvivalCard) : boolean
+ + removeSurvivalCard(cards : SurvivalCard[*]) : boolean
+ + playSurvivalCard(card : SurvivalCard) : boolean
+ + playSurvivalCard(cards : SurvivalCard[*]) : boolean
+
+
+ }
+
+
+ HandTraque "1" -- "1" PlaceCardDeck
+ HandCreature "1" -- "1" Deck
+ HandTraque "1" -- "1" Deck
+ }
+
+ Player <|-- Creature
+ Player <|-- Traque
+
+ PlayerStatus <|-- CreatureRight
+ PlayerStatus <|-- TraqueRight
+
+ Creature "1" - "1" CreatureRight
+ Traque "1" - "1" TraqueRight
+}
+
+....
+
+
+
+
+==== Power
+.Package power
+[plantuml]
+....
+package power{
+ class Power{
+ - inGameIdPlayer : Integer
+ + getInGameIdPlayer() : Integer
+ # {abstract} getType() : PowerType
+ }
+
+ enum PowerType{
+ MODIFICATOR
+ RECURRENT
+ }
+ package modifier{
+ class PowerModifier{
+ - modificatorType : PowerModifierType
+ - modifiedValue : Object
+ + getModificatorType() : PowerModifierType
+ + getModifiedValue() : Object
+ + getType() : PowerType
+ }
+ enum PowerType{
+ CHOOSABLE_PLACE_CARD
+ PLAYABLE_PLACE_CARD
+ CHOOSABLE_VISIBLE_ADDITIONAL_PLACE_CARD
+ PLAYABLE_TRACKING_CARD
+ USE_FJORD_IN_PREVIOUS_ROUND
+ }
+ package recurrent{
+ class PowerRecurrent{
+ - action : BiConsumer
+ - condition : BiPredicate
+ + apply(game : Game)
+ + conditionIsTrue(game : Game) : Boolean
+ + getType() : PowerType
+ }
+ }
+
+
+}
+....
+==== Phase
+.Phase
+[plantuml]
+....
+enum Phase{
+ PREPHASE_1
+ PHASE_1
+ POSTPHASE_1
+ PREPHASE_2
+ PHASE_2
+ POSTPHASE_2
+ PREPHASE_3
+ PHASE_3
+ POSTPHASE_3
+ PREPHASE_4
+ PHASE_4
+ POSTPHASE_4
+}
+....
+
+==== Reserve
+.Reserve
+[plantuml]
+....
+class Reserve{
+ - placeCards : Map>
+ + getNotEmptyPlaceCard() : PlaceCard[*]
+ + copiesNumber(numberPlayer : Integer) : Integer
+ + isNotEmpty() : Boolean
+ + notEmpty(cardNumber : Integer) : Boolean
+
+ + pick(cardNumber : Integer) : PlaceCard
+ + add(placeCard : PlaceCard)
+ + equals(obj : Object) : Boolean
+ + toString() : String
+}
+
+
+....
+
+=== Utilitary
+.Package utilitary
+[plantuml]
+....
+package utilitary{
+ package request{
+ enum GameRequestType{
+ JOIN
+ FINISH_PHASE
+ PLAY_CARDS
+ PLACE_JETONS
+ RESIST
+ GIVE_UP
+ }
+
+ class GameFinishPhaseRequest{
+ - phase : Phase
+ + getPhase() : Phase
+ + getType() : GameRequestType
+ + equals(obj : Object) : boolean
+ }
+ class GameGiveUpRequest{
+ + getType() : GameRequestType
+
+ }
+
+ class GameJoinRequest{
+ - inGameId : Integer
+ + getInGameId() : Integer
+ + getType() : GameRequestType
+ + equals(obj : Object) : boolean
+ }
+
+ class GamePlaceJetonsRequest{
+ - jetonList : PlacedJeton[*]
+ + getJetonList() : PlacedJeton[*]
+ + getType() : GameRequestType
+ + equals(obj : Object) : boolean
+ }
+ class GamePlayCardsRequest{
+ - cards : Card[*]
+ + getCards() : Card[*]
+ + getType() : GameRequestType
+ + equals(obj : Object) : boolean
+ }
+ abstract class GameRequest{
+ # user : User
+ # {abstract} getType() : GameRequestType
+ + getUser() : User
+ + equals(obj : Object) : boolean
+ }
+ class GameResistRequest{
+ - number : Integer
+ + getNumber() : Integer
+ + getType() : GameRequestType
+ + equals(obj : Object) : boolean
+ }
+
+ GameRequest <|-- GameJoinRequest
+ GameRequest <|-- GameResistRequest
+ GameRequest <|-- GamePlayCardsRequest
+ GameRequest <|-- GamePlaceJetonsRequest
+ GameRequest <|-- GameGiveUpRequest
+ GameRequest <|-- GameFinishPhaseRequest
+ }
+ class Conversion{
+ - {static} DATABASE : NotAloneDatabase
+ + {static} toPhase(s : String) : Phase
+ + {static} toPhase(tphase : TPhaseId) : Phase
+ + {static} toBoardColor(s : String) : BoardColor
+ + {static} toBoardColor(color : TColor) : BoardColor
+ + {static} toBoardDistribution(s : String) : BoardDistribution
+ + {static} toBoardDistribution(tBoard : TBoard) : BoardDistribution
+ + {static} toCardType(tCardType : String) : CardType
+ + {static} toCard(tCard : TCard) : Card
+ + {static} toCardList(tCards : TCard[*]) : Card[*]
+ + {static} toPlaceCardList(tPlaceCards : TCards[*]) : PlaceCard[*]
+ + {static} toCardName(name : String) : CardName[*]
+ + {static} toTCard(card : PlaceCard) : TCard
+ + {static} toTCard(card : SurvivalCard) : TCard
+ + {static} toTCard(card : TrackingCard) : TCard
+ + {static} toTCard(card : Card) : TCard
+ + {static} toJetonSymbol(s : String) : JetonSymbol
+ + {static} toPlacedJeton(tPlacedJeton : TPlacedJeton) : PlacedJeton
+ + {static} toPlacedJetonList(tPlacedJetons : TPlacedJeton[*]) : PlacedJeton[*]
+ + {static} toPlace(s : String) : Place
+ + {static} toPlaceList(positionJeton : TPositionJeton) : Place[*]
+ + {static} toPlaceList(strings : String[*]) : Place[*]
+ + {static} toTPairType(name : String) : TPairType
+ + {static} toAction(tAction : TAction) : Action
+ + {static} toUser(tPlayer : TPlayer) : User
+ + {static} toTScore(board : Board) : TScore
+ + {static} toTPlacedCard(placeCard : PlaceCard, place : Place) : TPlacedCard
+ + {static} toTPlacedJetonList(placedJetons : PlacedJeton[*]) : TPlacedJeton[*]
+ + {static} toTJeton(symbol : JetonSymbol) : TJeton
+ + {static} toTBalise(planetPawn : PlanetPawn) : PlanetPawn
+ + {static} toTPlanet(planet : Planet) : TPlanet
+ + {static} toTCardReserve(pair : Pair) : TCardReserve
+ + {static} toTCardReserveList(reserve : Reserve) : TCardReserve[*]
+ + {static} toTGameVariable(variables : GameRoundVariables) : TGameVariable[*]
+ + {static} toTCreature(creature : Creature) : TCreature
+ + {static} toTTraque(traque : Traque) : TTraque
+ + {static} toTTraquePlaceCardPlayedVisible(traque : Traque) : TTraque
+ + {static} toTHand(traque : Traque) : THand
+ + {static} toTHand(creature : Creature) : THand
+ + {static} toTHand(player : Player) : THand
+ }
+ class Pair{
+ - key : T
+ - value : U
+ + getKey() : T
+ + getValue() : U
+ + equals(obj : Object) : boolean
+ + toString() : String
+ }
+}
+
+
+....
+
+
+== Handler
+
+.Package Handler
+[plantuml]
+....
+package Handler{
+ class GameServiceHandler{
+ - service : RoomService
+ + createRoom(playerId : TPlayerId) : TRoomId
+ + sendStartGame(playerId : TPlayerId, idCreature : Integer, TBoard : board, Tcolor : color, tPlaceCards : TCard[*]) : Response
+ + joinRoom(playerId : TPlayerId, roomId : TRoomId) : Response
+ + getGameDescription(playerId : TPlayerId) : Response
+ + sendFinishPhase(playerId : TPlayerId, phaseId : TPhaseId) : Response
+ + sendPlayCards(playerId : TPlayerId, playerCards : TCard[*]) : Response
+ + sendPlaceJetons(playerId : TPlayerId, placedJetons : TPlacedJeton[*]) : Response
+ + sendResist(playerId : TPlayerId, number : Integer) : Response
+ + sendGiveUp(playerId : TPlayerId) : Response
+ }
+
+}
+
+....
+== User
+
+.Package User
+[plantuml]
+....
+package User{
+ class PlayerInterface{
+ + sendGameDescription(gameDescription : TDescription) : TRoomId
+ + sendGameStart()
+ + sendGameIsFinished(winner : TPlayerTeam)
+ + sendFirstRoundStart()
+ + sendStartPhase(phase : TPhase, gameDescription : TDescription)
+ + askAction(askedAction : TAskAction ) : TAction
+ + sendAction(askedAction : TAskAction )
+ + sendResponse(response : Response )
+ }
+ class PlayerProxy{
+ - client : PlayerService.Client
+ + ping() : boolean
+ + sendGameStart()
+ + sendGameDescription(gameDescription : TDescription)
+ + sendGameIsFinished(winner : TplayerTeam)
+ + sendFirstRoundStart()
+ + sendStartPhase(phase : TPhase, gameDescription : TDescription)
+ + askAction(askedAction : TAskAction ) : TAction
+ + sendAction(askedAction : TAskAction )
+ + sendResponse(response : Response )
+ }
+ class User{
+ - id : String
+ - name : String
+ - service : PlayerProxy
+ + getId() : String
+ + getName() : String
+ + getService() : PlayerProxy
+ + ping() : boolean
+ + sendGameStart()
+ + sendGameDescription(gameDescription : TDescription)
+ + sendGameIsFinished(winner : TplayerTeam)
+ + sendFirstRoundStart()
+ + sendStartPhase(phase : TPhase, gameDescription : TDescription)
+ + askAction(askedAction : TAskAction ) : TAction
+ + sendAction(askedAction : TAskAction )
+ + sendResponse(response : Response )
+ + equals(obj : Object ) : boolean
+ + hashCode() : Integer
+ }
+
+}
+
+....
+
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/exigences.adoc b/not-alone-doc/src/doc/asciidoc/_sections/exigences.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..390e48977bfb00afe472cc099b13a65031d619a9
--- /dev/null
+++ b/not-alone-doc/src/doc/asciidoc/_sections/exigences.adoc
@@ -0,0 +1,250 @@
+:project: Not Alone
+
+= Requirements Specification
+
+== Introduction
+
+// Ce chapitre décrit les exigences du projet «{project}». Il suit la norme IEEE 830-1998.
+
+=== Purpose
+
+The purpose of this document is to describe the requirement specifications for the project «{project}» for software engineering students.
+
+The intended audience of this specification includes the prospective developers of the tool, as well as the technical assessment personnel.
+
+// Identify the product whose software requirements are specified in this document, including the revision or release number. Describe the scope of the product that is covered by this SRS, particularly if this SRS describes only part of the system or a single subsystem.
+
+=== Document Conventions
+
+None so far.
+
+// Describe any standards or typographical conventions that were followed when writing this SRS, such as fonts or highlighting that have special significance. For example, state whether priorities for higher-level requirements are assumed to be inherited by detailed requirements, or whether every requirement statement is to have its own priority.
+
+=== Intended Audience and Reading Suggestions
+
+
+// Describe the different types of reader that the document is intended for, such as developers, project managers, marketing staff, users, testers, and documentation writers. Describe what the rest of this SRS contains and how it is organized. Suggest a sequence for reading the document, beginning with the overview sections and proceeding through the sections that are most pertinent to each reader type.
+
+=== Project Scope
+
+// Provide a short description of the software being specified and its purpose, including relevant benefits, objectives, and goals. Relate the software to corporate goals or business strategies. If a separate vision and scope document is available, refer to it rather than duplicating its contents here.
+
+The software system to be produced is a simplified version of the Hearthstone online room, which will be referred to as «{project}» thorough this document.
+
+The {project} system will allow players from different locations to confront each-other in short and intensive games.
+
+=== References
+
+. IEEE Standard 830-1993: IEEE Recommended Practice for Software Requirements Specifications
+
+
+// List any other documents or Web addresses to which this SRS refers. These may include user interface style guides, contracts, standards, system requirements specifications, use case documents, or a vision and scope document. Provide enough information so that the reader could access a copy of each reference, including title, author, version number, date, and source or location.
+
+=== Overview
+
+The rest of this document contains an overall description of the {project} software system (section <>), the specific functional requirements (section <>), and the non-functional requirements for the system (see <>.
+
+[#description]
+== Overall Description
+
+=== Product Perspective
+
+Hearthstone is a card room where two players confront each-other.
+The {project} software should allow players that are connected to the Internet to use their connected devices to play.
+Thus, «{project}» is an online, electronic version of the card room.
+
+While the system is distributed and organized in different components, players should perceive it as a single piece of software.
+Figure <> presents the overall architecture of the software.
+Players interact with a Web Client, which uses the HTTP protocol to communicate with (at most) one Game Server.
+Servers use TCP/IP to communicate with a Database Management Server, which stores all software data.
+
+// Describe the context and origin of the product being specified in this SRS. For example, state whether this product is a follow-on member of a product family, a replacement for certain existing systems, or a new, self-contained product. If the SRS defines a component of a larger system, relate the requirements of the larger system to the functionality of this software and identify interfaces between the two. A simple diagram that shows the major components of the overall system, subsystem interconnections, and external interfaces can be helpful.
+
+[#deployment]
+.UML Deployment Diagram
+[plantuml, deployment-diagram, png]
+----
+@startuml
+
+node Client {
+ artifact WebClient
+}
+node Server {
+ artifact GameServer
+}
+
+node Database {
+ artifact DBMS
+}
+
+WebClient -left- Server : TCP/IP - WebSockets
+Server -up- Database : JPA
+
+@enduml
+----
+
+=== Product Functions
+
+The {project} software must provide two main functions:
+
+. Game creation: allowing two players to discover each other and start a room.
+. Game play: allowing players to actually play {project} until the victory of one of them.
+
+// Summarize the major functions the product must perform or must let the user perform. Details will be provided in Section 3, so only a high level summary (such as a bullet list) is needed here. Organize the functions to make them understandable to any reader of the SRS. A picture of the major groups of related requirements and how they relate, such as a top level data flow diagram or object class diagram, is often effective.
+
+=== User Classes and Characteristics
+
+// Identify the various user classes that you anticipate will use this product. User classes may be differentiated based on frequency of use, subset of product functions used, technical expertise, security or privilege levels, educational level, or experience. Describe the pertinent characteristics of each user class. Certain requirements may pertain only to certain user classes. Distinguish the most important user classes for this product from those who are less important to satisfy.
+
+The {project} software has only one class of user: players.
+Players may have different levels: beginners, intermediate, or expert.
+However, independently from their level, players should use the same user interface to play against each other.
+
+=== Operating Environment
+
+// Describe the environment in which the software will operate, including the hardware platform, operating system and versions, and any other software components or applications with which it must peacefully coexist.
+
+The {project} software should operate on any popular and recent operating system: Linux, Windows, or MacOS.
+The Web Client should operate on any recent web browser: Firefox, Chrome, Safari, or Edge.
+
+=== Design and Implementation Constraints
+
+// Describe any items or issues that will limit the options available to the developers. These might include: corporate or regulatory policies; hardware limitations (timing requirements, memory requirements); interfaces to other applications; specific technologies, tools, and databases to be used; parallel operations; language requirements; communications protocols; security considerations; design conventions or programming standards (for example, if the customer’s organization will be responsible for maintaining the delivered software).
+
+. The Game Server must be developed in Java (version 1.8), using the https://spring.io[Spring Framework].
+. The Client must be developed in TypeScript (version 3.1), using the https://angular.io[Angular Framework].
+. All software artifacts must use a building too: Maven or Groovy for Java, npm for TypeScript.
+. Dynamic tests must use JUnit (version >= 5.0) and Jasmine (version >= 3.5.0).
+. The code must log its main operations using https://www.slf4j.org[SLF4J].
+
+
+=== Verification Constraints
+
+. Test Doubles must be used to test each component independently.
+. Each unit test must describe its intention.
+
+=== User Documentation
+
+// List the user documentation components (such as user manuals, on-line help, and tutorials) that will be delivered along with the software. Identify any known user documentation delivery formats or standards.
+
+No user documentation is required for the first version of the software.
+
+=== Assumptions and Dependencies
+
+// List any assumed factors (as opposed to known facts) that could affect the requirements stated in the SRS. These could include third-party or commercial components that you plan to use, issues around the development or operating environment, or constraints. The project could be affected if these assumptions are incorrect, are not shared, or change. Also identify any dependencies the project has on external factors, such as software components that you intend to reuse from another project, unless they are already documented elsewhere (for example, in the vision and scope document or the project plan).
+
+None until now.
+
+== External Interface Requirements
+
+=== User Interfaces
+
+// Describe the logical characteristics of each interface between the software product and the users. This may include sample screen images, any GUI standards or product family style guides that are to be followed, screen layout constraints, standard buttons and functions (e.g., help) that will appear on every screen, keyboard shortcuts, error message display standards, and so on. Define the software components for which a user interface is needed. Details of the user interface design should be documented in a separate user interface specification.
+
+=== Hardware Interfaces
+
+// Describe the logical and physical characteristics of each interface between the software product and the hardware components of the system. This may include the supported device types, the nature of the data and control interactions between the software and the hardware, and communication protocols to be used.
+
+The software does not interact directly with any hardware device.
+
+=== Software Interfaces}
+
+The client part of the software must operate on web browsers, whereas the server part must interact with a database through the Java Persistence API (JPA).
+
+// Describe the connections between this product and other specific software components (name and version), including databases, operating systems, tools, libraries, and integrated commercial components. Identify the data items or messages coming into the system and going out and describe the purpose of each. Describe the services needed and the nature of communications. Refer to documents that describe detailed application programming interface protocols. Identify data that will be shared across software components. If the data sharing mechanism must be implemented in a specific way (for example, use of a global data area in a multitasking operating system), specify this as an implementation constraint.
+
+=== Communications Interfaces
+
+// Describe the requirements associated with any communications functions required by this product, including e-mail, web browser, network server communications protocols, electronic forms, and so on. Define any pertinent message formatting. Identify any communication standards that will be used, such as FTP or HTTP. Specify any communication security or encryption issues, data transfer rates, and synchronization mechanisms.
+
+Communications between the client and the room server must use Websockets.
+
+[#features]
+== System Features
+
+// This template illustrates organizing the functional requirements for the product by system features, the major services provided by the product. You may prefer to organize this section by use case, mode of operation, user class, object class, functional hierarchy, or combinations of these, whatever makes the most logical sense for your product.
+
+=== Game initialization
+
+// Don’t really say “System Feature 1.” State the feature name in just a few words.
+
+The {project} software must allow the setup of a room with two players and automatically prepare and distribute cards.
+
+==== Description and Priority
+
+See Chapter <> (domain analysis) for further details.
+
+// Provide a short description of the feature and indicate whether it is of High, Medium, or Low priority. You could also include specific priority component ratings, such as benefit, penalty, cost, and risk (each rated on a relative scale from a low of 1 to a high of 9).
+
+==== Stimulus/Response Sequences
+
+// List the sequences of user actions and system responses that stimulate the behavior defined for this feature. These will correspond to the dialog elements associated with use cases.
+
+==== Functional Requirements
+
+// Itemize the detailed functional requirements associated with this feature. These are the software capabilities that must be present in order for the user to carry out the services provided by the feature, or to execute the use case. Include how the product should respond to anticipated error conditions or invalid inputs. Requirements should be concise, complete, unambiguous, verifiable, and necessary. Use “TBD” as a placeholder to indicate when necessary information is not yet available.
+
+// Each requirement should be uniquely identified with a sequence number or a meaningful tag of some kind.$>$
+
+// % REQ-1: REQ-2:
+
+=== Game play
+
+The {project} software must allow two players to play against each other until a winer is settled.
+See Chapter <> (domain analysis) for further details.
+
+[#nonfunctional]
+== Other Nonfunctional Requirements
+
+=== Performance Requirements}
+
+. The room must be _playable_, meaning that users must have fast feedback for their actions and delays due to communications/connection problems must be correctly held.
+. The Web Client must be able to execute on a personal computer with 4GB of RAM.
+
+
+// If there are performance requirements for the product under various circumstances, state them here and explain their rationale, to help the developers understand the intent and make suitable design choices. Specify the timing relationships for real time systems. Make such requirements as specific as possible. You may need to state performance requirements for individual functional requirements or features.
+
+=== Safety Requirements
+
+// Specify those requirements that are concerned with possible loss, damage, or harm that could result from the use of the product. Define any safeguards or actions that must be taken, as well as actions that must be prevented. Refer to any external policies or regulations that state safety issues that affect the product’s design or use. Define any safety certifications that must be satisfied.
+
+=== Security Requirements
+
+// Specify any requirements regarding security or privacy issues surrounding use of the product or protection of the data used or created by the product. Define any user identity authentication requirements. Refer to any external policies or regulations containing security issues that affect the product. Define any security or privacy certifications that must be satisfied.
+
+=== Software Quality Attributes
+
+// Specify any additional quality characteristics for the product that will be important to either the customers or the developers. Some to consider are: adaptability, availability, correctness, flexibility, interoperability, maintainability, portability, reliability, reusability, robustness, testability, and usability. Write these to be specific, quantitative, and verifiable when possible. At the least, clarify the relative preferences for various attributes, such as ease of use over ease of learning.
+
+==== Extensibility
+
+The software must be extensible, it must be easy for developers to add new cards and heroes to the room.
+
+==== Maintainability
+
+. The software must be readable and easy to maintain.
+. The Java source must respect Google's guidelines: https://google-styleguide.googlecode.com/svn/trunk/javaguide.html
+
+=== Business Rules
+
+// List any operating principles about the product, such as which individuals or roles can perform which functions under specific circumstances. These are not functional requirements in themselves, but they may imply certain functional requirements to enforce the rules.
+
+
+== Other Requirements
+
+// Define any other requirements not covered elsewhere in the SRS. This might include database requirements, internationalization requirements, legal requirements, reuse objectives for the project, and so on. Add any new sections that are pertinent to the project.
+
+=== Appendix A: Glossary
+
+//see https://en.wikibooks.org/wiki/LaTeX/Glossary
+// Define all the terms necessary to properly interpret the SRS, including acronyms and abbreviations. You may wish to build a separate glossary that spans multiple projects or the entire organization, and just include terms specific to a single project in each SRS.
+
+=== Appendix B: Analysis Models
+
+See Chapter <> (domain analysis) for further details.
+
+// Optionally, include any pertinent analysis models, such as data flow diagrams, class diagrams, state-transition diagrams, or entity-relationship diagrams.
+
+=== Appendix C: To Be Determined List
+
+// Collect a numbered list of the TBD (to be determined) references that remain in the SRS so they can be tracked to closure.
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc b/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc
index 5f69debccac755e14fd9d4ad5f0ee2b486679596..08699cc8e0da6e0e4ec7dec08eb4bc4dffdf0b09 100644
--- a/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc
+++ b/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc
@@ -8,9 +8,115 @@
|*Signification*
|*Exemples*
-| Créature
-| a
-| ax
+|Joueur
+| Chacun des participants au jeu.
+|
+| Anna, Mathis, Kévin.
+
+|Traqué
+| Joueur(s) devant survivre aux assauts de la Créature.
+|
+| Anna, Kévin.
+
+|Créature
+| Joueur incarnant le monstre pourchassant les Traqués.
+|
+| Mathis.
+
+|Plateau
+| Objet faisant office de score. Il est composé de cases Assimilation et de cases Secours. Il peut être disposé de deux façons différentes.
+|
+| Les cases marquée Artémia sur les cases Secours sont successives (et non 1/2).
+
+|Planète
+| Représente l'endroit où se déroule le jeu. Elle se nomme Artémia, et elle est composé de dix lieux.
|
+| L'Ante, la Jungle, la Rivière, la Plage, le Rover, le Marais, l'Abri, l'Épave, la Source, l'Artefact.
+|Pion
+| Objet permettant de marquer le score des joueurs sur le plateau.
+|
+|
+
+|PionAssimilation
+| Pion permettant de marquer le score de la Créature.
+|
+|
+
+|PionSecours
+| Pion permettant de marquer le score de l'équipe des Traqués.
+|
+|
+
+| Pouvoir
+| Un pouvoir représente un ensemble d'actions. Ces actions peuvent modifier une règle ou un élément de la partie (score, cartes, ...).
+|
+| Evitez les effets du jeton Créature ; Reprenez en main cette carte Lieu et une carte Lieu de votre défausse.
+
+
+| Carte
+| Objet possédant un pouvoir.
+|
+|
+
+|CarteLieu
+| Carte représentant un lieu et possédant un pouvoir.
+|
+|La rivière.
+
+|CarteSurvie
+| Cartes jouables uniquement par les Traqués et possédant un pouvoir.
+|
+| Vortex
+
+
+|CarteTraque
+| Cartes jouables uniquement par la Créature et possédant un pouvoir.
+|
+| Clone
+
+
+|Main
+| Représente les cartes lieux possédées par un Traqué à un moment de la partie.
+|
+| La Plage, l'Antre pour Anna et la Rivière et l'Épave pour Kévin.
+
+
+|Défausse
+| Représente l'endroit où un Traqué met ses CarteLieux défaussées.
+|
+| La Plage, l'Antre, le Rover et la Jungle pour Kévin. Le Rover, la Rivière, la Plage, l'Antre pour Anna.
+
+
+|PionVolonté
+| Représente la volonté d'un Traqué.
+|
+| 2 pions pour Anna, 1 pour Kévin.
+
+
+|Réserve
+| Représente l'endroit où sont stockées les CarteLieux numérotées de 6 à 10 quand elles n'ont pas encore été mises en jeu.
+|
+|
+
+
+|JetonTraque
+| Représente les jetons dont dispose la Créature pour marquer certains lieux durant un tour.
+|
+|
+
+|JetonCible
+|Si un traqué choisit le lieu marqué de ce pion : il subit l'effet de la carte cible et peut ensuite utiliser le pouvoir de la carte Lieu OU reprendre en main 1 carte Lieu au choix de sa défausse.
+|
+|
+
+|JetonCréature
+| Si un traqué choisit le lieu marqué de ce pion : il perd un pion de volonté. Peut importe le nombre de joueur le pion assimilation avance de 1.
+|
+|
+
+|JetonArtemia
+|Si un traqué choisit le lieu marqué de ce pion : il perd 1 carte lieu de sa main et ne créer pas l'effet du lieu où est le jeton.
+|
+|
|===
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/use-cases/deroulement.adoc b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/deroulement.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..aa68922621f3897675d4c0f87eaacf94227cad45
--- /dev/null
+++ b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/deroulement.adoc
@@ -0,0 +1,94 @@
+
+[cols="30s,70n",options="header", frame=sides]
+|===
+| Item | Description
+
+| # | 2
+| Use Case | Déroulement
+
+| AKA
+|
+
+| Goal in Context
+| Effectuer un tour
+
+
+| Scope | scope
+
+| Level | Summary
+| Success End Condition |
+| Failed End Condition |
+| Primary Actor | Les joueurs
+
+| Secondary Actor
+|
+
+| Trigger | Fin de mise en place ou fin d'un déroulement
+| Priority | Elevée
+
+| Frequency | Plusieurs fois à chaque partie
+
+
+| Pre-conditions
+a|
+- Le jeu a été mis en place antérieurement
+- Tous les joueurs présents lors de la mise en place sont toujours présents
+- La partie n'est pas finie
+
+| Post-conditions
+|
+
+|Main success scenario
+a|
+1. Phase 1
+ a. Les Traqués jouent une CarteLieu face cachée
+2. Phase 2
+ a. La créature pose son JetonCréature sur une CarteLieu de la planète
+3. Phase 3
+ a. Les Traqués dévoilent simultanément leur CarteLieu jouée
+ b. Les Traqués résolvent les lieux correspondants à la CarteLieu jouée dans un ordre préalablement défini
+4. Phase 4
+ a. Chaque Traqué défausse sa CarteLieu jouée face visible
+ b. La Créature reprend ses JetonTraque
+ c. La Créature pioche des CarteTraque jusqu'à en avoir 3 en mains
+ d. Le Pion Secours avance d'une case
+5. Fin de tour
+ a. Déclencher un nouveau déroulement
+| Variations
+a|
+1. Au début de chaque phase :
+ a. La Créature joue une CarteTraque (sauf contre-indication : au maximum une CarteTraque par déroulement)
+ b. Un ou des Traqués jouent une CarteSurvie
+2. Phase 1
+ a. Un ou des Traqués résistent
+ b. Un ou des Traqués lâchent prise
+ c. Le pion assimilation atteint la case Victoire et la partie est finie.
+3. Phase 2
+ a. La Créature pose son JetonArtemia
+ b. La Créature pose son JetonCible
+4. Phase 3
+ a. Un Traqué explore un lieu avec le JetonCréature.
+ Il perds un PionVolonté et ne peut pas résoudre le lieu lors de la phase suivante.
+ Le PionAssimilation avance de 1 case si c'est le premier Traqué attrapé lors de cette phase.
+ b. Un Traqué explore un lieu avec le JetonArtemia.
+ Le pouvoir du lieu sera inutilisable lors de la phase suivante.
+ Il défausse une CarteLieu de sa main.
+ c. Un Traqué explore un lieu avec le jeton Cible.
+ Le Pouvoir de la CarteTraque s'applique.
+ d. Le PionAssimilation atteint la case Victoire. La partie est finie.
+5. Fin de tour
+ a. Le PionSecours atteint la case Victoire. La partie est finie.
+
+
+|Superordinate Use Case | None
+|Subordinate Use Cases | optional, depending on tools, links to sub.use cases
+|Performance Target |the amount of time this use case should take
+
+|Open Issues
+a|
+
+|Schedule |
+|Constraints |
+|Annexes
+|
+|===
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/use-cases/mise-en-place.adoc b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/mise-en-place.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..681d34bd4a58deefc695c8172bb41a50b7371dc0
--- /dev/null
+++ b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/mise-en-place.adoc
@@ -0,0 +1,76 @@
+== Tableau de mise en place
+
+[cols="30s,70n",options="header", frame=sides]
+|===
+| Item | Description
+
+| # | 1
+| Use Case | Mise en place
+
+| AKA
+|
+
+| Goal in Context
+| Préparer le jeu
+
+
+| Scope | scope
+
+| Level | Summary
+| Success End Condition |
+| Failed End Condition |
+| Primary Actor | Le maître du jeu
+
+| Secondary Actor
+| Les joueurs
+
+| Trigger | Début de partie
+| Priority | Elevée
+
+| Frequency | Avant chaque partie
+
+
+| Pre-conditions
+a|. Il y a entre 2 et 7 joueurs.
+. Un joueur est désigné Créature
+. Les autres joueurs sont des Traqués
+
+| Post-conditions
+a|. Chaque Traqué possède un exemplaire de chacune des cartes Lieu numérotées de 1 à 5, ainsi que 3 pions Volonté et 1 carte Survie
+. La créature possède 3 pions Traque et 3 cartes Traque
+. Le plateau est initialisé avec les pions Secours et Assimilation placés respectivement sur la bonne case en fonction du nombre de joueurs.
+. Les pioches sont mélangés
+. La réserve contient le bon nombre d'exemplaires de chaque carte Lieu numérotée de 6 à 10 en fonction du nombre de joueurs.
+. La planète est mise en place.
+
+
+|Main success scenario
+a|
+. Maître du jeu met en place le plateau
+. Maître du jeu met en place la planète
+. Maître du jeu prépare les pioches
+. Les Traqués préparent leur main
+. La Créature prépare sa main
+
+| Extensions
+a|
+
+
+| Variations
+a| . Plateau peut être mis en place de 2 manières différents
+|Superordinate Use Case | None
+|Subordinate Use Cases | optional, depending on tools, links to sub.use cases
+|Performance Target
+|the amount of time this use case should take
+
+|Open Issues
+a|
+
+
+|Schedule |
+|Constraints |
+|Annexes
+|
+|===
+
+---
\ No newline at end of file
diff --git a/not-alone-doc/src/doc/asciidoc/_sections/use-cases/use-cases.adoc b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/use-cases.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..4aa740ffbd7e4b863501c75709714a0cba1aba40
--- /dev/null
+++ b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/use-cases.adoc
@@ -0,0 +1,25 @@
+== Use Cases
+
+
+[plantuml, uc-not-alone, png]
+....
+left to right direction
+skinparam packageStyle rectangle
+actor Client_Application
+entity Bob
+rectangle "Not Alone" {
+ Client_Application -- (Deroulement)
+ Client_Application -- (Discovery)
+ Bob -- (Mise en place)
+}
+....
+
+=== Mise en place
+
+include::mise-en-place.adoc[]
+
+=== Déroulement
+
+include::deroulement.adoc[]
+
+
diff --git a/not-alone-doc/src/doc/asciidoc/synthese.adoc b/not-alone-doc/src/doc/asciidoc/synthese.adoc
new file mode 100644
index 0000000000000000000000000000000000000000..33c07801b490742038c2f922bfd9ca671dbf5828
--- /dev/null
+++ b/not-alone-doc/src/doc/asciidoc/synthese.adoc
@@ -0,0 +1,766 @@
+= Synthèse des règles
+
+== Cartes lieu
+
+Fonctionnement:: Chaque carte Lieu possède un n°, un nom et un pouvoir pouvant être activé par les Traqués.
+
+Adjacence:: Deux cartes Lieu sont adjacentes si elles ont un bord en commun, horizontal ou vertical.
+
+Lieux multiples:: Quand un jeton est placé sur 2 Lieux adjacents, le placer à cheval sur ces 2 Lieux.
+
+Copier le pouvoir d'un Lieu:: Pour utiliser cet effet, un Traqué doit pouvoir utiliser le pouvoir de la carte Lieu qu’il a initialement jouée en Phase 1 :
+
+- cet effet permet à ce Traqué d’utiliser un Lieu révélé sans jouer la carte associée, même si ce lieu est inutilisable ou inaccessible pour lui,
+
+- tout jeton Traque sur le Lieu copié est sans effet sur ce Traqué.
+
+Lieu inaccessible:: Un Lieu non révélé est inaccessible pour les Traqués.
+Les jetons Traque peuvent être placés ou déplacés sur un Lieu inaccessible.
+
+Lieu inutilisable:: Lorsqu'un Lieu est inutilisable, son pourovir peut être copié grâce au pouvoir d’une carte Lieu ou d’une carte Survie.
+
+.Liste des cartes lieu
+[cols="10,30,60",options="header"]
+|===
+
+| N°
+| Nom
+| Pouvoir
+
+| 1
+| L'Antre
+a| Au choix :
+
+- reprenez en main les cartes Lieu de votre défausse (mais pas celui-ci),
+- copiez le pouvoir d'un Lieu où le jeton Créature se trouve,
+
+Perdez 1 Volonté supplémentaire si le jeton Créature vous attrape.
+
+| 2
+| La Jungle
+| Reprenez en main cette carte Lieu et 1 carte Lieu de votre défausse.
+
+| 3
+| La Rivière
+| Au prochain tour, jouez 2 cartes Lieu.
+
+Avant de révéler, choisissez-en une et reprenez l'autre en main.
+
+| 4
+| La Plage
+a| Au choix, 1 fois par tour :
+
+- placez le pion Balise sur la Plage,
+
+- retirez le pion Balise de la Plage pour avancer le pion Secours d’une case (max 1x/tour).
+
+Si plusieurs Traqués explorent la Plage, l’un d’eux peut utiliser le pouvoir de la Plage et les autres peuvent récupérer 1 carte Lieu de leur défausse.
+
+Le pouvoir de la Plage est cumulable avec celui de l’Épave.
+
+| 5
+| Le Rover
+| Prenez de la réserve une carte Lieu que vous ne possédez pas et ajoutez-le à votre main.
+
+
+| 6
+| Le Marais
+a| Reprenez en main cette carte Lieu et 2 cartes Lieu de votre défausse.
+
+.Précision:
+- Si le Marais est révélé grâce au Labyrinthe et que vous l’activez directement, ni le Marais ni le Labyrinthe ne sont repris en main.
+
+| 7
+| L'Abri
+| Piochez 2 carte Survie, gardez-en une et défaussez l'autre.
+
+| 8
+| L'Épave
+| Avancez le pion Secours d'1 case (1 fois par tour, quel que soit le nombre de Traqués explorant l’Épave).
+
+Si plusieurs Traqués explorent l’Épave, l’un d’eux peut utiliser le pouvoir de l’Épave et les autres peuvent récupérer 1 carte Lieu de leur défausse.
+
+Le pouvoir de l’Épave est cumulable avec celui de la Plage.
+
+| 9
+| La Source
+a| Au choix :
+
+- le Traqué de votre choix (vous ou un autre joueur) récupère 1 Volonté,
+- piochez 1 carte Survie.
+
+| 10
+| L'Artefact
+a| Le pouvoir de l'Artefact varie selon la couleur choisie pour la partie.
+
+L’Artefact ne peut être copié (que ce soit par le pouvoir d'un Lieu ou une carte Survie).
+
+.Bleu
+Au prochain tour, jouez 2 cartes Lieu.
+
+Résolvez les deux Lieu individuellement dans l’ordre de votre choix en respectant les règles de la Phase 3.
+
+Lorsqu’un Traqué révèle ses cartes Lieu, s’il peut appliquer les effets de la Rivière et de l’Artefact bleu durant
+un même tour, il doit choisir l’un des deux effets, puis il peut reprendre une carte Lieu de sa défausse.
+
+.Rouge
+Copiez les effets d'1 carte Lieu de votre défausse.
+
+.Vert
+Défaussez 1 carte Lieu et déplacez 1 Traqué de votre choix sur un Lieu adjacent.
+
+.Jaune
+Au choix :
+
+- annulez les effets du jeton Artemia,
+- récupérez 2 cartes Lieu de votre défausse.
+
+|===
+
+
+
+
+== Cartes traque
+
+Fonctionnement::
+Chaque carte Traque possède un nom, une Phase où elle peut être joéue et un effet pouvant être activé par la Créature.
+Certaines cartes Traque possèdent également le symbole Cible ou Artemia.
+Une carte Traque se joue à tout moment de la phase indiquée sur la carte et est ensuite défaussée.
+
+Précision::
+Quand l'effet d'une carte Traque qui indique "Dès que les cartes Lieu sont révélées à la Phase 3" : il est appliqué dès que chaque Traqué a dévoilé sa carte Lieu, avant la résolution des cartes Lieu.
+
+Symbole Cible::
+Lorsqu'une carte Traque avec le symbole Cible est jouée, la Créature pose le jeton Cible sur une des dix cartes Lieu d'Artemia.
+Si la Créature joue 2 cartes Traque avec ce symbole au cours d’un même tour, leurs effets sont cumulés sur le Lieu ciblé.
+
+Symbole Artemia::
+Lorsqu'une carte Traque avec le symbole Artemia est jouée, la Créature pose le jeton Artemia sur une des dix cartes Lieu d'Artemia.
+Si la Créature joue 2 cartes Traque avec ce symbole au cours d’un même tour, leurs effets sont cumulés.
+
+.Liste des cartes traque
+[cols="30,10,60",options="header"]
+|===
+| Nom
+| Phase
+| Effet
+
+| Acharnement
+| 2
+| Le jeton Créature fait perdre 1 Volonté supplémentaire.
+
+| Angoisse
+| 1 - Artémia
+| Les traqués ne peuvent pas Résister.
+
+| Anticipation
+| 2
+| Désigner 1 Traqué : si vous l’attrapez avec le jeton Créature, avancez le jeton Assimilation d’1 case supplémentaire.
+
+| Cataclysme
+| 3
+| Le pouvoir du Lieu de votre choix est inutilisable.
+
+| Champ de force
+| 1 - Cible
+| Avant que les Traqués ne jouent, ciblez 2 Lieux adjacents : ces Lieux sont inaccessibles pour ce tour.
+
+| Clone
+| 2 - Cible
+| Considérez le jeton Cible comme un second jeton Créature.
+
+| Déploiement
+| 3
+| Dès que les cartes Lieu sont révélées en Phase 3, reculer le pion Assimilation d'1 case
+pour déplacer le jeton Créature sur un Lieu adjacent.
+
+| Désespoir
+| 1 - Artemia
+| Aucune carte Survie ne peut être jouée ou piochée pour le reste du tour.
+
+| Détour
+| 3
+| Avant de résoudre les Lieux, déplacer 1 Traqué vers 1 Lieu adjacent.
+
+| Domination
+| 2
+|Poser cette carte devant 1 Traqué : à la fin de chaque tour, celui-ci doit défausser 1 carte Lieu de sa
+main.
+
+Si ce Traqué tombe à 0 Volonté, défausser cette carte.
+
+| Effroi
+| 1
+| Obligez un Traqué qui utilise l'action Résister à Lâcher prise.
+
+| Emprise
+| 2
+| Cibler 1 Traqué : il défausse toutes ses cartes Lieu sauf 2.
+
+| Épidémie
+| 2
+a| Désignez 1 Traqué :
+
+- le Lieu où il se trouve est inutilisable,
+- chaque autre Traqué présent sur ce Lieu perd 1 Volonté.
+
+| Faille temporelle
+| 2 - Cible
+| Pour chaque Traqué présent sur le Lieu ciblé, avancer le pion Assimilation d'autant de cases, puis le pion Secours d'autant de cases.
+
+| Flashback
+| Spécial
+| À jouer à la phase de la carte copiée : copier la dernière carte Traque défaussée.
+
+| Gargantua
+| 2
+| Placer le jeton Créature sur 2 Lieux adjacents : ses effets s'appliquent sur ces 2 Lieux.
+Si un Traqué copie le pouvoir du Lieu où se trouve le jeton Créature, il copie 1 seul des 2 Lieux.
+
+| Harcèlement
+| 2
+| Chaque Traqué ne peut récupérer qu'1 carte Lieu quand il utilise le pouvoir d'un Lieu.
+
+| Hurlements
+| 2 - Cible
+| Chaque Traqué présent sur le Lieu ciblé doit, selon son choix, défausser 2 cartes Lieu ou perdre 1 Volonté.
+
+| Inertie
+| 2 - Cible
+| Dès que les cartes Lieu sont révélées à la Phase 3, si au moins 1 Traqué se trouve sur le Lieu ciblé :
+les pouvoirs de tous les Lieux sont inutilisables, les effets des jetons Créature et Artemia sont quand même résolus.
+
+| Interférences
+| 2
+a| Au choix:
+
+- les pouvoirs de la Plage et de l’Épave sont inutilisables,
+- reculer le pion Bouclier d'1 Lieu.
+
+| Intuition
+| 1
+a|
+. Piocher 3 cartes Traque,
+. Jouer 1 de ces cartes durant le tour et défausser les 2 autres.
+
+| Magnétisme
+| 2 - Cible
+| Dès que les cartes Lieu sont révélées en Phase 3, chaque Traqué adjacent au Lieu ciblé est déplacé sur le Lieu ciblé.
+
+| Mirage
+| 2 - Cible
+| Ciblez 2 Lieux adjacents (placer le jeton Cible entre ces 2 Lieux) : leur pouvoir est inutilisable.
+
+| Mutation
+| 2 - Artemia
+| En plus de ses effets, le jeton Artemia fait perdre 1 Volonté.
+
+| Psychose
+| 2 - Artemia
+| Désigner 1 Traqué : il vous montre toutes les cartes Lieu de sa main sauf 2.
+
+| Réminiscence
+| 2 - Artemia
+| Reprendre 1 carte Traque de la défausse.
+
+| Repérage
+| 4
+| Au prochain tour, vous pouvez jouer jusqu’à 2 cartes Traque.
+
+| Sables mouvants
+| 2 - Cible
+| Chaque Traqué présent sur le Lieu ciblé choisit et défausse toutes les cartes Lieu de sa main sauf 2.
+
+| Soif de sang
+| 2 - Cible
+a|
+. Chaque Traqué présent sur le Lieu ciblé récupère 1 Volonté, si possible,
+. Chaque Traqué présent sur un Lieu adjacent au Lieu ciblé perd 1 Volonté.
+
+| Stase
+| 4
+| Le pion Secours n'avance pas lors de cette Phase.
+
+| Télépathie
+| 2 - Artemia
+a|
+. Désigner 1 Lieu,
+. Choisir 1 Traqué, tirer au hasard 1 carte de sa main et la défausser,
+. Si la carte correspond au Lieu désigné : avancer le pion Assimilation d'1 case.
+
+| Tornade
+| 2 - Artemia
+| Dès que les cartes Lieu sont révélées à la Phase 3, vous pouvez déplacer le jeton Artemia sur un Lieu adjacent.
+
+| Toxine
+| 2 - Cible
+| Chaque Traqué sur le Lieu ciblé défausse 1 carte Survie.
+
+Le pouvoir de ce lieu est inutilisable.
+
+| Ubiquité
+| 2 - Artemia + Cible
+| Dès que les cartes Lieu sont révélées à la Phase 3, vous pouvez permuter les jetons Traque.
+
+Si un jeton Traque se trouve sur 2 Lieux adjacents, le jeton qui le remplace est placé sur ces 2 Lieux adjacents.
+
+| Virus
+| 2 - Artemia
+| Ciblez 2 Lieux adjacents : les effets du jeton Artemia s'appliquent sur ces 2 Lieux.
+
+| Zone interdite
+| 2
+| Tous les Traqués défaussent simultanément 1 carte Lieu de leur choix.
+
+|===
+
+== Cartes survie
+
+Fonctionnement::
+Chaque carte Survie possède un nom, une Phase où elle peut être joéue et un effet pouvant être activé par le Traqué qui la détient.
+Une carte Survie se joue à tout moment de la phase indiquée sur la carte et est ensuite défaussée.
+
+.Liste des cartes survie
+[cols="30,10,60"]
+|===
+| Nom | Phase | Effet
+
+| Adrénaline
+| 1
+| Récupérez 1 Volonté.
+
+| Alerte
+| 3
+a| Désigner 1 Lieu :
+
+- les jetons Traque présents sur ce Lieu sont sans effet,
+- le pouvoir de ce Lieu est inutilisable.
+
+| Amplificateur
+| 4
+a| Au choix:
+
+- retirez le jeton Balise de la Plage pour avancer le pion Secours d’1 case,
+- avancez le pion Bouclier d'1 Lieu vers le Dôme.
+
+| Brouillage
+| 1
+| Tous les Traqués cachent les cartes Lieu de leur défausse jusqu’à la fin du tour
+
+| Cavale
+| 1
+a|
+. Jouez 3 cartes Lieu,
+. En Phase 3 : révélez celle de votre choix,
+. En Phase 4 : reprenez en main la carte révélée et défaussez les 2 autres.
+
+| Détecteur
+| 3
+| Évitez les effets du jeton Artemia.
+
+| Drone
+| 3
+| À la place d'utiliser le pouvoir de votre carte Lieu,
+prenez de la réserve 1 carte d'un Lieu révélé que vous ne possédez pas et
+ajoutez-la à votre main.
+
+| Entrave
+| 1
+| Le jeton Créature ne peut pas être posé sur les Lieux 6 à 10.
+
+| Équipement
+| 4
+a| Au choix :
+
+- piochez 1 carte Survie,
+- prenez la carte Survie du dessus de la défausse.
+
+| Esquive
+| 3
+| Évitez les effets du jeton Créature.
+
+| Fausse piste
+| 3
+| Déplacez le jeton Créature sur un Lieu adjacent.
+
+| Hologramme
+| 3
+| Déplacez le jeton Artemia sur un Lieu adjacent.
+
+| Leurre
+| 3
+a|
+. Permutez 2 jetons Traque,
+. Reprenez 1 carte Lieu de votre défausse.
+
+| Mimétisme
+| 1
+| En Phase 3, si vous êtes sur le même Lieu que le jeton Créature : avancez le pion Secours d'1 case,
+vous ne subissez pas les effets du jeton Créature.
+
+| Navette
+| 4
+| Jouer cette carte quand le pion Secours se trouve à 1 case de la case Victoire :
+les Traqués reportent la partie.
+
+| Planques
+| 4
+| Piocher 2 cartes Survie et les placer face cachée chacune sous 1 Lieu d'Artemia :
+si un Traqué explore un de ces Lieux et peut utiliser son pouvoir,
+il peut également récupérer la carte Survie qui s'y trouve.
+
+| Portail
+| 3
+| À la place d'utiliser le pouvoir de votre carte Lieu, copiez le pouvoir d’1
+Lieu adjacent.
+
+| Ralliement
+| 4
+| Chaque Traqué attrapé par le jeton Créature peut reprendre en main la carte Lieu sur laquelle il s'est fait attraper.
+
+| Refuge
+| 1
+| Poser le jeton Cible sur 2 Lieux adjacents : le jeton Créature ne peut être posé sur
+ces Lieux Aucune carte Traque avec le symbole Cible ne peut être jouée.
+
+| Régénération
+| 3
+| À la place d'utiliser le pouvoir de votre carte Lieu,
+copiez le pouvoir d’1 carte Lieu de votre défausse.
+
+| Résistance
+| 3
+| Évitez les effets du jeton Cible.
+
+| Retraite
+| 3
+| Déplacez 1 Traqué de votre choix sur un Lieu adjacent, le Lieu de destination n'est pas résolu.
+
+| Riposte
+| 1
+| Tirer 2 cartes Traque au hasard de la main de la Créature et placez-lez sous la pioche Traque.
+
+| Sacrifice
+| 1
+| Défaussez 1 carte Lieu : aucune carte Traque ne peut être jouée ce tour-ci.
+
+| Second souffle
+| 1
+| Si vous avez au plus 1 carte Lieu en main : récupérez toutes les cartes Lieu de votre défausse.
+
+| Sixième sens
+| 1
+| Reprenez en main 2 carte Lieu de votre défausse.
+
+| Système D
+| 1
+a| Au choix:
+
+- placez le pion Balise sur la Plage,
+- avancez le pion Bouclier d'1 Lieu vers le Dôme.
+
+| Ténacité
+| 1
+| Récupérez 1 carte Lieu supplémentaire pour chaque Volonté dépensée dans l'action Résister.
+
+| Vaccin
+| 1
+| Reculer le pion Assimilation d'1 case.
+
+| Volte-face
+| 4
+| Reprenez en main votre carte Lieu jouée.
+
+| Vortex
+| 2
+| Échangez votre carte Lieu jouée contre 1 carte Lieu de votre défausse.
+
+|===
+
+== Mise en place
+
+.Nombre cartes lieu
+[cols="60h,10,10,10"]
+|===
+| Nombre de Traqués | 1 | 2-3 | 4-6
+| Nombre de Cartes Lieu 6 à 10 | 1 | 2 | 3
+|===
+
+.Mise en place
+[cols="30h,40"]
+|===
+| Action | Description
+
+| Choix
+a|
+. Choisir un mode de difficulté : normal ou expert.
+. Choisir si l'extension Exploration est utilisée.
+. Choisir si la variante Labyrinthe est utilisée (l'extension Exploration est obligatoire dans ce cas).
+. Choisir quel joueur incarne la Créature, les autres joueurs étant les Traqués.
+
+| Créer la planète Artemia
+a|
+. Placer 1 exemplaire des 10 cartes Lieu devant la créature en 2 rangées de chacune 5 cartes, par ordre croissant,
+. Placer le pion Balise à côté de la carte Plage.
+
+| Extension Exploration
+a| Choisir les 10 Lieux qui formeront la planète Artemia en s'assurant que chaque n° de 1 à 10 n’apparaisse qu’une seule fois.
+Les Lieux suivants requièrent une mise en place spécifique :
+
+Le Dôme:: Le pion Balise devient le pion Bouclier : le Placer sur la carte Lieu 1 de la planète Artemia.
+
+Le Labyrinthe::
+. Mélanger les cinq cartes Lieu 6 à 10 qui forment la planète Artemia,
+. Placer aléatoirement face cachée ces 5 cartes sous la rangée des cartes Lieu 1 à 5.
+
+Le Pôle:: La carte Pôle n’existe qu’en 2 exemplaires : la première carte sert à former la planète Artemia et la seconde est placée dans la réserve Lieux, indépendamment du nombre de Traqués.
+
+| Pioche Traque
+| Mélanger et placer face cachée les cartes Traque à proximité de la Créature.
+
+| Pioche Survie
+| Mélanger et placer face cachée les cartes Survie à proximité des Traqués.
+
+| La Créature:
+a|
+- place le plateau au centre de la table sur la face de son choix,
+- place le pion Secours et le pion Assimilation sur le chiffre de leur piste respective correspondant au nombre de joueurs,
+- pioche 3 cartes Traque et prend les 3 jetons Traque (Créature, Cible et Artemia).
+
+| Chaque Traqué:
+a|
+- prend 3 pions Volonté, les pions Volonté restants sont retirés du jeu,
+- prend un set de 5 cartes Lieu numérotées de 1 à 5, les cartes inutilisées sont retirées du jeu,
+- pioche 1 carte Survie.
+
+| Réserve
+| Former la réserve Lieux avec les cartes Lieu numérotées de 6 à 10.
+
+Placer près du plateau le nombre d’exemplaires de chaque carte Lieu correspondant au nombre de Traqués (voir le tableau "Traqués"), face visible, les cartes inutilisées sont retirées du jeu.
+
+|===
+
+== Conditions de victoire
+
+La Créature remporte immédiatement la partie si le pion Assimilation atteint la case Victoire.
+
+Les Traqués remportent immédiatement la partie si le pion Secours atteint la case Victoire.
+
+== Déroulement d'une partie
+
+.Règles générales
+[cols="30h,70"]
+|===
+| Fonctionnement
+| La partie est une succession de tours de jeu.
+
+| Règle d'or
+| Tout effet ou pouvoir qui contredit la règle prévaut sur elle.
+
+| Informations
+| Les cartes Lieu défaussées par les Traqués sont visibles de tous.
+
+Le nombre de cartes en possession de chacun et leur type (leur dos) est connu de tous, mais il est interdit de montrer ses cartes aux autres joueurs.
+
+Les Traqués peuvent communiquer et bluffer, mais uniquement à voix haute.
+
+| Cartes en main
+| Le nombre de cartes Survie qu’un Traqué peut détenir n’est pas limité.
+
+| Durée des effets
+| Les effets des cartes Traque et des cartes Survie sont limités au tour de jeu en cours.
+
+Les effets d'une carte Survie ciblent uniquement leur propriétaire, sauf indication contraire.
+
+| Ordre de résolution des cartes
+| Les effets des cartes Traque et des cartes Survie jouées lors d’une même phase sont résolus dans l’ordre dans lequel les cartes ont été jouées.
+
+En cas de conflit, la Créature décide de l’ordre de résolution.
+
+| Pions Volonté
+| Un Traqué ne peut jamais avoir plus de 3 pions Volonté en sa possession.
+
+Tout effet qui ferait perdre plus que les pions Volonté restants à un Traqué se limite à lui faire perdre les pions Volonté restants.
+
+| Pioche Survie
+| Si, au moment de piocher, la pile des cartes Survie est vide :
+mélanger les cartes Survie défaussées pour former une nouvelle pioche.
+
+|===
+
+.Tour de jeu
+[cols="30h,70"]
+|===
+| Fonctionnement
+| Résoudre les Phases suivantes dans l'ordre.
+
+| Créature
+| Par défaut, la Créature ne peut jouer qu’1 carte Traque par tour.
+
+| Traqués
+| Chaque Traqué ne peut jouer qu’1 carte Survie par tour, et ce, même s’il est attrapé par la Créature.
+
+| Phase 1 : Exploration
+| Les Traqués jouent simultanément et obligatoirement 1 carte Lieu de leur main en la posant face cachée devant eux.
+
+| Actions optionnelles
+| Avant de jouer une carte Lieu, chaque Traqué peut Résister ou Lâcher prise.
+
+| Résister
+a| Lorsqu'un Traqué Résiste, il choisit 1 des cas suivants :
+
+- perdre 1 pion Volonté pour choisir et reprendre en main 2 cartes Lieu de sa défausse,
+- perdre 2 pions Volonté pour choisir et reprendre en main 4 cartes Lieu de sa défausse.
+
+Si par cette action un Traqué perd son dernier pion Volonté, il doit résoudre Lâcher prise.
+
+| Lâcher prise
+a|
+. Récupérer ses 3 pions Volonté et reprendre en main toutes ses cartes Lieu défaussées,
+. Avancer le pion Assimilation d'1 case.
+
+| Phase 2 : Traque
+a| La Créature pose sur les cartes Lieu d'Artemia de son choix :
+
+- le jeton Créature,
+- le jeton Cible si le symbole se trouve sur une carte Traque jouée,
+- le jeton Artemia si le symbole se trouve sur une carte Traque jouée ou sur une case située sous le pion Secours.
+
+| Précision
+| Plusieurs jetons Traque peuvent être posés sur un même Lieu pour en cumuler leurs effets.
+
+| Phase 3 : Résolution
+| Résoudre les étapes suivantes dans l'ordre :
+
+| 1) Choix des Traqués
+| Les Traqués qui ont le choix parmi plusieurs cartes Lieu décident secrètement du Lieu qu’ils vont explorer.
+
+| 2) Révélation
+| Les Traqués dévoilent simultanément leur carte Lieu.
+
+| 3) Lieux sans jeton Traque
+a| Résoudre les Lieux sans jeton Traque, en sens horaire depuis le joueur à gauche de la Créature. Le Traqué peut au choix, si le Lieu n'est pas inutilisable :
+
+- utiliser le pouvoir du Lieu,
+- reprendre en main 1 carte Lieu au choix de sa défausse.
+
+| 4) Lieu avec jeton Cible
+a| Résoudre le Lieu avec le jeton Cible, en sens horaire depuis le joueur à gauche de la Créature :
+
+A) Chaque Traqué présent sur ce Lieu subit l’effet de la carte Traque,
+
+B) Chaque Traqué présent sur ce Lieu peut au choix, si le Lieu n'est pas inutilisable :
+
+- utiliser le pouvoir du Lieu,
+- reprendre en main 1 carte Lieu au choix de sa défausse.
+
+| 5) Lieu avec jeton Artemia
+a| Résoudre le Lieu avec le jeton Artemia, en sens horaire depuis le joueur à gauche de la Créature :
+
+A) Chaque Traqué présent sur ce Lieu choisit et défausse 1 carte Lieu de sa main,
+
+B) Le pouvoir du Lieu est inutilisable et le Traqué ne peut pas reprendre de carte Lieu de sa défausse.
+
+| 6) Lieu avec jeton Créature
+a| Résoudre le Lieu avec le jeton Créature, en sens horaire depuis le joueur à gauche de la Créature :
+
+A) Le pouvoir du Lieu est inutilisable et le Traqué ne peut pas reprendre de carte Lieu de sa défausse,
+
+B) Avancer immédiatement le pion Assimilation d'1 case,
+
+C) Chaque Traqué présent sur ce Lieu est attrapé par la Créature et perd 1 pion Volonté,
+
+D) Si au moins 1 Traqué perd son dernier pion Volonté : avancer le pion Assimilation d'1 case.
+
+| 7) Récupération
+a| Pour chaque Traqué ayant perdu ses 3 pions Volonté, en fonction du mode de difficulté.
+
+Mode normal:: Il reprend en main toutes les cartes Lieu de sa défausse ainsi que ses 3 pions Volonté.
+
+Mode expert:: Il reprend en main toutes les cartes Lieu de sa défausse ainsi que 2 pions Volonté (le pion restant peut être récupéré par tout autre moyen).
+
+| Phase 4 : Maintenance
+a|
+A) Chaque Traqué défausse sa carte Lieu jouée, face visible de façon à ce que le n° de chacune de ses cartes Lieu défaussées soit visible,
+
+B) La Créature reprend ses jetons Traque et pioche des cartes Traque jusqu’à en avoir 3 en main,
+
+C) Avancer le pion Secours d'1 case, un nouveau tour de jeu commence.
+|===
+
+== Extension Exploration
+
+.Liste des cartes lieu (exploration)
+[cols="10,20,70"]
+|===
+| N° | Nom | Effet
+
+| 1
+| Le Nexus
+a|
+. Copiez le pouvoir d'1 Lieu 2à 5.
+. Avancez le pion Assimilation d'1 case supplémentaire si le jeton Créature attrape au moins 1 Traqué sur le Nexus.
+
+| 2
+| L'Oasis
+| Reprenez en main cette carte Lieu plus 1 carte Lieu de votre défausse par Volonté qu'il vous manque, si possible.
+
+| 3
+| Le Fjord
+a| Lors du prochain tour :
+
+. En Phase 1 : vous pouvez jouer une 2ème carte Lieu, face visible, de votre défausse, s'il n'y en a,
+. En Phase 3 : résolvez 1 de ces Lieux,
+. En Phase 4 : défaussez ces 2 cartes Lieu.
+
+| 4
+| Le Dôme
+a|
+. Déplacez le Bouclier d'1 Lieu vers le Dôme.
+. Si le pion Boucler atteint le Dôme : reculer le pion Assimilation d'1 case et replacer le pion Bouclier sur le Lieu 1 (max 1x/tour).
+
+| 5
+| Le Labyrinthe
+a| Au choix :
+
+- révéler un Lieu : retourner, face visible, une des 5 cartes Lieu 6 à 10 de la planète Artemia et activer son pouvoir ou prendre 1 carte Lieu correspondante,
+- prendre de la réserve 1 carte Lieu déjà révélé.
+
+| 6
+| La Mangrove
+a|
+. Échanger les cartes Lieu de sa main contre celles de sa défausse,
+. Reprendre cette carte Lieu en main.
+
+Précision:: Si la Mangrove est révélée grâce au Labyrinthe et que vous l’activez directement,
+ni la Mangrove ni le Labyrinthe ne sont repris en main.
+
+| 7
+| L'Archipel
+a|
+. Piocher 1 carte Survie,
+. S'il vous reste moins de 3 cartes Lieu en main, le Traqué de votre choix récupère 1 Volonté.
+
+| 8
+| Le Pôle
+a|
+. Sacrifiez 1 Volonté (même si c'est le dernier), puis avancez le pion Secours de 2 cases,
+. En Phase 4, replacer le pôle dans la réserve, qu’elle ait pu être activée ou non,
+
+Le Pôle ne peut être copié (que ce soit par le pouvoir d'un Lieu ou une carte Survie).
+
+| 9
+| Les Fungi
+a| Au choix :
+
+- piocher 1 carte Survie,
+- placer jusqu’à 2 pions Volonté (si possible) sur des cases libres différentes de la piste Secours, ce pouvoir est inutilisable si la réserve de pions Volonté est vide ou s’il n’y a plus de case libre pour placer un pion Volonté. Quand le pion Secours atteint une de ces cases : les Traqués décident ensemble qui récupère le pion Volonté. Si un Traqué doit récupérer au moins 1 Volonté alors que la réserve est vide, il prend les pions Volonté disponibles de son choix sur la piste Secours.
+
+| 10
+| Le Portail
+a|
+. Défausser le Portail pour jouer une autre carte Lieu de sa main et la résoudre.
+Le Portail téléporte le Traqué sur le second lieu joué, ce Traqué est donc susceptible de s’y faire attraper par un jeton Traque et/ou d’y être la cible d’une carte Traque,
+. Le Portail est défaussé en phase 3 et la seconde carte Lieu en phase 4.
+|===
+
diff --git a/not-alone-player/.gitignore b/not-alone-player/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..baaba59f84e372e88b9b329c75e4acbf7d097457
--- /dev/null
+++ b/not-alone-player/.gitignore
@@ -0,0 +1,4 @@
+node_modules/
+node/
+dist/
+src/codegen/
\ No newline at end of file
diff --git a/not-alone-player/package-lock.json b/not-alone-player/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..864d98c5957b41161a5273dcf7a6e175d30c8825
--- /dev/null
+++ b/not-alone-player/package-lock.json
@@ -0,0 +1,3269 @@
+{
+ "name": "not-alone-player",
+ "version": "0.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "version": "0.0.0",
+ "dependencies": {
+ "@creditkarma/thrift-client": "^0.16.1",
+ "@creditkarma/thrift-server-core": "^0.16.1",
+ "@creditkarma/thrift-server-express": "^0.16.1"
+ },
+ "devDependencies": {
+ "@creditkarma/thrift-parser": "^1.2.0",
+ "@creditkarma/thrift-typescript": "^3.7.6",
+ "@types/thrift": "^0.10.10",
+ "codelyzer": "^6.0.1",
+ "tslint": "^6.1.3"
+ }
+ },
+ "node_modules/@angular/compiler": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz",
+ "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==",
+ "dev": true,
+ "peerDependencies": {
+ "tslib": "^1.10.0"
+ }
+ },
+ "node_modules/@angular/core": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz",
+ "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==",
+ "dev": true,
+ "peerDependencies": {
+ "rxjs": "^6.5.3",
+ "tslib": "^1.10.0",
+ "zone.js": "~0.10.2"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "dev": true
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "node_modules/@creditkarma/thrift-client": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-client/-/thrift-client-0.16.1.tgz",
+ "integrity": "sha512-oTlz6dNGj0nQjPyTB+eLwMDE2DAsbsfgz4xmPt7yf8tMd4lazFY7eVzEK0slh6zj9KYD/wuS21wz3Bmofp3pQw==",
+ "dependencies": {
+ "@types/generic-pool": "^3.1.4",
+ "@types/request": "^2.48.1",
+ "generic-pool": "^3.4.2",
+ "request": "^2.88.0"
+ },
+ "peerDependencies": {
+ "@creditkarma/thrift-server-core": "0.16.x"
+ }
+ },
+ "node_modules/@creditkarma/thrift-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-parser/-/thrift-parser-1.2.0.tgz",
+ "integrity": "sha512-mSRxjSXvU6sBfWhMBWXl7H/XEKWHQ7x+MUDLwyeFIwwX9UaZKPOc7TgGd0N78kcZtIMk82ArdxO6aFhqnBuNtg==",
+ "dev": true,
+ "bin": {
+ "thrift-parser": "dist/main/bin/index.js"
+ }
+ },
+ "node_modules/@creditkarma/thrift-server-core": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-core/-/thrift-server-core-0.16.1.tgz",
+ "integrity": "sha512-rbzmS46vH6oth1I7zcSLcTslRlzolAiD9TSCNoxZHdnwfM65QJQIVCJ8Tz3l/78fzZAiZ71+9wZAuf61jl0Wzg==",
+ "dependencies": {
+ "@types/lodash": "^4.14.136",
+ "lodash": "^4.17.15"
+ }
+ },
+ "node_modules/@creditkarma/thrift-server-express": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-express/-/thrift-server-express-0.16.1.tgz",
+ "integrity": "sha512-XPUPRnnJkGbLCZZMwLRSNGMZgxlC0n1LYIW2CXuH24aZIcTd9hQP09xc1khs5STMZii6q79wWx2hg6H/oZDDYA==",
+ "dependencies": {
+ "zipkin": "^0.15.0"
+ },
+ "peerDependencies": {
+ "@creditkarma/thrift-server-core": "0.16.x",
+ "@types/express": ">=4.0.0 <5.0.0",
+ "express": ">=4.0.0 <5.0.0"
+ }
+ },
+ "node_modules/@creditkarma/thrift-typescript": {
+ "version": "3.7.6",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-typescript/-/thrift-typescript-3.7.6.tgz",
+ "integrity": "sha512-v/9Bi3YqExw8bOHA1F/087zru14qExO1e4rdV/+hjYOnUk0HX3zmi6giu/QR9c9QK+5bxekZd4pUxgX7HWwvwQ==",
+ "dev": true,
+ "dependencies": {
+ "@creditkarma/thrift-parser": "^1.2.0",
+ "@types/fs-extra": "^7.0.0",
+ "fs-extra": "^8.0.1",
+ "glob": "^7.1.2",
+ "typescript": "3.5.x"
+ },
+ "bin": {
+ "thrift-typescript": "dist/main/bin/index.js"
+ }
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+ "peer": true,
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/caseless": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
+ "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.33",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
+ "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
+ "peer": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.9",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.9.tgz",
+ "integrity": "sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw==",
+ "peer": true,
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "*",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.17.14",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.14.tgz",
+ "integrity": "sha512-uFTLwu94TfUFMToXNgRZikwPuZdOtDgs3syBtAIr/OXorL1kJqUJT9qCLnRZ5KBOWfZQikQ2xKgR2tnDj1OgDA==",
+ "peer": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*"
+ }
+ },
+ "node_modules/@types/fs-extra": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-7.0.0.tgz",
+ "integrity": "sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/generic-pool": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/@types/generic-pool/-/generic-pool-3.1.9.tgz",
+ "integrity": "sha512-IkXMs8fhV6+E4J8EWv8iL7mLvApcLLQUH4m1Rex3KCPRqT+Xya0DDHIeGAokk/6VXe9zg8oTWyr+FGyeuimEYQ==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/lodash": {
+ "version": "4.14.165",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz",
+ "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg=="
+ },
+ "node_modules/@types/mime": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
+ "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
+ "peer": true
+ },
+ "node_modules/@types/node": {
+ "version": "14.14.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
+ "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ=="
+ },
+ "node_modules/@types/node-int64": {
+ "version": "0.4.29",
+ "resolved": "https://registry.npmjs.org/@types/node-int64/-/node-int64-0.4.29.tgz",
+ "integrity": "sha512-rHXvenLTj/CcsmNAebaBOhxQ2MqEGl3yXZZcZ21XYR+gzGTTcpOy2N4IxpvTCz48loyQNatHvfn6GhIbbZ1R3Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/q": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
+ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+ "dev": true
+ },
+ "node_modules/@types/qs": {
+ "version": "6.9.5",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz",
+ "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==",
+ "peer": true
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
+ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
+ "peer": true
+ },
+ "node_modules/@types/request": {
+ "version": "2.48.5",
+ "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz",
+ "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==",
+ "dependencies": {
+ "@types/caseless": "*",
+ "@types/node": "*",
+ "@types/tough-cookie": "*",
+ "form-data": "^2.5.0"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.13.8",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
+ "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==",
+ "peer": true,
+ "dependencies": {
+ "@types/mime": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/thrift": {
+ "version": "0.10.10",
+ "resolved": "https://registry.npmjs.org/@types/thrift/-/thrift-0.10.10.tgz",
+ "integrity": "sha512-sEhRbmmQgiTn+JdophEPiuTFkc9QRl7R/Kxs/le5GXZAc2K1/VCHauW734nCwpu1cFI8jL1niyrqk7E4tGL92w==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "@types/node-int64": "*",
+ "@types/q": "*"
+ }
+ },
+ "node_modules/@types/tough-cookie": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
+ "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A=="
+ },
+ "node_modules/accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "peer": true,
+ "dependencies": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/app-root-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
+ "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/argparse/node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ },
+ "node_modules/aria-query": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
+ "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
+ "dev": true,
+ "dependencies": {
+ "ast-types-flow": "0.0.7",
+ "commander": "^2.11.0"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+ "peer": true
+ },
+ "node_modules/asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/ast-types-flow": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
+ "dev": true
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
+ },
+ "node_modules/axobject-query": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
+ "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
+ "dev": true,
+ "dependencies": {
+ "ast-types-flow": "0.0.7"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "peer": true,
+ "dependencies": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/codelyzer": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz",
+ "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==",
+ "dev": true,
+ "dependencies": {
+ "@angular/compiler": "9.0.0",
+ "@angular/core": "9.0.0",
+ "app-root-path": "^3.0.0",
+ "aria-query": "^3.0.0",
+ "axobject-query": "2.0.2",
+ "css-selector-tokenizer": "^0.7.1",
+ "cssauron": "^1.4.0",
+ "damerau-levenshtein": "^1.0.4",
+ "rxjs": "^6.5.3",
+ "semver-dsl": "^1.0.1",
+ "source-map": "^0.5.7",
+ "sprintf-js": "^1.1.2",
+ "tslib": "^1.10.0",
+ "zone.js": "~0.10.3"
+ },
+ "peerDependencies": {
+ "@angular/compiler": ">=2.3.1 <12.0.0 || ^11.0.0-next || ^11.1.0-next || ^11.2.0-next",
+ "@angular/core": ">=2.3.1 <12.0.0 || ^11.0.0-next || ^11.1.0-next || ^11.2.0-next",
+ "tslint": "^5.0.0 || ^6.0.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "peer": true,
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+ "peer": true
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "node_modules/css-selector-tokenizer": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
+ "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "node_modules/cssauron": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
+ "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
+ "dev": true,
+ "dependencies": {
+ "through": "X.X.X"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/damerau-levenshtein": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
+ "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
+ "dev": true
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "peer": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+ "peer": true
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "peer": true
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "peer": true
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "peer": true,
+ "dependencies": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ },
+ "node_modules/fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "peer": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+ "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=6 <7 || >=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "node_modules/generic-pool": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.7.1.tgz",
+ "integrity": "sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w==",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "deprecated": "this library is no longer supported",
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "peer": true,
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-errors/node_modules/inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "peer": true
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "peer": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
+ "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
+ "dev": true,
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "node_modules/json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "node_modules/jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.1.6"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "peer": true
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "peer": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "dependencies": {
+ "mime-db": "1.44.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "peer": true
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "peer": true,
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+ "peer": true
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+ "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+ "peer": true,
+ "dependencies": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/psl": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "peer": true,
+ "dependencies": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/request/node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/request/node_modules/qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+ "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.1.0",
+ "path-parse": "^1.0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.9.0"
+ },
+ "engines": {
+ "npm": ">=2.0.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/semver-dsl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
+ "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=",
+ "dev": true,
+ "dependencies": {
+ "semver": "^5.3.0"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "peer": true,
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "peer": true
+ },
+ "node_modules/serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "peer": true,
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "peer": true
+ },
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
+ },
+ "node_modules/sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "node_modules/tslint": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+ "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
+ "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "builtin-modules": "^1.1.1",
+ "chalk": "^2.3.0",
+ "commander": "^2.12.1",
+ "diff": "^4.0.1",
+ "glob": "^7.1.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.3",
+ "resolve": "^1.3.2",
+ "semver": "^5.3.0",
+ "tslib": "^1.13.0",
+ "tsutils": "^2.29.0"
+ },
+ "bin": {
+ "tslint": "bin/tslint"
+ },
+ "engines": {
+ "node": ">=4.8.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev"
+ }
+ },
+ "node_modules/tsutils": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev"
+ }
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "peer": true,
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+ "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+ "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "node_modules/zipkin": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/zipkin/-/zipkin-0.15.0.tgz",
+ "integrity": "sha512-kKzRYWErW93bLh0kzyGPa7rQN49IN+TdeWWDNrF5r/B1VyPbj0Hqmwp2h0bsRiaukd+DBjprj22GbatOCjDVWA==",
+ "dependencies": {
+ "base64-js": "^1.1.2",
+ "is-promise": "^2.1.0"
+ }
+ },
+ "node_modules/zone.js": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
+ "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==",
+ "dev": true
+ }
+ },
+ "dependencies": {
+ "@angular/compiler": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz",
+ "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==",
+ "dev": true,
+ "requires": {}
+ },
+ "@angular/core": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz",
+ "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==",
+ "dev": true,
+ "requires": {}
+ },
+ "@babel/code-frame": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+ "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
+ "dev": true,
+ "requires": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+ "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
+ "dev": true
+ },
+ "@babel/highlight": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+ "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.10.4",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ }
+ },
+ "@creditkarma/thrift-client": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-client/-/thrift-client-0.16.1.tgz",
+ "integrity": "sha512-oTlz6dNGj0nQjPyTB+eLwMDE2DAsbsfgz4xmPt7yf8tMd4lazFY7eVzEK0slh6zj9KYD/wuS21wz3Bmofp3pQw==",
+ "requires": {
+ "@types/generic-pool": "^3.1.4",
+ "@types/request": "^2.48.1",
+ "generic-pool": "^3.4.2",
+ "request": "^2.88.0"
+ }
+ },
+ "@creditkarma/thrift-parser": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-parser/-/thrift-parser-1.2.0.tgz",
+ "integrity": "sha512-mSRxjSXvU6sBfWhMBWXl7H/XEKWHQ7x+MUDLwyeFIwwX9UaZKPOc7TgGd0N78kcZtIMk82ArdxO6aFhqnBuNtg==",
+ "dev": true
+ },
+ "@creditkarma/thrift-server-core": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-core/-/thrift-server-core-0.16.1.tgz",
+ "integrity": "sha512-rbzmS46vH6oth1I7zcSLcTslRlzolAiD9TSCNoxZHdnwfM65QJQIVCJ8Tz3l/78fzZAiZ71+9wZAuf61jl0Wzg==",
+ "requires": {
+ "@types/lodash": "^4.14.136",
+ "lodash": "^4.17.15"
+ }
+ },
+ "@creditkarma/thrift-server-express": {
+ "version": "0.16.1",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-express/-/thrift-server-express-0.16.1.tgz",
+ "integrity": "sha512-XPUPRnnJkGbLCZZMwLRSNGMZgxlC0n1LYIW2CXuH24aZIcTd9hQP09xc1khs5STMZii6q79wWx2hg6H/oZDDYA==",
+ "requires": {
+ "zipkin": "^0.15.0"
+ }
+ },
+ "@creditkarma/thrift-typescript": {
+ "version": "3.7.6",
+ "resolved": "https://registry.npmjs.org/@creditkarma/thrift-typescript/-/thrift-typescript-3.7.6.tgz",
+ "integrity": "sha512-v/9Bi3YqExw8bOHA1F/087zru14qExO1e4rdV/+hjYOnUk0HX3zmi6giu/QR9c9QK+5bxekZd4pUxgX7HWwvwQ==",
+ "dev": true,
+ "requires": {
+ "@creditkarma/thrift-parser": "^1.2.0",
+ "@types/fs-extra": "^7.0.0",
+ "fs-extra": "^8.0.1",
+ "glob": "^7.1.2",
+ "typescript": "3.5.x"
+ }
+ },
+ "@types/body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+ "peer": true,
+ "requires": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/caseless": {
+ "version": "0.12.2",
+ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
+ "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
+ },
+ "@types/connect": {
+ "version": "3.4.33",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
+ "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
+ "peer": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/express": {
+ "version": "4.17.9",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.9.tgz",
+ "integrity": "sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw==",
+ "peer": true,
+ "requires": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "*",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "@types/express-serve-static-core": {
+ "version": "4.17.14",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.14.tgz",
+ "integrity": "sha512-uFTLwu94TfUFMToXNgRZikwPuZdOtDgs3syBtAIr/OXorL1kJqUJT9qCLnRZ5KBOWfZQikQ2xKgR2tnDj1OgDA==",
+ "peer": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*"
+ }
+ },
+ "@types/fs-extra": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-7.0.0.tgz",
+ "integrity": "sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/generic-pool": {
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/@types/generic-pool/-/generic-pool-3.1.9.tgz",
+ "integrity": "sha512-IkXMs8fhV6+E4J8EWv8iL7mLvApcLLQUH4m1Rex3KCPRqT+Xya0DDHIeGAokk/6VXe9zg8oTWyr+FGyeuimEYQ==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/lodash": {
+ "version": "4.14.165",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz",
+ "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg=="
+ },
+ "@types/mime": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
+ "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==",
+ "peer": true
+ },
+ "@types/node": {
+ "version": "14.14.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz",
+ "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ=="
+ },
+ "@types/node-int64": {
+ "version": "0.4.29",
+ "resolved": "https://registry.npmjs.org/@types/node-int64/-/node-int64-0.4.29.tgz",
+ "integrity": "sha512-rHXvenLTj/CcsmNAebaBOhxQ2MqEGl3yXZZcZ21XYR+gzGTTcpOy2N4IxpvTCz48loyQNatHvfn6GhIbbZ1R3Q==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/q": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
+ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+ "dev": true
+ },
+ "@types/qs": {
+ "version": "6.9.5",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz",
+ "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==",
+ "peer": true
+ },
+ "@types/range-parser": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
+ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
+ "peer": true
+ },
+ "@types/request": {
+ "version": "2.48.5",
+ "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz",
+ "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==",
+ "requires": {
+ "@types/caseless": "*",
+ "@types/node": "*",
+ "@types/tough-cookie": "*",
+ "form-data": "^2.5.0"
+ }
+ },
+ "@types/serve-static": {
+ "version": "1.13.8",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz",
+ "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==",
+ "peer": true,
+ "requires": {
+ "@types/mime": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/thrift": {
+ "version": "0.10.10",
+ "resolved": "https://registry.npmjs.org/@types/thrift/-/thrift-0.10.10.tgz",
+ "integrity": "sha512-sEhRbmmQgiTn+JdophEPiuTFkc9QRl7R/Kxs/le5GXZAc2K1/VCHauW734nCwpu1cFI8jL1niyrqk7E4tGL92w==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/node-int64": "*",
+ "@types/q": "*"
+ }
+ },
+ "@types/tough-cookie": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
+ "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A=="
+ },
+ "accepts": {
+ "version": "1.3.7",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+ "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+ "peer": true,
+ "requires": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ }
+ },
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "app-root-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
+ "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==",
+ "dev": true
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ },
+ "dependencies": {
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ }
+ }
+ },
+ "aria-query": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
+ "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
+ "dev": true,
+ "requires": {
+ "ast-types-flow": "0.0.7",
+ "commander": "^2.11.0"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+ "peer": true
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ },
+ "ast-types-flow": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+ "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
+ "dev": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ },
+ "aws4": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+ "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
+ },
+ "axobject-query": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
+ "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
+ "dev": true,
+ "requires": {
+ "ast-types-flow": "0.0.7"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+ "dev": true
+ },
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+ "peer": true,
+ "requires": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "builtin-modules": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+ "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+ "dev": true
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+ "peer": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "codelyzer": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz",
+ "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==",
+ "dev": true,
+ "requires": {
+ "@angular/compiler": "9.0.0",
+ "@angular/core": "9.0.0",
+ "app-root-path": "^3.0.0",
+ "aria-query": "^3.0.0",
+ "axobject-query": "2.0.2",
+ "css-selector-tokenizer": "^0.7.1",
+ "cssauron": "^1.4.0",
+ "damerau-levenshtein": "^1.0.4",
+ "rxjs": "^6.5.3",
+ "semver-dsl": "^1.0.1",
+ "source-map": "^0.5.7",
+ "sprintf-js": "^1.1.2",
+ "tslib": "^1.10.0",
+ "zone.js": "~0.10.3"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+ "dev": true
+ },
+ "content-disposition": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+ "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "peer": true,
+ "requires": {
+ "safe-buffer": "5.1.2"
+ }
+ },
+ "content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "peer": true
+ },
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+ "peer": true
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+ "peer": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "css-selector-tokenizer": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
+ "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
+ "cssauron": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
+ "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
+ "dev": true,
+ "requires": {
+ "through": "X.X.X"
+ }
+ },
+ "cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true
+ },
+ "damerau-levenshtein": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
+ "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
+ "dev": true
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "peer": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "depd": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+ "peer": true
+ },
+ "destroy": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
+ "peer": true
+ },
+ "diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
+ "peer": true
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+ "peer": true
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+ "peer": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+ "dev": true
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+ "peer": true
+ },
+ "express": {
+ "version": "4.17.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+ "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+ "peer": true,
+ "requires": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ },
+ "fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
+ "finalhandler": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+ "peer": true,
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ },
+ "form-data": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+ "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "forwarded": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
+ "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+ "peer": true
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+ "peer": true
+ },
+ "fs-extra": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+ "dev": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "generic-pool": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.7.1.tgz",
+ "integrity": "sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w=="
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ },
+ "har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "requires": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "http-errors": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+ "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+ "peer": true,
+ "requires": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+ "peer": true
+ }
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "peer": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dev": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "peer": true
+ },
+ "is-core-module": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
+ "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
+ "dev": true,
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ },
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+ "peer": true
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+ "peer": true
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+ "peer": true
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "peer": true
+ },
+ "mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
+ },
+ "mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "requires": {
+ "mime-db": "1.44.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "dev": true
+ },
+ "mkdirp": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "peer": true
+ },
+ "negotiator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+ "peer": true
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "on-finished": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+ "peer": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dev": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "peer": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "dev": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+ "peer": true
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ },
+ "proxy-addr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
+ "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+ "peer": true,
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "psl": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ },
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ },
+ "qs": {
+ "version": "6.7.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+ "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
+ "peer": true
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "peer": true
+ },
+ "raw-body": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+ "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+ "peer": true,
+ "requires": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ }
+ }
+ },
+ "resolve": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+ "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+ "dev": true,
+ "requires": {
+ "is-core-module": "^2.1.0",
+ "path-parse": "^1.0.6"
+ }
+ },
+ "rxjs": {
+ "version": "6.6.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+ "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ },
+ "semver-dsl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
+ "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=",
+ "dev": true,
+ "requires": {
+ "semver": "^5.3.0"
+ }
+ },
+ "send": {
+ "version": "0.17.1",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+ "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+ "peer": true,
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+ "peer": true
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+ "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+ "peer": true,
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+ "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+ "peer": true
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true
+ },
+ "sprintf-js": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+ "dev": true
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
+ "peer": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+ "dev": true
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "peer": true
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "tslint": {
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+ "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "builtin-modules": "^1.1.1",
+ "chalk": "^2.3.0",
+ "commander": "^2.12.1",
+ "diff": "^4.0.1",
+ "glob": "^7.1.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.3",
+ "resolve": "^1.3.2",
+ "semver": "^5.3.0",
+ "tslib": "^1.13.0",
+ "tsutils": "^2.29.0"
+ }
+ },
+ "tsutils": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.8.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "peer": true,
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "typescript": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+ "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
+ "dev": true
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "peer": true
+ },
+ "uri-js": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+ "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+ "requires": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "peer": true
+ },
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "peer": true
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "dev": true
+ },
+ "zipkin": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/zipkin/-/zipkin-0.15.0.tgz",
+ "integrity": "sha512-kKzRYWErW93bLh0kzyGPa7rQN49IN+TdeWWDNrF5r/B1VyPbj0Hqmwp2h0bsRiaukd+DBjprj22GbatOCjDVWA==",
+ "requires": {
+ "base64-js": "^1.1.2",
+ "is-promise": "^2.1.0"
+ }
+ },
+ "zone.js": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
+ "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==",
+ "dev": true
+ }
+ }
+}
diff --git a/not-alone-player/package.json b/not-alone-player/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..7e48baa52be3640716125b97237db3b07092b8ff
--- /dev/null
+++ b/not-alone-player/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "not-alone-player",
+ "version": "0.0.0",
+ "main": "dist/main.js",
+ "scripts": {
+ "prebuild": "tslint -c tslint.json -p tsconfig.json --fix",
+ "build": "tsc",
+ "prestart": "npm run build",
+ "start": "node ./dist/main.js",
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "codegen": "\"./node_modules/.bin/thrift-typescript\" --target thrift-server --sourceDir \"../not-alone-core/src/main/thrift/\" --outDir \"./src/codegen/\""
+ },
+ "private": true,
+ "devDependencies": {
+ "@creditkarma/thrift-parser": "^1.2.0",
+ "@creditkarma/thrift-typescript": "^3.7.6",
+ "@types/thrift": "^0.10.10",
+ "codelyzer": "^6.0.1",
+ "tslint": "^6.1.3"
+ },
+ "dependencies": {
+ "@creditkarma/thrift-client": "^0.16.1",
+ "@creditkarma/thrift-server-core": "^0.16.1",
+ "@creditkarma/thrift-server-express": "^0.16.1",
+ "@types/express": "^4.17.9",
+ "express": "^4.17.1"
+ },
+ "browser": {
+ "crypto": false,
+ "stream": false
+ }
+}
diff --git a/not-alone-player/pom.xml b/not-alone-player/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4ca80c0fb5a5e01dc0f466f0bcbf2c0079447db9
--- /dev/null
+++ b/not-alone-player/pom.xml
@@ -0,0 +1,74 @@
+
+
+
+ not-alone
+ fr.univnantes.alma
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ not-alone-player
+ Not Alone Player Services
+
+
+
+
+ com.github.eirslett
+ frontend-maven-plugin
+ 1.10.0
+
+ ./
+ v14.11.0
+ 7.0.10
+
+
+
+ install node and npm
+
+ install-node-and-npm
+
+ generate-resources
+
+
+ npm install
+
+ npm
+
+
+ install
+
+ generate-resources
+
+
+ npm run build
+
+ npm
+
+
+ run build
+
+
+
+ code generation
+ compile
+
+ npm
+
+
+ run codegen
+
+
+
+
+
+
+
+ ./dist/not-alone-web
+ static
+
+
+
+
+
diff --git a/not-alone-player/src/core/game.ts b/not-alone-player/src/core/game.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b5e59123a18f4720f339d631a0167db5e6e6a239
--- /dev/null
+++ b/not-alone-player/src/core/game.ts
@@ -0,0 +1,26 @@
+import { TPlayer, TRoomId, TBoard, TColor, TCard, TPlacedJeton, TPhase, TDescription } from 'src/codegen/common';
+
+export interface GameInterface {
+
+/*
+ createGame(numberOfPlayers: number): Promise;
+ join(gameId: number): Promise;
+*/
+ createRoom(player: TPlayer): Promise;
+
+ sendStartGame(player: TPlayer, creatureId: number, board: TBoard, color: TColor, placeCards: TCard[]): Promise;
+
+ joinRoom(player: TPlayer, roomId: TRoomId): Promise;
+
+ getGameDescription(player: TPlayer): Promise;
+
+ sendFinishPhase(player: TPlayer, phase: TPhase): Promise;
+
+ sendPlayCards(player: TPlayer, playerCards: TCard[]): Promise;
+
+ sendPlaceJetons(player: TPlayer, placedJetons: TPlacedJeton[]): Promise;
+
+ sendResist(player: TPlayer, number: number): Promise;
+
+ sendGiveUp(player: TPlayer): Promise;
+}
diff --git a/not-alone-player/src/game/items/player-team.ts b/not-alone-player/src/game/items/player-team.ts
new file mode 100644
index 0000000000000000000000000000000000000000..00a40e482656afa36fa21cf441e46116e0095d2e
--- /dev/null
+++ b/not-alone-player/src/game/items/player-team.ts
@@ -0,0 +1,4 @@
+export enum PlayerTeam {
+ CREATURE,
+ TRAQUES
+}
diff --git a/not-alone-player/src/game/utilitary/conversion.ts b/not-alone-player/src/game/utilitary/conversion.ts
new file mode 100644
index 0000000000000000000000000000000000000000..031b1611294de510ecbcf4706e85dd6e968854bc
--- /dev/null
+++ b/not-alone-player/src/game/utilitary/conversion.ts
@@ -0,0 +1,16 @@
+import { TPlayerTeam } from 'src/codegen/common';
+import { PlayerTeam } from '../items/player-team';
+
+export class Conversion {
+
+ public static toPlayerTeam(tTeam: TPlayerTeam): PlayerTeam {
+ if (tTeam.type === 'CREATURE') {
+ return PlayerTeam.CREATURE;
+ } else if (tTeam.type === 'TRAQUES') {
+ return PlayerTeam.TRAQUES;
+ } else {
+ throw new Error(tTeam.type + ' is not a valid PlayerTeam');
+ }
+ }
+
+}
diff --git a/not-alone-player/src/handler/client-service-handler.ts b/not-alone-player/src/handler/client-service-handler.ts
new file mode 100644
index 0000000000000000000000000000000000000000..979955456871da428d8c7018e3c8e1040ee2acfc
--- /dev/null
+++ b/not-alone-player/src/handler/client-service-handler.ts
@@ -0,0 +1,106 @@
+import { TDescription, TPlayerTeam, TPhase, TAction, TAskAction, Response } from 'src/codegen/common';
+import { PlayerTeam } from 'src/game/items/player-team';
+import { Conversion } from 'src/game/utilitary/conversion';
+// import { IHandler } from '../codegen/common/GameService';
+import { IHandler } from '../codegen/common/PlayerService';
+import { PlayerService } from '../player/player-service';
+
+export class ClientServiceHandler implements IHandler {
+
+ private service: PlayerService;
+
+ constructor() {
+ this.service = new PlayerService();
+ }
+
+ /*
+ public createGame(numberOfPlayers: number, context?: Context): number | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public join(gameId: number, request: IJoinRequest, context?: Context): number | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public startGame(gameId: number): void | Promise {
+ return this.service.startGame(gameId);
+ }
+ */
+
+ public ping(): boolean | Promise {
+ // return this.service.ping();
+ throw new Error('Method not implemented.');
+ }
+
+ public sendGameDescription(gameDescription: TDescription): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public sendGameStart(): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public sendGameIsFinished(winner: TPlayerTeam): void | Promise {
+ const team: PlayerTeam = Conversion.toPlayerTeam(winner);
+ throw new Error('Method not implemented.');
+ }
+
+ public sendFirstRoundStart(): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public sendStartPhase(phase: TPhase, gameDescription: TDescription): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public askAction(askedAction: TAskAction): TAction | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public sendAction(askedAction: TAskAction): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public sendResponse(response: Response): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ /*
+ public ping(): boolean | Promise {
+ return service.ping();
+ }
+
+ public sendGameDescription(gameDescription: TDescription): void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public void sendGameStart() : void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public void sendGameIsFinished(winner : TPlayerTeam) : void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public void sendFirstRoundStart() : void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public void sendStartPhase(phase : TPhase, gameDescription : TDescription) : void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public askAction(askedAction : TAskAction) : TAction | Promise {
+ return null;
+ }
+
+ public sendAction(askedAction : TAskAction) : void | Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ public sendResponse(response : Response) : void | Promise {
+ throw new Error('Method not implemented.');
+ }
+ */
+
+}
diff --git a/not-alone-player/src/main.ts b/not-alone-player/src/main.ts
new file mode 100644
index 0000000000000000000000000000000000000000..259572eedd53c905c125aa965ab01be9a4ce7f3a
--- /dev/null
+++ b/not-alone-player/src/main.ts
@@ -0,0 +1,17 @@
+
+import { ThriftServer } from './thrift/thrift-server';
+
+/**
+ * Port used for local Thrift server.
+ */
+const LOCAL_PORT = 8090;
+
+class Main {
+ private server: ThriftServer;
+ constructor() {
+ console.log('Main class');
+ this.server = new ThriftServer(LOCAL_PORT);
+ }
+}
+
+const main: Main = new Main();
diff --git a/not-alone-player/src/player/player-service.ts b/not-alone-player/src/player/player-service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ee1428c4c5c386ce5b813a1ee2928d03c1c3e9ff
--- /dev/null
+++ b/not-alone-player/src/player/player-service.ts
@@ -0,0 +1,6 @@
+export class PlayerService {
+
+ startGame(gameId: number): void {
+ console.log('Start game', gameId);
+ }
+}
diff --git a/not-alone-player/src/thrift/game-proxy.ts b/not-alone-player/src/thrift/game-proxy.ts
new file mode 100644
index 0000000000000000000000000000000000000000..30b82bcb6d05482b1130703682db6a1e4aa36aaf
--- /dev/null
+++ b/not-alone-player/src/thrift/game-proxy.ts
@@ -0,0 +1,53 @@
+import { Client } from 'src/codegen/common/GameService';
+import { GameInterface } from '../core/game';
+import { CoreOptions } from 'request';
+import { createHttpClient, ICreateHttpClientOptions } from '@creditkarma/thrift-client';
+import { IJoinRequest, JoinRequest } from '../codegen/common/JoinRequest';
+import { TPlayer, TRoomId, TBoard, TColor, TCard, TDescription, TPhase, TPlacedJeton } from 'src/codegen/common';
+
+export class GameProxy implements GameInterface {
+ private thriftClient: Client;
+
+ constructor(options: ICreateHttpClientOptions) {
+ this.thriftClient = createHttpClient(Client, options);
+ }
+ createRoom(player: TPlayer): Promise {
+ throw new Error('Method not implemented.');
+ }
+ sendStartGame(player: TPlayer, creatureId: number, board: TBoard, color: TColor, placeCards: TCard[]): Promise {
+ throw new Error('Method not implemented.');
+ }
+ joinRoom(player: TPlayer, roomId: TRoomId): Promise {
+ throw new Error('Method not implemented.');
+ }
+ getGameDescription(player: TPlayer): Promise {
+ throw new Error('Method not implemented.');
+ }
+ sendFinishPhase(player: TPlayer, phase: TPhase): Promise {
+ throw new Error('Method not implemented.');
+ }
+ sendPlayCards(player: TPlayer, playerCards: TCard[]): Promise {
+ throw new Error('Method not implemented.');
+ }
+ sendPlaceJetons(player: TPlayer, placedJetons: TPlacedJeton[]): Promise {
+ throw new Error('Method not implemented.');
+ }
+ sendResist(player: TPlayer, number: number): Promise {
+ throw new Error('Method not implemented.');
+ }
+ sendGiveUp(player: TPlayer): Promise {
+ throw new Error('Method not implemented.');
+ }
+
+ /*
+ createGame(numberOfPlayers: number): Promise {
+ return this.thriftClient.createGame(numberOfPlayers);
+ }
+
+ join(gameId: number): Promise {
+ const request: IJoinRequest = new JoinRequest();
+ request.name = 'me';
+ return this.thriftClient.join(gameId, request);
+ }
+ */
+}
diff --git a/not-alone-player/src/thrift/thrift-client.ts b/not-alone-player/src/thrift/thrift-client.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d4133ebfdcee3305e9b6c92a19c414efc85171e9
--- /dev/null
+++ b/not-alone-player/src/thrift/thrift-client.ts
@@ -0,0 +1,16 @@
+import { createHttpClient, HttpConnection } from '@creditkarma/thrift-client';
+import * as request from 'request';
+import { CoreOptions } from 'request';
+
+import { Client } from '../codegen/common/GameService';
+
+const CONFIG = {
+ hostName: 'localhost',
+ port: 8045,
+};
+
+const thriftClient: Client = createHttpClient(Client, CONFIG);
+
+// const id: Promise = thriftClient.createGame(8);
+
+export class ThriftClient {}
diff --git a/not-alone-player/src/thrift/thrift-server.ts b/not-alone-player/src/thrift/thrift-server.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2817a3b51237940bcdb4b47c35859a95bf3e6d12
--- /dev/null
+++ b/not-alone-player/src/thrift/thrift-server.ts
@@ -0,0 +1,26 @@
+
+// import { GameService } from '../codegen/common/';
+import { PlayerService } from '../codegen/common/';
+import { ClientServiceHandler } from '../handler/client-service-handler';
+import * as express from 'express';
+import { createThriftServer } from '@creditkarma/thrift-server-express';
+
+const handler: ClientServiceHandler = new ClientServiceHandler();
+
+
+export class ThriftServer {
+ private app: express.Application;
+ constructor(port: number) {
+ this.app = createThriftServer({
+ path: '/thrift',
+ thriftOptions: {
+ serviceName: 'calculator-service',
+ handler: new PlayerService.Processor(handler),
+ },
+ });
+ this.app.listen(port, () => {
+ console.log(`Thrift Express server listening on port: ${port}`);
+ });
+ }
+}
+
diff --git a/not-alone-player/tsconfig.json b/not-alone-player/tsconfig.json
new file mode 100644
index 0000000000000000000000000000000000000000..8d1c6e7fea75c09ff00532b3c80ee0446bcc3fe2
--- /dev/null
+++ b/not-alone-player/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compileOnSave": false,
+ "compilerOptions": {
+ "baseUrl": "./",
+ "outDir": "./dist/",
+ "sourceMap": true,
+ "declaration": false,
+ "module": "CommonJs",
+ "moduleResolution": "node",
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "strict": true,
+ "target": "ES2017",
+ "typeRoots": [
+ "node_modules/@types"
+ ],
+ "lib": [
+ "es2017",
+ "dom"
+ ],
+ "paths": {
+ "core-js/es7/reflect": [
+ "node_modules/core-js/proposals/reflect-metadata"
+ ]
+ }
+ },
+ "include": ["target/generated-sources/thrift//**/*", "src/**/*"]
+}
diff --git a/not-alone-player/tslint.json b/not-alone-player/tslint.json
new file mode 100644
index 0000000000000000000000000000000000000000..6ddb6b2931511b11e5d5938f76076fb37e70363e
--- /dev/null
+++ b/not-alone-player/tslint.json
@@ -0,0 +1,131 @@
+{
+ "rulesDirectory": [
+ "node_modules/codelyzer"
+ ],
+ "rules": {
+ "arrow-return-shorthand": true,
+ "callable-types": true,
+ "class-name": true,
+ "comment-format": [
+ true,
+ "check-space"
+ ],
+ "curly": true,
+ "deprecation": {
+ "severity": "warn"
+ },
+ "eofline": true,
+ "forin": true,
+ "import-blacklist": [
+ true,
+ "rxjs/Rx"
+ ],
+ "import-spacing": true,
+ "indent": [
+ true,
+ "spaces"
+ ],
+ "interface-over-type-literal": true,
+ "label-position": true,
+ "max-line-length": [
+ true,
+ 140
+ ],
+ "member-access": false,
+ "member-ordering": [
+ true,
+ {
+ "order": [
+ "static-field",
+ "instance-field",
+ "static-method",
+ "instance-method"
+ ]
+ }
+ ],
+ "no-arg": true,
+ "no-bitwise": true,
+ "no-console": [
+ true,
+ "debug",
+ "info",
+ "time",
+ "timeEnd",
+ "trace"
+ ],
+ "no-construct": true,
+ "no-debugger": true,
+ "no-duplicate-super": true,
+ "no-empty": false,
+ "no-empty-interface": true,
+ "no-eval": true,
+ "no-inferrable-types": [
+ true,
+ "ignore-params"
+ ],
+ "no-misused-new": true,
+ "no-non-null-assertion": true,
+ "no-redundant-jsdoc": true,
+ "no-shadowed-variable": true,
+ "no-string-literal": false,
+ "no-string-throw": true,
+ "no-switch-case-fall-through": true,
+ "no-trailing-whitespace": true,
+ "no-unnecessary-initializer": true,
+ "no-unused-expression": true,
+ "no-use-before-declare": true,
+ "no-var-keyword": true,
+ "object-literal-sort-keys": false,
+ "one-line": [
+ true,
+ "check-open-brace",
+ "check-catch",
+ "check-else",
+ "check-whitespace"
+ ],
+ "prefer-const": true,
+ "quotemark": [
+ true,
+ "single"
+ ],
+ "radix": true,
+ "semicolon": [
+ true,
+ "always"
+ ],
+ "triple-equals": [
+ true,
+ "allow-null-check"
+ ],
+ "typedef-whitespace": [
+ true,
+ {
+ "call-signature": "nospace",
+ "index-signature": "nospace",
+ "parameter": "nospace",
+ "property-declaration": "nospace",
+ "variable-declaration": "nospace"
+ }
+ ],
+ "unified-signatures": true,
+ "variable-name": false,
+ "whitespace": [
+ true,
+ "check-branch",
+ "check-decl",
+ "check-operator",
+ "check-separator",
+ "check-type"
+ ],
+ "no-output-on-prefix": true,
+ "use-input-property-decorator": true,
+ "use-output-property-decorator": true,
+ "use-host-property-decorator": true,
+ "no-input-rename": true,
+ "no-output-rename": true,
+ "use-life-cycle-interface": true,
+ "use-pipe-transform-interface": true,
+ "component-class-suffix": true,
+ "directive-class-suffix": true
+ }
+}
diff --git a/not-alone-server/.gitignore b/not-alone-server/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ae3c1726048cd06b9a143e0376ed46dd9b9a8d53
--- /dev/null
+++ b/not-alone-server/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/not-alone-server/not-alone-server.iml b/not-alone-server/not-alone-server.iml
deleted file mode 100644
index 4a4ce55406053014eaaca4546111548f263f24ed..0000000000000000000000000000000000000000
--- a/not-alone-server/not-alone-server.iml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/not-alone-server/pom.xml b/not-alone-server/pom.xml
index 9ced649047d86a2433b631585f3eaeddb74dad02..e32fc10252fba49a5a1c674c6ddd67eec1bbdf7c 100644
--- a/not-alone-server/pom.xml
+++ b/not-alone-server/pom.xml
@@ -1,13 +1,13 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
spring-boot-starter-parent
- 2.3.4.RELEASE
-
+ 2.4.0
+
fr.univnantes.alma
@@ -17,25 +17,48 @@
Spring Boot Not Alone server
- 11
+ 0.8.5
+
+ org.mockito
+ mockito-core
+ 3.3.3
+ test
+
+
+ fr.univnantes.alma
+ not-alone-core
+ ${project.version}
+
+
org.springframework.boot
spring-boot-starter
-
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.atlanmod.commons
+ commons-core
+ 1.0.6
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
org.springframework.boot
spring-boot-starter-test
test
-
-
- org.junit.vintage
- junit-vintage-engine
-
-
+
+
+ com.h2database
+ h2
+ runtime
@@ -45,6 +68,33 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ org.apache.maven.plugins
+ maven-site-plugin
+ 3.9.1
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco.version}
+
+
+
+ prepare-agent-exe
+
+ prepare-agent
+
+
+
+
+ report-exe
+ pre-site
+
+ report
+
+
+
+
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java b/not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java
deleted file mode 100644
index 6f684090d7250c285a5314f1d59f5c0d88ff14b8..0000000000000000000000000000000000000000
--- a/not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package fr.univnantes.alma;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-@SpringBootApplication
-public class NotAloneApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(NotAloneApplication.class, args);
- }
-}
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/common/NotAloneDatabase.java b/not-alone-server/src/main/java/fr/univnantes/alma/common/NotAloneDatabase.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a036d55728dde2fb4e74180f676351c64fd94aa
--- /dev/null
+++ b/not-alone-server/src/main/java/fr/univnantes/alma/common/NotAloneDatabase.java
@@ -0,0 +1,32 @@
+package fr.univnantes.alma.common;
+
+import fr.univnantes.alma.server.game.item.card.CardName;
+import fr.univnantes.alma.server.game.item.card.PlaceCard;
+import fr.univnantes.alma.server.game.item.card.SurvivalCard;
+import fr.univnantes.alma.server.game.item.card.TrackingCard;
+
+import java.util.List;
+
+public interface NotAloneDatabase {
+
+ public PlaceCard findPlaceCard(String idCard);
+
+ public List findPlaceCards(List idCards);
+
+ public SurvivalCard findSurvivalCard(String idCard);
+
+ public List findSurvivalCards(List idCards);
+
+ public List findAllSurvivalCard();
+
+ public TrackingCard findTrackingCard(String idCard);
+
+ public List findTrackingCards(List idCards);
+
+ public List findAllTrackingCard();
+
+ public List findPowersDescription(String cardNameString);
+
+ public List findPowersDescription(CardName cardName);
+
+}
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/common/RoomService.java b/not-alone-server/src/main/java/fr/univnantes/alma/common/RoomService.java
new file mode 100644
index 0000000000000000000000000000000000000000..ee23c97298e780b161179edf4bc1a4b1b4b73efe
--- /dev/null
+++ b/not-alone-server/src/main/java/fr/univnantes/alma/common/RoomService.java
@@ -0,0 +1,83 @@
+package fr.univnantes.alma.common;
+
+import fr.univnantes.alma.server.game.item.Phase;
+import fr.univnantes.alma.server.game.item.board.Board;
+import fr.univnantes.alma.server.game.item.card.Card;
+import fr.univnantes.alma.server.game.item.jeton.PlacedJeton;
+import fr.univnantes.alma.server.game.item.planet.Planet;
+import fr.univnantes.alma.server.user.User;
+import fr.univnantes.alma.thrift.GameNotFound;
+import fr.univnantes.alma.thrift.InvalidOperationException;
+import fr.univnantes.alma.thrift.Response;
+import fr.univnantes.alma.thrift.TDescription;
+import org.checkerframework.checker.units.qual.C;
+
+import java.util.List;
+
+public interface RoomService {
+
+ /**
+ * Create a room if the player is not already in a room
+ * @param user The player
+ * @return The game id
+ */
+ String createRoom(User user) throws InvalidOperationException;
+
+ /**
+ * Join the room if it's not full and if the player is not in a room
+ * @param user The player
+ * @param roomId The room id
+ * @return A response
+ */
+ Response joinRoom(User user, String roomId) throws GameNotFound;
+
+ /**
+ * Start the game where the player is the game creator
+ * @param user The player
+ * @param creatureId The in game id of the creature
+ * @param board The board choose to play
+ * @param planet The planet used to play
+ * @return A response
+ */
+ Response startGame(User user, int creatureId, Board board, Planet planet);
+
+ /**
+ * @param user A user
+ * @return The description of the user's game
+ */
+ TDescription getGameDescription(User user) throws InvalidOperationException;
+
+ /**
+ * Send to the room that the user has finished a phase
+ * @param user The user
+ * @param phase The phase
+ */
+ void sendFinishPhase(User user, Phase phase) throws InvalidOperationException;
+
+ /**
+ * Send to the room that the user play cards
+ * @param user The user
+ * @param cards The cards
+ */
+ void sendPlayCards(User user, List cards) throws InvalidOperationException;
+
+ /**
+ * Send to the room that the user place jetons
+ * @param user The user
+ * @param placedJetons The placed jetons
+ */
+ void sendPlaceJetons(User user, List placedJetons) throws InvalidOperationException;
+
+ /**
+ * Send to the room that the user resist of number pawn Willingness
+ * @param user The user
+ * @param number The number of pawn Willingness lost
+ */
+ void sendResist(User user, int number) throws InvalidOperationException;
+
+ /**
+ * Send to the room that the user give up
+ * @param user The user
+ */
+ void sendGiveUp(User user) throws InvalidOperationException;
+}
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseFactory.java b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..39556245e362ff7e8d3b351c8c2f1a1445fde5ea
--- /dev/null
+++ b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseFactory.java
@@ -0,0 +1,12 @@
+package fr.univnantes.alma.data;
+
+import fr.univnantes.alma.common.NotAloneDatabase;
+
+public class DatabaseFactory {
+
+ private DatabaseFactory(){}
+
+ public static NotAloneDatabase getDatabase(){
+ return new DatabaseStub();
+ }
+}
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseStub.java b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseStub.java
new file mode 100644
index 0000000000000000000000000000000000000000..2653e47aa7a8bd7d9adc8cbae673406b2d1b4254
--- /dev/null
+++ b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseStub.java
@@ -0,0 +1,266 @@
+package fr.univnantes.alma.data;
+
+import fr.univnantes.alma.common.NotAloneDatabase;
+import fr.univnantes.alma.server.game.item.Phase;
+import fr.univnantes.alma.server.game.item.card.CardName;
+import fr.univnantes.alma.server.game.item.card.PlaceCard;
+import fr.univnantes.alma.server.game.item.card.SurvivalCard;
+import fr.univnantes.alma.server.game.item.card.TrackingCard;
+import fr.univnantes.alma.server.game.item.jeton.JetonSymbol;
+
+import java.util.*;
+
+public class DatabaseStub implements NotAloneDatabase {
+
+ private Map placeCardMap;
+ private Map survivalCardMap;
+ private Map trackingCardMap;
+
+ public DatabaseStub() {
+ initializePlaceCardMap();
+ initializeSurvivalCardMap();
+ initializeTrackingCardMap();
+ }
+
+ private void initializePlaceCardMap(){
+ placeCardMap = new HashMap<>();
+ placeCardMap.put("ANTRE", new PlaceCard(CardName.ANTRE, "Antre", "Lorem ipsum",1, "/image.png", "#4466bb"));
+ placeCardMap.put("NEXUS", new PlaceCard(CardName.NEXUS, "Nexus", "Lorem ipsum", 1, "/image.png", "#4466bb"));
+ placeCardMap.put("JUNGLE", new PlaceCard(CardName.JUNGLE, "Jungle", "Lorem ipsum", 2, "/image.png", "#4466bb"));
+ placeCardMap.put("OASIS", new PlaceCard(CardName.OASIS, "Oasis", "Lorem ipsum", 2, "/image.png", "#4466bb"));
+ placeCardMap.put("RIVIERE", new PlaceCard(CardName.RIVIERE, "Rivière", "Lorem ipsum", 3, "/image.png", "#4466bb"));
+ placeCardMap.put("FJORD", new PlaceCard(CardName.FJORD, "Fjord", "Lorem ipsum", 3, "/image.png", "#4466bb"));
+ placeCardMap.put("DOME", new PlaceCard(CardName.DOME,"Dôme", "Lorem ipsum", 4, "/image.png", "#4466bb"));
+ placeCardMap.put("PLAGE", new PlaceCard(CardName.PLAGE,"Plage", "Lorem ipsum", 4, "/image.png", "#4466bb"));
+ placeCardMap.put("ROVER", new PlaceCard(CardName.ROVER,"Rover", "Lorem ipsum", 5, "/image.png", "#4466bb"));
+ placeCardMap.put("LABYRINTHE", new PlaceCard(CardName.LABYRINTHE,"Labyrinthe", "Lorem ipsum", 5, "/image.png", "#4466bb"));
+ placeCardMap.put("MANGROVE", new PlaceCard(CardName.MANGROVE, "Mangrove", "Lorem ipsum", 6, "/image.png", "#4466bb"));
+ placeCardMap.put("MARAIS", new PlaceCard(CardName.MARAIS, "Marais", "Lorem ipsum", 6, "/image.png", "#4466bb"));
+ placeCardMap.put("ABRI", new PlaceCard(CardName.ABRI, "Abri", "Lorem ipsum", 7, "/image.png", "#4466bb"));
+ placeCardMap.put("ARCHIPEL", new PlaceCard(CardName.ARCHIPEL, "Archipel", "Lorem ipsum", 7, "/image.png", "#4466bb"));
+ placeCardMap.put("EPAVE", new PlaceCard(CardName.EPAVE, "Epave", "Lorem ipsum", 8, "/image.png", "#4466bb"));
+ placeCardMap.put("POLE", new PlaceCard(CardName.POLE, "Pole", "Lorem ipsum", 8, "/image.png", "#4466bb"));
+ placeCardMap.put("FUNGI", new PlaceCard(CardName.FUNGI, "Fungi", "Lorem ipsum", 9, "/image.png", "#4466bb"));
+ placeCardMap.put("SOURCE", new PlaceCard(CardName.SOURCE, "Source", "Lorem ipsum", 9, "/image.png", "#4466bb"));
+ placeCardMap.put("PORTAIL", new PlaceCard(CardName.PORTAIL, "Portail", "Lorem ipsum", 10, "/image.png", "#4466bb"));
+ placeCardMap.put("ARTEFACT", new PlaceCard(CardName.ARTEFACT, "Artefact", "Lorem ipsum", 10, "/image.png", "#4466bb"));
+ }
+
+ private void initializeSurvivalCardMap(){
+ survivalCardMap = new HashMap<>();
+ survivalCardMap.put("ADRENALINE", new SurvivalCard(CardName.ADRENALINE,"Adrénaline", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("ALERTE", new SurvivalCard(CardName.ALERTE,"Alerte", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("AMPLIFICATEUR", new SurvivalCard(CardName.AMPLIFICATEUR,"Amplificateur", "Lorem ipsum", Phase.PREPHASE_4));
+ survivalCardMap.put("BROUILLAGE", new SurvivalCard(CardName.BROUILLAGE,"Brouillage", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("CAVALE", new SurvivalCard(CardName.CAVALE,"Cavale", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("DETECTEUR", new SurvivalCard(CardName.DETECTEUR,"Détecteur", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("DRONE", new SurvivalCard(CardName.DRONE,"Drone", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("ENTRAVE", new SurvivalCard(CardName.ENTRAVE,"Entrave", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("EQUIPEMENT", new SurvivalCard(CardName.EQUIPEMENT,"Equipement", "Lorem ipsum", Phase.PREPHASE_4));
+ survivalCardMap.put("ESQUIVE", new SurvivalCard(CardName.ESQUIVE,"Esquive", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("FAUSSE_PISTE", new SurvivalCard(CardName.FAUSSE_PISTE,"Fausse-piste", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("HOLOGRAMME", new SurvivalCard(CardName.HOLOGRAMME,"Hologramme", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("LEURRE", new SurvivalCard(CardName.LEURRE,"Leurre", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("MIMETISME", new SurvivalCard(CardName.MIMETISME,"Mimétisme", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("NAVETTE", new SurvivalCard(CardName.NAVETTE,"Navette", "Lorem ipsum", Phase.PREPHASE_4));
+ survivalCardMap.put("PLANQUES", new SurvivalCard(CardName.PLANQUES,"Planques", "Lorem ipsum", Phase.PREPHASE_4));
+ survivalCardMap.put("PORTAIL_SURVIVAL", new SurvivalCard(CardName.PORTAIL_SURVIVAL,"Portail", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("RALLIEMENT", new SurvivalCard(CardName.RALLIEMENT,"Ralliement", "Lorem ipsum", Phase.PREPHASE_4));
+ survivalCardMap.put("REFUGE", new SurvivalCard(CardName.REFUGE,"Refuge", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("REGENERATION", new SurvivalCard(CardName.REGENERATION,"Régénération", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("RESISTANCE", new SurvivalCard(CardName.RESISTANCE,"Résistance", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("RETRAITE", new SurvivalCard(CardName.RETRAITE,"Retraite", "Lorem ipsum", Phase.PREPHASE_3));
+ survivalCardMap.put("RIPOSTE", new SurvivalCard(CardName.RIPOSTE,"Riposte", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("SACRIFICE", new SurvivalCard(CardName.SACRIFICE,"Sacrifice", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("SECOND_SOUFFLE", new SurvivalCard(CardName.SECOND_SOUFFLE,"Second souffle", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("SIXIEME_SENS", new SurvivalCard(CardName.SIXIEME_SENS,"Sixième sens", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("SYSTEME_D", new SurvivalCard(CardName.SYSTEME_D,"Système D", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("TENACITE", new SurvivalCard(CardName.TENACITE,"Ténacité", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("VACCIN", new SurvivalCard(CardName.VACCIN,"Vaccin", "Lorem ipsum", Phase.PREPHASE_1));
+ survivalCardMap.put("VOLTE_FACE", new SurvivalCard(CardName.VOLTE_FACE,"Volte-face", "Lorem ipsum", Phase.PREPHASE_4));
+ survivalCardMap.put("VORTEX", new SurvivalCard(CardName.VORTEX,"Vortex", "Lorem ipsum", Phase.PREPHASE_2));
+ }
+
+ private void initializeTrackingCardMap(){
+ trackingCardMap = new HashMap<>();
+ trackingCardMap.put("ACHARNEMENT", new TrackingCard(CardName.ACHARNEMENT, "Acharnement", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("ANGOISSE", new TrackingCard(CardName.ANGOISSE, "Angoisse", "Lorem ipsum", Phase.PREPHASE_1, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("ANTICIPATION", new TrackingCard(CardName.ANTICIPATION, "Anticipation", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("CATACLYSME", new TrackingCard(CardName.CATACLYSME, "Cataclysme", "Lorem ipsum", Phase.PREPHASE_3));
+ trackingCardMap.put("CHAMP_DE_FORCE", new TrackingCard(CardName.CHAMP_DE_FORCE, "Champ de force", "Lorem ipsum", Phase.PREPHASE_1, JetonSymbol.CIBLE));
+ trackingCardMap.put("CLONE", new TrackingCard(CardName.CLONE, "Clone", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("DEPLOIEMENT", new TrackingCard(CardName.DEPLOIEMENT, "Déploiement", "Lorem ipsum", Phase.PREPHASE_3));
+ trackingCardMap.put("DESESPOIR", new TrackingCard(CardName.DESESPOIR, "Désespoir", "Lorem ipsum", Phase.PREPHASE_1, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("DETOUR", new TrackingCard(CardName.DETOUR, "Détour", "Lorem ipsum", Phase.PREPHASE_3));
+ trackingCardMap.put("DOMINATION", new TrackingCard(CardName.DOMINATION, "Domination", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("EFFROI", new TrackingCard(CardName.EFFROI, "Effroi", "Lorem ipsum", Phase.POSTPHASE_1));
+ trackingCardMap.put("EMPRISE", new TrackingCard(CardName.EMPRISE, "Emprise", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("EPIDEMIE", new TrackingCard(CardName.EPIDEMIE, "Epidémie", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("FAILLE_TEMPORELLE", new TrackingCard(CardName.FAILLE_TEMPORELLE, "Faille temporelle", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("FLASHBACK", new TrackingCard(CardName.FLASHBACK, "Flashback", "Lorem ipsum", Phase.PREPHASE_1));
+ trackingCardMap.put("GARGANTUA", new TrackingCard(CardName.GARGANTUA, "Gargantua", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("HARCELEMENT", new TrackingCard(CardName.HARCELEMENT, "Harcèlements", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("HURLEMENTS", new TrackingCard(CardName.HURLEMENTS, "Hurlements", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("INERTIE", new TrackingCard(CardName.INERTIE, "Inertie", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("INTERFERENCES", new TrackingCard(CardName.INTERFERENCES, "Interférences", "Lorem ipsum", Phase.PREPHASE_2));
+ trackingCardMap.put("INTUITION", new TrackingCard(CardName.INTUITION, "Intuition", "Lorem ipsum", Phase.PREPHASE_1));
+ trackingCardMap.put("MAGNETISME", new TrackingCard(CardName.MAGNETISME, "Magnétisme", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("MIRAGE", new TrackingCard(CardName.MIRAGE, "Mirage", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("MUTATION", new TrackingCard(CardName.MUTATION, "Mutation", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("PSYCHOSE", new TrackingCard(CardName.PSYCHOSE, "Psychose", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("REMINISCENCE", new TrackingCard(CardName.REMINISCENCE, "Réminiscence", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("REPERAGE", new TrackingCard(CardName.REPERAGE, "Repérage", "Lorem ipsum", Phase.PREPHASE_4));
+ trackingCardMap.put("SABLES_MOUVANTS", new TrackingCard(CardName.SABLES_MOUVANTS, "Sables mouvants", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("SOIF_DE_SANG", new TrackingCard(CardName.SOIF_DE_SANG, "Soif de sang", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("STASE", new TrackingCard(CardName.STASE, "Stase", "Lorem ipsum", Phase.PREPHASE_4));
+ trackingCardMap.put("TELEPATHIE", new TrackingCard(CardName.TELEPATHIE, "Télépathie", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("TORNADE", new TrackingCard(CardName.TORNADE, "Tornade", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("TOXINE", new TrackingCard(CardName.TOXINE, "Toxine", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE));
+ trackingCardMap.put("UBIQUITE", new TrackingCard(CardName.UBIQUITE, "Ubiquité", "Lorem ipsum", Phase.PREPHASE_2, Arrays.asList(JetonSymbol.CIBLE, JetonSymbol.ARTEMIA)));
+ trackingCardMap.put("VIRUS", new TrackingCard(CardName.VIRUS, "Virus", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA));
+ trackingCardMap.put("ZONE_INTERDITE", new TrackingCard(CardName.ZONE_INTERDITE, "Zone interdite", "Lorem ipsum", Phase.PREPHASE_2));
+ }
+
+ public PlaceCard findPlaceCard(String idCard) {
+ return placeCardMap.get(idCard);
+ }
+
+ @Override
+ public List findPlaceCards(List idCards) {
+ List places = new ArrayList<>();
+ for(String id : idCards){
+ places.add(placeCardMap.get(id));
+ }
+ return places;
+ }
+
+ @Override
+ public SurvivalCard findSurvivalCard(String idCard) {
+ return survivalCardMap.get(idCard);
+ }
+
+ @Override
+ public List findSurvivalCards(List idCards) {
+ List survival = new ArrayList<>();
+ for(String id : idCards){
+ survival.add(survivalCardMap.get(id));
+ }
+ return survival;
+ }
+
+ @Override
+ public List findAllSurvivalCard() {
+ List survival = new ArrayList<>();
+ for(Map.Entry entry : survivalCardMap.entrySet()){
+ survival.add((SurvivalCard) entry.getValue());
+ }
+ return survival;
+ }
+
+ @Override
+ public TrackingCard findTrackingCard(String idCard) {
+ return trackingCardMap.get(idCard);
+ }
+
+ @Override
+ public List findTrackingCards(List idCards) {
+ List tracking = new ArrayList<>();
+ for(String id : idCards){
+ tracking.add(trackingCardMap.get(id));
+ }
+ return tracking;
+ }
+
+ @Override
+ public List findAllTrackingCard() {
+ List tracking = new ArrayList<>();
+ for(Map.Entry entry : trackingCardMap.entrySet()){
+ tracking.add((TrackingCard) entry.getValue());
+ }
+ return tracking;
+ }
+
+ @Override
+ public List findPowersDescription(String cardNameString) {
+ CardName cardName = null;
+ try {
+ cardName = CardName.valueOf(cardNameString);
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException("Invalid name of card");
+ }
+ return findPowersDescription(cardName);
+ }
+
+ @Override
+ public List findPowersDescription(CardName cardName) {
+ List powersDescription = new ArrayList<>();
+ switch (cardName) {
+ case ANTRE:
+ powersDescription = Arrays.asList("Reprenez en main les cartes Lieu de votre défausse (mais pas celui-ci)", "Copiez le pouvoir d’un Lieu où le jeton Créature se trouve");
+ break;
+ case JUNGLE:
+ powersDescription = Arrays.asList("Reprenez en main cette carte Lieu et 1 carte Lieu de votre défausse.");
+ break;
+ case RIVIERE:
+ powersDescription = Arrays.asList("Au prochain tour, jouez 2 cartes Lieu. Avant de révéler, choisissez-en une et reprenez l’autre en main.");
+ break;
+ case PLAGE:
+ powersDescription = Arrays.asList("Placer/Retirer le Pion Balise de la Plage. (Max 1 fois/tour). Si plusieurs Traqués explorent la Plage, l’un d’eux peut utiliser le pouvoir de la Plage et les autres peuvent récupérer 1 carte Lieu de leur défausse. Le pouvoir de la Plage est cumulable avec celui de l’Épave. ");
+ break;
+ case ROVER:
+ powersDescription = Arrays.asList("Prenez de la réserve une carte Lieu que vous ne possédez pas et ajoutez-le à votre main.");
+ break;
+ case MARAIS:
+ powersDescription = Arrays.asList("Reprenez en main cette carte Lieu et 2 cartes Lieu de votre défausse. Si le Marais est révélé grâce au Labyrinthe et que vous l’activez directement, ni le Marais ni le Labyrinthe ne sont repris en main.");
+ break;
+ case ABRI:
+ powersDescription = Arrays.asList("Piochez 2 carte Survie, gardez-en une et défaussez l’autre.");
+ break;
+ case EPAVE:
+ powersDescription = Arrays.asList("Avancez le pion Secours d'1 case (1 fois par tour, quel que soit le nombre de Traqués explorant l’Épave). Si plusieurs Traqués explorent l’Épave, l’un d’eux peut utiliser le pouvoir de l’Épave et les autres peuvent récupérer 1 carte Lieu de leur défausse. Le pouvoir de l’Épave est cumulable avec celui de la Plage.");
+ break;
+ case SOURCE:
+ powersDescription = Arrays.asList("Le Traqué de votre choix (vous ou un autre joueur) récupère 1 Volonté", "Piochez 1 carte Survie.");
+ break;
+ case ARTEFACT:
+ //None description list
+ break;
+ case NEXUS:
+ powersDescription = Arrays.asList("Copiez le pouvoir d'1 Lieu 2à 5. Avancez le pion Assimilation d'1 case supplémentaire si le jeton Créature attrape au moins 1 Traqué sur le Nexus.");
+ break;
+ case OASIS:
+ powersDescription = Arrays.asList("Reprenez en main cette carte Lieu plus 1 carte Lieu de votre défausse par Volonté qu’il vous manque, si possible.");
+ break;
+ case FJORD:
+ powersDescription = Arrays.asList("Lors du prochain tour : En Phase 1 : vous pouvez jouer une 2ème carte Lieu, face visible, de votre défausse, s’il n’y en a. En Phase 3 : résolvez 1 de ces Lieux. En Phase 4 : défaussez ces 2 cartes Lieu.");
+ break;
+ case DOME:
+ powersDescription = Arrays.asList("Déplacez le Bouclier d'1 Lieu vers le Dôme. Si le pion Boucler atteint le Dôme : reculer le pion Assimilation d'1 case et replacer le pion Bouclier sur le Lieu 1 (max 1x/tour).");
+ break;
+ case LABYRINTHE:
+ powersDescription = Arrays.asList("Révéler un Lieu : retourner, face visible, une des 5 cartes Lieu 6 à 10 de la planète Artemia et activer son pouvoir ou prendre 1 carte Lieu correspondante.", "Prendre de la réserve 1 carte Lieu déjà révélé.");
+ break;
+ case MANGROVE:
+ powersDescription = Arrays.asList("Échanger les cartes Lieu de sa main contre celles de sa défausse. Reprendre cette carte Lieu en main.");
+ break;
+ case ARCHIPEL:
+ powersDescription = Arrays.asList("Piocher 1 carte Survie. S’il vous reste moins de 3 cartes Lieu en main, le Traqué de votre choix récupère 1 Volonté.");
+ break;
+ case POLE:
+ powersDescription = Arrays.asList("Sacrifiez 1 Volonté (même si c’est le dernier), puis avancez le pion Secours de 2 cases. En Phase 4, replacer le pôle dans la réserve, qu’elle ait pu être activée ou non. Le Pôle ne peut être copié (que ce soit par le pouvoir d’un Lieu ou une carte Survie).");
+ break;
+ case FUNGI:
+ powersDescription = Arrays.asList("Piocher une carte Survie", "Placer jusqu’à 2 pions Volonté (si possible) sur les prochaines cases de la piste Secours. Quand le pion Secours atteint une de ces cases : le Traqué qui a le moins de Pion Volonté récupère le pion Volonté.");
+ break;
+ case PORTAIL:
+ powersDescription = Arrays.asList("Défausser le Portail pour jouer une autre carte Lieu de sa main et la résoudre. Le Portail téléporte le Traqué sur le second lieu joué, ce Traqué est donc susceptible de s’y faire attraper par un jeton Traque et/ou d’y être la cible d’une carte Traque. Le Portail est défaussé en phase 3 et la seconde carte Lieu en phase 4.");
+ break;
+ default:
+
+ }
+ List powers = new ArrayList<>(Collections.singletonList("Reprenez en main une carte Lieu de votre défausse"));
+ powers.addAll(powersDescription);
+ return powers;
+ }
+}
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/NotAloneApplication.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/NotAloneApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f31907fa8da4e499340b13bd899fb164c8fb0af
--- /dev/null
+++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/NotAloneApplication.java
@@ -0,0 +1,35 @@
+package fr.univnantes.alma.server;
+
+import fr.univnantes.alma.server.handler.GameServiceHandler;
+import fr.univnantes.alma.thrift.GameService;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TProtocolFactory;
+import org.apache.thrift.server.TServlet;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.web.servlet.ServletRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableAutoConfiguration
+@ComponentScan(basePackages = {"fr.univnantes.alma"})
+public class NotAloneApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(NotAloneApplication.class, args);
+ }
+
+ @Bean
+ public TProtocolFactory tProtocolFactory() {
+ return new TBinaryProtocol.Factory();
+ }
+
+ @Bean
+ public ServletRegistrationBean gameServer(TProtocolFactory protocolFactory, GameServiceHandler handler) {
+ TServlet tServlet = new TServlet(new GameService.Processor(handler), protocolFactory);
+
+ return new ServletRegistrationBean(tServlet, "/api");
+ }
+}
diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Game.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Game.java
new file mode 100644
index 0000000000000000000000000000000000000000..fd61a6e8c381288c91b89bc903fc1179ba9c1b63
--- /dev/null
+++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Game.java
@@ -0,0 +1,1504 @@
+package fr.univnantes.alma.server.game;
+
+import fr.univnantes.alma.common.NotAloneDatabase;
+import fr.univnantes.alma.data.DatabaseFactory;
+import fr.univnantes.alma.server.game.item.Phase;
+import fr.univnantes.alma.server.game.item.Reserve;
+import fr.univnantes.alma.server.game.item.action.*;
+import fr.univnantes.alma.server.game.item.board.Board;
+import fr.univnantes.alma.server.game.item.card.*;
+import fr.univnantes.alma.server.game.item.jeton.JetonSymbol;
+import fr.univnantes.alma.server.game.item.jeton.PlacedJeton;
+import fr.univnantes.alma.server.game.item.pioche.Pioche;
+import fr.univnantes.alma.server.game.item.planet.Place;
+import fr.univnantes.alma.server.game.item.planet.Planet;
+import fr.univnantes.alma.server.game.item.player.Creature;
+import fr.univnantes.alma.server.game.item.player.Player;
+import fr.univnantes.alma.server.game.item.player.Traque;
+import fr.univnantes.alma.server.game.item.power.Power;
+import fr.univnantes.alma.server.game.item.power.PowerType;
+import fr.univnantes.alma.server.game.item.power.modifier.PowerModifier;
+import fr.univnantes.alma.server.game.item.power.modifier.PowerModifierType;
+import fr.univnantes.alma.server.game.item.power.recurrent.PowerRecurrent;
+import fr.univnantes.alma.server.game.utilitary.Conversion;
+import fr.univnantes.alma.server.game.utilitary.Pair;
+import fr.univnantes.alma.thrift.*;
+import org.apache.thrift.TException;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static fr.univnantes.alma.server.game.PowerApplicator.applyPlayerCard;
+import static fr.univnantes.alma.server.game.PowerApplicator.resolvePlace;
+import static fr.univnantes.alma.server.game.item.action.ActionType.*;
+import static fr.univnantes.alma.server.game.item.jeton.JetonSymbol.ARTEMIA;
+import static fr.univnantes.alma.server.game.item.jeton.JetonSymbol.CIBLE;
+import static fr.univnantes.alma.server.game.item.player.PlayerTeam.CREATURE;
+import static fr.univnantes.alma.server.game.item.player.PlayerTeam.TRAQUE;
+
+public class Game implements GameInterface {
+ /**
+ * The powers of the next round
+ */
+ private List nextRoundPowers;
+
+ /**
+ * The planet
+ */
+ private Planet planet;
+
+ /**
+ * The reserve of the game
+ */
+ private Reserve reserve;
+
+ /**
+ * The "pioche" for survival cards
+ */
+ private Pioche survivalCardPioche;
+
+ /**
+ * The "pioche" for tracking cards
+ */
+ private Pioche trackingCardPioche;
+
+ /**
+ * The board of the game, containing the score
+ */
+ private Board board;
+
+ /**
+ * The database where the data are stored
+ */
+ private NotAloneDatabase database;
+
+ /**
+ * The creature
+ */
+ private Creature creature;
+
+ /**
+ * The traques
+ */
+ private List traques;
+
+ /**
+ * Map of inGameId to players
+ */
+ private Map playersMap;
+
+ /**
+ * Represents the state of the game
+ */
+ private Phase state;
+
+ /**
+ * Reference to the room
+ */
+ private Room room;
+
+ /**
+ * Contains the round variables that may be modified by power
+ */
+ private GameRoundVariables gameRoundVariables;
+
+ public Game(List> players, int creatureId, Planet planet, Board board, Room room) {
+ if(players.isEmpty() || players.size() > 7) {
+ throw new IllegalArgumentException("Need between 1 and 7 players");
+ }
+ int playerNumber = players.size();
+ this.planet = planet;
+ this.board = board;
+ this.board.initializeScore(playerNumber);
+ this.room = room;
+ this.database = DatabaseFactory.getDatabase();
+ this.nextRoundPowers = new ArrayList<>();
+ this.gameRoundVariables = new GameRoundVariables();
+ initializePlayer(players, creatureId);
+ initializeReserve(playerNumber);
+ initializeSurvivalCardPioche();
+ initializeTrackingCardPioche();
+ initializeCardsOfPlayers();
+ this.state = Phase.PREPHASE_1;
+ sendFirstRoundStart();
+ }
+
+ public Game(Collection playersId, int creatureId, Planet planet, Board board, Room room) {
+ if(playersId.isEmpty() || playersId.size() > 7) {
+ throw new IllegalArgumentException("Need between 1 and 7 players");
+ }
+ int playerNumber = playersId.size();
+ this.planet = planet;
+ this.board = board;
+ this.board.initializeScore(playerNumber);
+ this.room = room;
+ this.database = DatabaseFactory.getDatabase();
+ this.nextRoundPowers = new ArrayList<>();
+ this.gameRoundVariables = new GameRoundVariables();
+ initializePlayer(playersId, creatureId);
+ initializeReserve(playerNumber);
+ initializeSurvivalCardPioche();
+ initializeTrackingCardPioche();
+ initializeCardsOfPlayers();
+ this.state = Phase.PREPHASE_1;
+ sendFirstRoundStart();
+ }
+
+ /***************************
+ * Initialization
+ **************************/
+
+ /**
+ * Initialize Creature, Traques and the playerMap
+ */
+ private void initializePlayer(Collection playersId, int creatureId){
+ if(!playersId.contains(creatureId)) {
+ throw new IllegalArgumentException(creatureId + " doesn't represent a valid in game id");
+ }
+ this.traques = new ArrayList<>();
+ this.playersMap = new HashMap<>();
+ this.creature = new Creature("Player" + creatureId, creatureId);
+ this.playersMap.put(creatureId, this.creature);
+ for(int id : playersId) {
+ if(id != creatureId) {
+ Traque traque = new Traque("Player" + id, id);
+ this.traques.add(traque);
+ this.playersMap.put(id, traque);
+ }
+ }
+ }
+
+ /**
+ * Initialize Creature, Traques and the playerMap
+ */
+ private void initializePlayer(List> players, int creatureId){
+ List ids = players.stream().map(Pair::getKey).collect(Collectors.toList());
+ if(!ids.contains(creatureId)) {
+ throw new IllegalArgumentException(creatureId + " doesn't represent a valid in game id");
+ }
+ this.traques = new ArrayList<>();
+ this.playersMap = new HashMap<>();
+ for(Pair pair : players) {
+ if(pair.getKey() != creatureId) {
+ Traque traque = new Traque(pair.getValue(), pair.getKey());
+ this.traques.add(traque);
+ this.playersMap.put(pair.getKey(), traque);
+ }
+ else {
+ this.creature = new Creature(pair.getValue(), pair.getKey());
+ this.playersMap.put(creatureId, this.creature);
+ }
+ }
+ }
+
+ /**
+ * Initialize the reserve with placeCards
+ * @param playerNumber The number of players
+ */
+ private void initializeReserve(int playerNumber){
+ List cards = planet.getPlaceCardsInInterval(6, 10);
+ reserve = new Reserve(cards, playerNumber);
+ }
+
+ /**
+ * Initialize the pioche of survival cards
+ */
+ private void initializeSurvivalCardPioche(){
+ this.survivalCardPioche = new Pioche<>(database.findAllSurvivalCard());
+ }
+
+ /**
+ * Initialize the pioche of tracking cards
+ */
+ private void initializeTrackingCardPioche(){
+ this.trackingCardPioche = new Pioche<>(database.findAllTrackingCard());
+ }
+
+ /**
+ * Initialize the player's place cards, survival cards and tracking cards
+ */
+ private void initializeCardsOfPlayers(){
+ for(Traque traque : traques) {
+ traque.addPlaceCard(planet.getPlaceCardsInInterval(1, 5));
+ traque.addSurvivalCard(survivalCardPioche.draw());
+ }
+ creature.addTrackingCard(trackingCardPioche.draw(3));
+ }
+
+ /***************************
+ * Getters
+ **************************/
+
+ public Planet getPlanet() {
+ return planet;
+ }
+
+ public Reserve getReserve() {
+ return reserve;
+ }
+
+ public Pioche getSurvivalCardPioche() {
+ return survivalCardPioche;
+ }
+
+ public Pioche getTrackingCardPioche() {
+ return trackingCardPioche;
+ }
+
+ public Board getBoard() {
+ return board;
+ }
+
+ public Creature getCreature() {
+ return creature;
+ }
+
+ public List getTraques() {
+ return traques;
+ }
+
+ public Map getPlayersMap() {
+ return playersMap;
+ }
+
+ public Player getPlayer(int idPlayer) {return playersMap.get(idPlayer);}
+
+ public GameRoundVariables getGameRoundVariables() {
+ return gameRoundVariables;
+ }
+
+ public Phase getState() {
+ return state;
+ }
+
+ public Room getRoom() {
+ return room;
+ }
+
+ public boolean isJetonArtemiaIsActive() {
+ return gameRoundVariables.isJetonArtemiaIsActive();
+ }
+
+ public int getNumberWillingnessDecrementByJetonCreature() {
+ return gameRoundVariables.getNumberWillingnessDecrementByJetonCreature();
+ }
+
+ public boolean traqueCanResist() {
+ return gameRoundVariables.traqueCanResist();
+ }
+
+ public int getIdPlayerTargetByTrackingCardAnticipation() {
+ return gameRoundVariables.getIdPlayerTargetByTrackingCardAnticipation();
+ }
+
+ public boolean traqueCanPickSurvivalCards() {
+ return gameRoundVariables.traqueCanPickSurvivalCards();
+ }
+
+ /***************************
+ * Setters and modifiers
+ **************************/
+
+ public void addPowerForNextRound(Power power) {
+ this.nextRoundPowers.add(power);
+ }
+
+ public void disableJetonArtemia() {
+ gameRoundVariables.disableJetonArtemia();
+ }
+
+ public void enableJetonArtemia() {
+ gameRoundVariables.enableJetonArtemia();
+ }
+
+ public void setNumberWillingnessDecrementByJetonCreature(int number) {
+ gameRoundVariables.setNumberWillingnessDecrementByJetonCreature(number);
+ }
+
+ public void addNumberWillingnessByJetonCreature() {
+ gameRoundVariables.addNumberWillingnessByJetonCreature();
+ }
+ public void setTraqueCanResist(boolean traqueCanResist) {
+ this.gameRoundVariables.setTraqueCanResist(traqueCanResist);
+ }
+
+ public void setIdPlayerTargetByTrackingCardAnticipation(int idPlayerTargetByJetonCreature) {
+ this.gameRoundVariables.setIdPlayerTargetByTrackingCardAnticipation(idPlayerTargetByJetonCreature);
+ }
+
+ public void setTraqueCanPickSurvivalCards(boolean traqueCanPickSurvivalCards) {
+ gameRoundVariables.setTraqueCanPickSurvivalCards(traqueCanPickSurvivalCards);
+ }
+
+ /*************************************
+ * Game Interface Methods
+ ***********************************/
+
+ @Override
+ public boolean isFinish() {
+ return board.isFinish();
+ }
+
+ @Override
+ public Response playerHasFinished(int playerId, Phase phase) {
+ Response response;
+ Player player = playersMap.get(playerId);
+ if(state.equals(phase)) {
+ if (player.teamEqualsTo(CREATURE)) {
+ response = creatureHasFinished((Creature) player, phase);
+ } else {
+ response = traqueHasFinished((Traque) player, phase);
+
+ }
+ }
+ else {
+ return new Response(false, "The current phase is " + state);
+ }
+ if(response.isState()) {
+ playerFinishedPhase(player, phase);
+ }
+ return response;
+ }
+
+ public Response creatureHasFinished(Creature creature, Phase phase) {
+ if (phase.equals(Phase.PHASE_2) && creature.jetonsPlayedIsEmpty()) {
+ return new Response(false, "You must to place at least one jeton");
+ }
+ else{
+ boolean thereIsPowerToApplied = false;
+ for(TrackingCard card : creature.getTrackingCardToApplied()) {
+ if(card.getPhaseToApply().equals(phase)) {
+ thereIsPowerToApplied = true;
+ }
+ }
+ if(thereIsPowerToApplied){
+ return new Response(false, "You must to applied card's power");
+ }
+ else {
+ return new Response(true, "");
+ }
+ }
+ }
+
+ public Response traqueHasFinished(Traque traque, Phase phase) {
+ if(phase.equals(Phase.PHASE_1) && traque.placeCardPlayedIsEmpty()) {
+ return new Response(false, "You must play a place card");
+ }
+ else{
+ boolean thereIsPowerToApplied = false;
+ for(SurvivalCard card : traque.getSurvivalCardsToApplied()) {
+ if(card.getPhaseToApply().equals(phase)) {
+ thereIsPowerToApplied = true;
+ }
+ }
+ if(thereIsPowerToApplied){
+ return new Response(false, "You must to applied card's power");
+ }
+ else {
+ return new Response(true, "");
+ }
+ }
+ }
+
+ public void playerFinishedPhase(Player player, Phase phase) {
+ player.setCurrentPhase(nextPhase(phase));
+ if(allPlayersHasFinishedCurrentPhase()) {
+ startNextPhase();
+ }
+ }
+
+ @Override
+ public Response playerPlayCard(int playerId, Card card) {
+ Response response;
+ Player player = playersMap.get(playerId);
+ switch (state) {
+ case PREPHASE_1:
+ case POSTPHASE_1:
+ case PREPHASE_2:
+ case POSTPHASE_2:
+ case PREPHASE_3:
+ case POSTPHASE_3:
+ case PREPHASE_4:
+ case POSTPHASE_4:
+ response = playerPlayPlayerCard(player, card);
+ break;
+ case PHASE_1:
+ if(player.teamEqualsTo(TRAQUE)) {
+ try {
+ PlaceCard placeCard = (PlaceCard) card;
+ Traque traque = (Traque) player;
+ response = traquePlayPlaceCard(traque, placeCard);
+ }
+ catch (Exception e){
+ response = new Response(false, "Need a place card");
+ }
+ }
+ else{
+ response = new Response(false, "No card authorize in this phase");
+ }
+ break;
+ case PHASE_2:
+ case PHASE_3:
+ case PHASE_4:
+ default:
+ response = new Response(false, "No card authorize in this phase");
+ }
+ return response;
+ }
+
+ @Override
+ public Response playerPlayCard(int playerId, List cards) {
+ Response response;
+ Player player = playersMap.get(playerId);
+ switch (state) {
+ case PHASE_1:
+ if(player.getTeam().equals(TRAQUE)) {
+ try {
+ List placeCards = cards.stream().map(c -> (PlaceCard) c).collect(Collectors.toList());
+ Traque traque= (Traque) player;
+ response = traquePlayPlaceCard(traque, placeCards);
+ }
+ catch (Exception e){
+ response = new Response(false, "Need only place card");
+ }
+ }
+ else{
+ response = new Response(false, "No card authorize in this phase");
+ }
+ break;
+ case PREPHASE_1:
+ case POSTPHASE_1:
+ case PREPHASE_2:
+ case POSTPHASE_2:
+ case PREPHASE_3:
+ case POSTPHASE_3:
+ case PREPHASE_4:
+ case POSTPHASE_4:
+ response = playerPlayPlayerCard(player, cards);
+ break;
+ case PHASE_2:
+ case PHASE_3:
+ case PHASE_4:
+ default:
+ response = new Response(false, "No card authorize in this phase");
+ }
+ return response;
+ }
+
+ @Override
+ public Response playerPlaceJeton(int playerId, PlacedJeton placedJeton) {
+ Response response;
+ Player player = playersMap.get(playerId);
+ if(player.teamEqualsTo(TRAQUE)){
+ response = new Response(false, "Only the Creature can played jeton");
+ }
+ else if(! state.equals(Phase.PHASE_2)) {
+ if(gameRoundVariables.isJetonCibleBlockPlace() && placedJeton.getJetonSymbol().equals(CIBLE)) {
+ response = creaturePlaceAJeton(creature, placedJeton);
+ }
+ else {
+ response = new Response(false, "You can play jeton only in Phase 2");
+ }
+ }
+ else if(gameRoundVariables.refugeIsActive() && isJetonCibleOnThisPlace(placedJeton.getPlaces())) {
+ response = new Response(false, "Can't play JetonCible when Refuge is active");
+ }
+ else{
+ response = creaturePlaceAJeton(creature, placedJeton);
+ }
+ return response;
+ }
+
+ @Override
+ public Response playerPlaceJeton(int playerId, List jetons) {
+ Player player = playersMap.get(playerId);
+ Response response;
+ if(player.teamEqualsTo(TRAQUE)){
+ response = new Response(false, "Only the Creature can played jetons");
+ }
+ else {
+ boolean canPlaceAllJetons = true;
+ for (PlacedJeton placedJeton : jetons) {
+ canPlaceAllJetons = canPlaceAllJetons && playerPlaceJeton(playerId, placedJeton).isState();
+ }
+ if (!canPlaceAllJetons) {
+ creature.initializationJeton();
+ response = new Response(false, "Invalid action");
+ }
+ else{
+ response = new Response(true, "");
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public Response playerResist(int playerId, int number) {
+ Player player = playersMap.get(playerId);
+ Response response;
+ if(! gameRoundVariables.traqueCanResist()) {
+ response = new Response(false, "You can't resist for this round");
+ }
+ else if(player.teamEqualsTo(CREATURE)) {
+ response = new Response(false, "Only traque can resist");
+ }
+ else{
+ Traque traque = (Traque) player;
+ if(number < 1 || number > 2) {
+ response = new Response(false, "Number must be 1 or 2");
+ }
+ else if(! state.equals(Phase.PHASE_1)){
+ response = new Response(false, "Resist is only possible in PHASE_1");
+ }
+ else if(traque.getNumberWillingness() >= number && traque.canResist()) {
+ traque.subWillingness(number);
+ int cardsPerWillingness = 2 + traque.getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist();
+ int numberCard = Math.min(cardsPerWillingness * number, traque.defausseSize());
+ if(numberCard > 0) {
+ List chosen = choosePlaceCardsAction(playerId, numberCard, traque.getDefausse());
+ traque.takeBackPlaceCard(chosen);
+ }
+ traque.getRights().setCanGiveUp(false);
+ traque.getRights().setCanResist(false);
+ gameRoundVariables.addPlayersWhoHaveResist(traque.getInGameId());
+ response = new Response(true, "");
+ }
+ else{
+ response = new Response(false, "You can't resist");
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public Response playerGiveUp(int playerId) {
+ Player player = playersMap.get(playerId);
+ Response response;
+ if(player.teamEqualsTo(CREATURE)) {
+ response = new Response(false, "Only traque can resist");
+ }
+ else{
+ Traque traque = (Traque) player;
+ if(! state.equals(Phase.PHASE_1)){
+ response = new Response(false, "Give up is only possible in PHASE_1");
+ }
+ else if(traque.canGiveUp()) {
+ traque.fillWillingness();
+ traque.takeBackAllPlaceCardFromDefausse();
+ traque.setCanGiveUp(false);
+ traque.setCanResist(false);
+ board.moveForwardCreature();
+ response = new Response(true, "");
+ }
+ else{
+ response = new Response(false, "You can't resist");
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public Action askAction(int inGameIdPlayer, TAskAction askedAction) {
+ try{
+ return room.askAction(inGameIdPlayer, askedAction);
+ }
+ catch (Exception e){
+ throw new IllegalArgumentException("Unknown error");
+ }
+ }
+
+ @Override
+ public void sendAction(int inGameIdPlayer, TAskAction askedAction) {
+ try {
+ room.sendAction(inGameIdPlayer, askedAction);
+ } catch (TException e) {
+ throw new IllegalArgumentException("Unknown error");
+ }
+ }
+
+ @Override
+ public void sendFirstRoundStart() {
+ try {
+ room.sendFirstRoundStart();
+ } catch (TException e) {
+ throw new IllegalArgumentException("Unknown error");
+ }
+ }
+
+ @Override
+ public void sendStartPhase() {
+ for(Integer id : playersMap.keySet()) {
+ try {
+ room.sendStartPhase(id, new TPhase(state.toString()),createDescription(id));
+ } catch (TException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void sendDescription() {
+ for(Integer id : playersMap.keySet()) {
+ try {
+ room.sendDescription(id, createDescription(id));
+ } catch (TException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void sendGameIsFinished() {
+ TPlayerTeam winner = new TPlayerTeam(board.winner().toString());
+ try {
+ room.sendGameIsFinished(winner);
+ } catch (TException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /*************************************
+ * Player play card
+ *************************************/
+
+ /**
+ * A player play a survival card or a tracking card
+ * @param player The player
+ * @param card The player card
+ * @return A Response
+ */
+ public Response playerPlayPlayerCard(Player player, Card card) {
+ Response response;
+ if(player.teamEqualsTo(TRAQUE)) {
+ try {
+ SurvivalCard survivalCard = (SurvivalCard) card;
+ Traque traque = (Traque) player;
+ response = traquePlaySurvivalCard(traque, survivalCard);
+ }
+ catch (Exception e){
+ response = new Response(false, "Need a survival card");
+ }
+ }
+ else{
+ try {
+ TrackingCard trackingCard = (TrackingCard) card;
+ response = creaturePlayTrackingCard(creature, trackingCard);
+ }
+ catch (Exception e){
+ response = new Response(false, "Need a tracking card");
+ }
+ }
+ return response;
+ }
+
+ /**
+ * A player play survival cards or tracking cards
+ * @param player The player
+ * @param cards The player cards
+ * @return A Response
+ */
+ public Response playerPlayPlayerCard(Player player, List cards) {
+ Response response;
+ if(player.teamEqualsTo(TRAQUE)) {
+ try {
+ List survivalCards = cards.stream().map(c -> (SurvivalCard) c).collect(Collectors.toList());
+ Traque traque = (Traque) player;
+ response = traquePlaySurvivalCard(traque, survivalCards);
+ }
+ catch (Exception e){
+ response = new Response(false, "Need a survival card");
+ }
+ }
+ else{
+ try {
+ List trackingCards = cards.stream().map(c -> (TrackingCard) c).collect(Collectors.toList());
+ response = creaturePlayTrackingCard(creature, trackingCards);
+ }
+ catch (Exception e){
+ response = new Response(false, "Need a tracking card");
+ }
+ }
+ return response;
+ }
+
+
+ /**
+ * The creature play a tracking card
+ * @param creature The creature
+ * @param trackingCard The tracking card
+ * @return A Response
+ */
+ public Response creaturePlayTrackingCard(Creature creature, TrackingCard trackingCard) {
+ boolean canPlay = creatureCanPlayThisTrackingCards(creature, trackingCard);
+ if(canPlay){
+ if(creature.getTrackingCardToApplied().contains(trackingCard)
+ || creature.playTrackingCard(trackingCard)) {
+ applyCreaturePlayTrackingCard(creature, trackingCard);
+ return new Response(true, "");
+ }
+ else{
+ return new Response(false, "Unable to play this card");
+ }
+ }
+ else{
+ return new Response(false, "Unable to play this card");
+ }
+ }
+
+ /**
+ * The creature play tracking cards
+ * @param creature The creature
+ * @param trackingCards The tracking cards
+ * @return A Response
+ */
+ public Response creaturePlayTrackingCard(Creature creature, List trackingCards) {
+ boolean canPlay = creatureCanPlayThisTrackingCards(creature, trackingCards);
+ if(canPlay) {
+ for(TrackingCard trackingCard : trackingCards){
+ creatureCanPlayThisTrackingCards(creature, trackingCard);
+ }
+ return new Response(true, "");
+ }
+ else{
+ return new Response(false, "Unable to play this card");
+ }
+ }
+
+ /**
+ * Play the card and/or apply its power
+ * @param creature The creature
+ * @param trackingCard The card
+ */
+ private void applyCreaturePlayTrackingCard(Creature creature, TrackingCard trackingCard) {
+ Phase toApplied = trackingCard.getPhaseToApply();
+ if(toApplied.equals(state)) {
+ creature.removeTrackingCardToApplied(trackingCard);
+ applyPlayerCard(this, creature.getInGameId(), trackingCard);
+ trackingCardPioche.throwAway(trackingCard);
+ }
+ else {
+ creature.addTrackingCardToApplied(trackingCard);
+ }
+ }
+
+ public boolean creatureCanPlayThisTrackingCards(Creature creature, TrackingCard trackingCard) {
+ if(gameRoundVariables.refugeIsActive() && trackingCard.containsSymbol(CIBLE)) {
+ return false;
+ }
+ if(! gameRoundVariables.canPlayTrackingCard()) {
+ return false;
+ }
+ else if(creature.getTrackingCardToApplied().contains(trackingCard) && state.equals(trackingCard.getPhaseToApply())) {
+ return true;
+ }
+ else{
+ boolean canPlay = creature.getHand().trackingCardPlayedSize() < creature.getMaxTrackingCardPlayable()
+ && state.equals(trackingCard.getPhase());
+ return canPlay && creature.getTrackingCardHand().contains(trackingCard);
+ }
+ }
+
+ public boolean creatureCanPlayThisTrackingCards(Creature creature, List trackingCards) {
+ if(! gameRoundVariables.canPlayTrackingCard()) {
+ return false;
+ }
+ Iterator iterator = trackingCards.iterator();
+ boolean canPlay = true;
+ List toPlay = new ArrayList<>();
+ TrackingCard trackingCard;
+ while (canPlay && iterator.hasNext()) {
+ trackingCard = iterator.next();
+ if(! creature.getTrackingCardToApplied().contains(trackingCard)) {
+ toPlay.add(trackingCard);
+ }
+ if(! creatureCanPlayThisTrackingCards(creature, trackingCard)) {
+ canPlay = false;
+ }
+ }
+ canPlay = canPlay && creature.getHand().trackingCardPlayedSize() + toPlay.size() <= creature.getMaxTrackingCardPlayable();
+ return canPlay && creature.getTrackingCardHand().containsAll(toPlay);
+ }
+
+ /**
+ * A Traque play a SurvivalCard
+ * @param traque The Traque
+ * @param survivalCard The SurvivalCard
+ * @return A Response
+ */
+ public Response traquePlaySurvivalCard(Traque traque, SurvivalCard survivalCard) {
+ if(traqueCanPlayThisSurvivalCards(traque, survivalCard) &&
+ traque.playSurvivalCard(survivalCard)) {
+ applyTraquePlaySurvivalCard(traque, survivalCard);
+ return new Response(true, "");
+ }
+ else{
+ return new Response(false, "Unable to play this card");
+ }
+ }
+
+ /**
+ * A Traque play survival cards
+ * @param traque The traque
+ * @param survivalCards The survival cards
+ * @return A Response
+ */
+ public Response traquePlaySurvivalCard(Traque traque, List survivalCards) {
+ if(traqueCanPlayThisSurvivalCards(traque, survivalCards) &&
+ traque.playSurvivalCard(survivalCards)) {
+ for(SurvivalCard survivalCard : survivalCards){
+ applyTraquePlaySurvivalCard(traque, survivalCard);
+ }
+ return new Response(true, "");
+ }
+ else{
+ return new Response(false, "Unable to play this card");
+ }
+ }
+
+ /**
+ * Play the card and/or apply its power
+ * @param traque The traque
+ * @param survivalCard The card
+ */
+ private void applyTraquePlaySurvivalCard(Traque traque, SurvivalCard survivalCard) {
+ if(playerCardsPlayedPhaseAndAppliedPhaseDifferent(survivalCard)) {
+ if(state.equals(survivalCard.getPhase())){
+ traque.playSurvivalCard(survivalCard);
+ traque.addSurvivalCardToApplied(survivalCard);
+ }
+ else{
+ applyPlayerCard(this, traque.getInGameId(), survivalCard);
+ traque.removeSurvivalCardToApplied(survivalCard);
+ survivalCardPioche.throwAway(survivalCard);
+ }
+ }
+ else{
+ applyPlayerCard(this, traque.getInGameId(), survivalCard);
+ traque.playSurvivalCard(survivalCard);
+ survivalCardPioche.throwAway(survivalCard);
+ }
+ }
+
+ public boolean traqueCanPlayThisSurvivalCards(Traque traque, SurvivalCard survivalCard) {
+ //if the card doesn't apply himself in the same phase that it's played
+ if(playerCardsPlayedPhaseAndAppliedPhaseDifferent(survivalCard)) {
+ //true if the card can to be played or can to be applied
+ return (traque.getHand().survivalCardPlayedSize() < traque.getMaxSurvivalCardPlayable() && state.equals(survivalCard.getPhase()))
+ || (state.equals(survivalCard.getPhaseToApply()) && traque.getSurvivalCardsPlayed().contains(survivalCard));
+ }
+ else{
+ //true if the card can to be played
+ return traque.getHand().survivalCardPlayedSize() < traque.getMaxSurvivalCardPlayable() && state.equals(survivalCard.getPhase());
+ }
+ }
+
+ public boolean traqueCanPlayThisSurvivalCards(Traque traque, List survivalCards) {
+ int numberCardPlayed = 0;
+ //Count the number of played cards
+ for(SurvivalCard survivalCard : survivalCards) {
+ if(!playerCardsPlayedPhaseAndAppliedPhaseDifferent(survivalCard)) {
+ ++numberCardPlayed;
+ }
+ }
+ if(traque.getHand().survivalCardPlayedSize() + numberCardPlayed > traque.getMaxSurvivalCardPlayable()){
+ return false;
+ }
+ boolean aux = true;
+ for(SurvivalCard survivalCard : survivalCards) {
+ aux = aux && traqueCanPlayThisSurvivalCards(traque, survivalCard);
+ }
+ return aux;
+ }
+
+ /**
+ * A traque play a place card
+ * @param traque The traque
+ * @param placeCard The place card
+ * @return A Response
+ */
+ public Response traquePlayPlaceCard(Traque traque, PlaceCard placeCard) {
+ Response response;
+ if(!planet.isRevealedPlace(placeCard)) {
+ response = new Response(false, "The place must be revealed");
+ }
+ else if(planet.isBlockedPlace(placeCard) ||
+ (gameRoundVariables.isJetonCibleBlockPlace() && planet.isJetonSymbolOnPlaceCard(CIBLE, placeCard))) {
+ response = new Response(false, "The place is blocked");
+ }
+ else if(traque.placeCardPlayedSize() < traque.getMaxPlacesCardChoosable() && traque.playPlaceCard(placeCard)) {
+ response = new Response(true, "");
+ }
+ else{
+ response = new Response(false, "Unable to play this card");
+ }
+ return response;
+ }
+
+ /**
+ * A traque play place cards
+ * @param traque The traque
+ * @param placeCards The place cards
+ * @return A Response
+ */
+ public Response traquePlayPlaceCard(Traque traque, List placeCards) {
+ if(traque.placeCardPlayedSize() + placeCards.size() <= traque.getMaxPlacesCardChoosable() &&
+ traque.playPlaceCard(placeCards)) {
+ return new Response(true, "");
+ }
+ else{
+ return new Response(false, "Unable to play this card");
+ }
+
+ }
+
+ public boolean playerCardsPlayedPhaseAndAppliedPhaseDifferent(PlayerCard playerCard) {
+ return ! playerCard.getPhase().equals(playerCard.getPhaseToApply());
+ }
+
+ /*************************************
+ * Creature place jetons
+ *************************************/
+
+ public Response creaturePlaceAJeton(Creature creature, PlacedJeton placedJeton) {
+ List trackingCards = creature.getTrackingCardsPlayed();
+ boolean containsJetonCible = false;
+ boolean containsJetonArtemia = false;
+ boolean canPlaceOn6To10 = gameRoundVariables.canPlaceJetonCreatureOnPlaces6To10();
+ boolean placeBetween6To10 = false;
+
+ for(TrackingCard trackingCard : trackingCards) {
+ if(trackingCard.containsSymbol(CIBLE)){
+ containsJetonCible = true;
+ }
+ if(trackingCard.containsSymbol(ARTEMIA)){
+ containsJetonArtemia = true;
+ }
+ }
+
+ JetonSymbol symbol = placedJeton.getJetonSymbol();
+
+ if(placedJeton.getPlaces().size() > 1) {
+ if(symbol.equals(JetonSymbol.CIBLE) && !gameRoundVariables.jetonCibleCanBeOnTwoAdjacentPlaces()) {
+ return new Response(false, "JetonCible can't be place on two adjacent places");
+ }
+ else if(symbol.equals(ARTEMIA) && !gameRoundVariables.jetonArtemiaCanBeOnTwoAdjacentPlaces()) {
+ return new Response(false, "JetonArtemia can't be place on two adjacent places");
+ }
+ else if(symbol.equals(JetonSymbol.CREATURE) && !gameRoundVariables.jetonCreatureCanBeOnTwoAdjacentPlaces()) {
+ return new Response(false, "JetonCreature can't be place on two adjacent places");
+ }
+ }
+ for(Place place : placedJeton.getPlaces()) {
+ if(Planet.placeToNumber(place) >= 6) {
+ placeBetween6To10 = true;
+ }
+ }
+ if( (symbol.equals(CIBLE) && containsJetonCible)
+ || (symbol.equals(ARTEMIA) && (containsJetonArtemia || board.isArtemiaSquare()))
+ || symbol.equals(JetonSymbol.CREATURE) && (canPlaceOn6To10 || !placeBetween6To10)) {
+ if(planet.placeJeton(placedJeton)) {
+ creature.playJeton(placedJeton.getJetonSymbol());
+ return new Response(true, "");
+ }
+ else {
+ return new Response(false, "Impossible action");
+ }
+ }
+ else {
+ return new Response(false, "Invalid jeton");
+ }
+ }
+
+ /*************************************
+ * Phase management methods
+ ***********************************/
+
+ public Phase nextPhase(Phase phase) {
+ switch (phase) {
+ case PREPHASE_1:
+ return Phase.PHASE_1;
+ case PHASE_1:
+ return Phase.POSTPHASE_1;
+ case POSTPHASE_1:
+ return Phase.PREPHASE_2;
+ case PREPHASE_2:
+ return Phase.PHASE_2;
+ case PHASE_2:
+ return Phase.POSTPHASE_2;
+ case POSTPHASE_2:
+ return Phase.PREPHASE_3;
+ case PREPHASE_3:
+ return Phase.PHASE_3;
+ case PHASE_3:
+ return Phase.POSTPHASE_3;
+ case POSTPHASE_3:
+ return Phase.PREPHASE_4;
+ case PREPHASE_4:
+ return Phase.PHASE_4;
+ case PHASE_4:
+ return Phase.POSTPHASE_4;
+ case POSTPHASE_4:
+ return Phase.PREPHASE_1;
+ default:
+ throw new IllegalArgumentException(phase + " is not a valid phase");
+ }
+ }
+
+ public boolean allPlayersHasFinishedCurrentPhase(){
+ boolean res = true;
+ Phase nextPhase = nextPhase(state);
+ Iterator> iterator = playersMap.entrySet().iterator();
+ while(res && iterator.hasNext()) {
+ if(! nextPhase.equals(iterator.next().getValue().getCurrentPhase())) {
+ res = false;
+ }
+ }
+ return res;
+ }
+
+ public void startNextPhase() {
+ state = nextPhase(state);
+ sendStartPhase();
+ if(state.equals(Phase.PHASE_3)) {
+ managePhase3();
+ }
+ else if(state.equals(Phase.PHASE_4)) {
+ managePhase4();
+ }
+ else if(state.equals(Phase.PREPHASE_1)) {
+ nextRound();
+ }
+ else if(state.equals(Phase.PREPHASE_3)){
+ if(PowerApplicator.checkInertieCondition(this)){
+ planet.blockPlaces(Arrays.asList(Place.values()));
+ }
+ }
+ }
+
+ public void managePhase3() {
+ List chosenPlaceCards;
+ for(Traque traque : traques) {
+ chosenPlaceCards = choosePlaceCardsToReveal(traque);
+ for(PlaceCard placeCard : chosenPlaceCards) {
+ resolvePlace(this, traque.getInGameId(), placeCard);
+ }
+ sendDescription();
+ }
+ }
+
+ private List choosePlaceCardsToReveal(Traque traque) {
+ List placeCardsPlayed = new ArrayList<>(traque.getPlaceCardsPlayed());
+ List chosenPlaceCards = placeCardsPlayed;
+ //if player plays too many cards
+ if(placeCardsPlayed.size() > traque.getMaxPlacesCardPlayable()) {
+ chosenPlaceCards = choosePlaceCardsAction(traque.getInGameId(), traque.getMaxPlacesCardPlayable(), placeCardsPlayed);
+ for(PlaceCard placeCard : placeCardsPlayed) {
+ if(! chosenPlaceCards.contains(placeCard)) {
+ if(gameRoundVariables.getPlayersWhoHavePlayCavale().contains(traque.getInGameId())
+ || gameRoundVariables.getplayersWhoUseFjordInPreviousRound().contains(traque.getInGameId())) {
+ traque.throwAwayPlaceCard(placeCard);
+ }
+ else {
+ //put back non-played cards in the hand
+ traque.takeBackPlaceCard(placeCard);
+ }
+ }
+ }
+ }
+ return chosenPlaceCards;
+ }
+
+ public void managePhase4() {
+ for(Traque traque : traques) {
+ if(gameRoundVariables.getPlayersWhoHavePlayCavale().contains(traque.getInGameId())
+ || gameRoundVariables.getPlayersWhoHavePlayVolteFace().contains(traque.getInGameId())) {
+ traque.takeBackPlayedPlaceCards();
+ }
+ else if(gameRoundVariables.ralliementIsActive() && gameRoundVariables.getPlayersWhoHasCaughtByCreature().contains(traque.getInGameId())) {
+ List placeCardsWhereIsJetonCreature = planet.findPlaceCardsWhereJetonIs(JetonSymbol.CREATURE);
+ traque.takeBackPlaceCard(placeCardsWhereIsJetonCreature);
+ traque.throwAwayPlaceCard();
+ }
+ else{
+ traque.throwAwayPlaceCard();
+ }
+ }
+ creature.initializationJeton();
+ int numberTrackingCardToDraw = creature.getMaxTrackingCards() - creature.trackingCardHandSize();
+ creature.addTrackingCard(trackingCardPioche.draw(numberTrackingCardToDraw));
+ sendDescription();
+ }
+
+ public void nextRound() {
+ if(gameRoundVariables.rescuePawnCanMoveForward()){
+ board.moveForwardTraque(gameRoundVariables.getIncrementScoreTraque());
+ if(gameRoundVariables.isPawnWillingnessOnBoard()) {
+ useWillingnessOnBoard();
+ }
+ }
+ if(isFinish()) {
+ sendGameIsFinished();
+ }
+ else{
+ gameRoundVariables.reset();
+ planet.reset();
+ for(Traque t : traques) {
+ t.reset();
+ }
+ creature.reset();
+ applyNextRoundPowers();
+ gameRoundVariables.resetAfterNextRoundPowersApplication();
+ }
+ }
+
+ /**
+ * Apply the next round powers and clear them
+ */
+ private void applyNextRoundPowers() {
+ List newNextRoundPowers = new ArrayList<>();
+ for(Power power : nextRoundPowers) {
+ if(power.getType().equals(PowerType.MODIFICATOR)) {
+ applyModificatorPower((PowerModifier) power);
+ }
+ else if(power.getType().equals(PowerType.RECURRENT)) {
+ PowerRecurrent powerRecurrent = (PowerRecurrent) power;
+ if(powerRecurrent.conditionIsTrue(this)) {
+ newNextRoundPowers.add(power);
+ powerRecurrent.apply(this);
+ }
+ }
+ }
+ nextRoundPowers = newNextRoundPowers;
+ }
+
+ /**
+ * Apply a power modificator
+ */
+ private void applyModificatorPower(PowerModifier power) {
+ PowerModifierType type = power.getModificatorType();
+ Player player = getPlayer(power.getInGameIdPlayer());
+ if(player.getTeam().equals(CREATURE)) {
+ if(type.equals(PowerModifierType.PLAYABLE_TRACKING_CARD)) {
+ creature.getRights().setMaxTrackingCardPlayable((int) power.getModifiedValue());
+ }
+ }
+ else{
+ Traque traque = (Traque) player;
+ switch (type) {
+ case PLAYABLE_PLACE_CARD:
+ traque.setMaxPlacesCardPlayable((int)power.getModifiedValue());
+ break;
+ case CHOOSABLE_PLACE_CARD:
+ traque.setMaxPlacesCardChoosable((int)power.getModifiedValue());
+ break;
+ case CHOOSABLE_VISIBLE_ADDITIONAL_PLACE_CARD:
+ int tmp = traque.getMaxPlacesCardChoosable() + ((int)power.getModifiedValue());
+ traque.setMaxPlacesCardChoosable(tmp);
+ traque.setPlaceCardsVisible(((int)power.getModifiedValue()));
+ break;
+ case USE_FJORD_IN_PREVIOUS_ROUND:
+ gameRoundVariables.addplayersWhoUseFjordInPreviousRound(traque.getInGameId());
+ default:
+ }
+ }
+ }
+
+ /**
+ * Use willingness on board and give one willingness to the traque with the least willingness
+ */
+ private void useWillingnessOnBoard() {
+ gameRoundVariables.usePawnWillingnessOnBoard();
+ Traque traqueWithTheLeastOfWillingness = traques.get(0);
+ int minWillingness = traqueWithTheLeastOfWillingness.getNumberWillingness();
+ for(Traque traque : traques) {
+ if(traque.getNumberWillingness() < minWillingness) {
+ minWillingness = traque.getNumberWillingness();
+ traqueWithTheLeastOfWillingness = traque;
+ }
+ }
+ traqueWithTheLeastOfWillingness.addWillingness(1);
+ }
+
+ /*************************************
+ * Choose action methods
+ ***********************************/
+
+ public List choosePlaceCardsAction(int idPlayer, int max, List placesCards) {
+ List cardList = new ArrayList<>(placesCards);
+ List cards = null;
+ boolean validChoice = false;
+ do {
+ try {
+ cards = chooseCardsAction(idPlayer, max, cardList).stream()
+ .map(c -> (PlaceCard) c)
+ .collect(Collectors.toList());
+ validChoice = true;
+ }
+ catch (Exception e){
+ //Bad Card type
+ }
+ }
+ while (!validChoice);
+ return cards;
+ }
+
+ public List chooseSurvivalCardsAction(int idPlayer, int max, List survivalCards) {
+ List cardList = new ArrayList<>(survivalCards);
+ List cards = null;
+ boolean validChoice = false;
+ do {
+ try {
+ cards = chooseCardsAction(idPlayer, max, cardList).stream()
+ .map(c -> (SurvivalCard) c)
+ .collect(Collectors.toList());
+ validChoice = true;
+ }
+ catch (Exception e){
+ //Bad Card type
+ }
+ }
+ while (!validChoice);
+ return cards;
+ }
+
+ public List chooseTrackingCardsAction(int idPlayer, int max, List trackingCards) {
+ List cardList = new ArrayList<>(trackingCards);
+ List cards = null;
+ boolean validChoice = false;
+ do {
+ try {
+ cards = chooseCardsAction(idPlayer, max, cardList).stream()
+ .map(c -> (TrackingCard) c)
+ .collect(Collectors.toList());
+ validChoice = true;
+ }
+ catch (Exception e){
+ //Bad Card type
+ }
+ }
+ while (!validChoice);
+ return cards;
+ }
+
+ public List chooseCardsAction(int idPlayer, int max, List cardsToChoose) {
+ TAskAction askAction = createTActionForChooseCardsAction(max, cardsToChoose);
+ List cards = new ArrayList<>();
+ List cardNames;
+ Action action;
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(ActionType.CHOOSE_CARD)) {
+ cardNames = ((ActionChooseCard) action).getCards();
+ cards = computeCardListFromCardNames(cardNames, cardsToChoose);
+ }
+ } while (cards.isEmpty() || cards.size() > max);
+ return cards;
+ }
+
+ private TAskAction createTActionForChooseCardsAction(int max, List cardsToChoose){
+ List params = new ArrayList<>();
+ params.add(new TPair("number", ""+ max));
+ for(int i = 0 ; i < cardsToChoose.size() ; ++i) {
+ params.add(new TPair("" + (i+1), cardsToChoose.get(i).getCardName().toString()));
+ }
+ String message = "Choose a maximum of " + max + "cards";
+ return new TAskAction(CHOOSE_CARD.toString(), message, params);
+ }
+ public void sendPlaceCardsAction(int idPlayer, List cardsToShow) {
+ List cards = new ArrayList<>(cardsToShow);
+ sendCardsAction(idPlayer, cards);
+ }
+
+ public void sendCardsAction(int idPlayer, List cardsToShow) {
+ TAskAction askAction = createTActionForSendCardsAction(cardsToShow);
+ sendAction(idPlayer, askAction);
+ }
+
+ private TAskAction createTActionForSendCardsAction(List cardsToShow){
+ List params = new ArrayList<>();
+ for(int i = 0 ; i < cardsToShow.size() ; ++i) {
+ params.add(new TPair("" + (i+1), cardsToShow.get(i).getCardName().toString()));
+ }
+ String message = "";
+ return new TAskAction(SHOW_CARD.toString(), message, params);
+ }
+
+ private List computeCardListFromCardNames(List cardNames, List cardsToChoose){
+ List chosenCards = new ArrayList<>();
+ for(Card card : cardsToChoose){
+ if(cardNames.contains(card.getCardName())){
+ chosenCards.add(card);
+ }
+ }
+ return chosenCards;
+ }
+
+ public int choosePower(int idPlayer, List powersDescription) {
+ List params = new ArrayList<>();
+ String number;
+ for(int i = 0 ; i < powersDescription.size() ; ++i){
+ number = "" + (i+1);
+ params.add(new TPair(number, powersDescription.get(i)));
+ }
+ String message = "Choose a power";
+ TAskAction askAction = new TAskAction(CHOOSE_POWER.toString(), message, params);
+ int idPower = -1;
+ Action action;
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(CHOOSE_POWER)) {
+ idPower = ((ActionChoosePower) action).getIdPowerChosen();
+ }
+ } while (idPower < 0 || idPower >= powersDescription.size());
+ return idPower;
+ }
+
+ public int targetPlayer(int idPlayer) {
+ String message = "Choose one traque";
+ TAskAction askAction = new TAskAction(TARGET_PLAYER.toString(), message, new ArrayList<>());
+ int idTargetPlayer = -1;
+ Action action;
+ Set playersIdList = playersMap.keySet();
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(TARGET_PLAYER)) {
+ idTargetPlayer = ((ActionTargetPlayer) action).getIdPlayer();
+ }
+ } while(! playersIdList.contains(idTargetPlayer) || creature.getInGameId() == idTargetPlayer);
+ return idTargetPlayer;
+ }
+
+ public List choosePlace(int idPlayer, int number) {
+ String message = number > 1 ? "Choose" + number + " places" : "Choose 1 place";
+ return choosePlace(idPlayer, number, message);
+ }
+
+ public List choosePlace(int idPlayer, int number, String message) {
+ if(number <= 0 || number > 10) {
+ throw new IllegalArgumentException("number must be between 1 and 10");
+ }
+ List params = new ArrayList<>();
+ params.add(new TPair("number", number+""));
+ TAskAction askAction = new TAskAction(CHOOSE_PLACE.toString(), message, params);
+ List places = new ArrayList<>();
+ Action action;
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(CHOOSE_PLACE)) {
+ places = ((ActionChoosePlace) action).getPlaces();
+ }
+ } while(places.size() != number);
+ return places;
+ }
+
+ public Pair movePlayer(int idPlayer) {
+ String message = "Move one traque";
+ TAskAction askAction = new TAskAction(MOVE_PLAYER.toString(), message, new ArrayList<>());
+ int idTargetPlayer = -1;
+ Place place = null;
+ Action action;
+ ActionMovePlayer actionMovePlayer;
+ Set playersIdList = playersMap.keySet();
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(MOVE_PLAYER)) {
+ actionMovePlayer = (ActionMovePlayer) action;
+ idTargetPlayer = actionMovePlayer.getIdPlayer();
+ place = actionMovePlayer.getPlace();
+ }
+ } while(! playersIdList.contains(idTargetPlayer) && creature.getInGameId() == idTargetPlayer);
+ return new Pair<>(idTargetPlayer, place);
+ }
+
+ public Pair swapJetons(int idPlayer) {
+ TAskAction askAction = new TAskAction(MOVE_PLAYER.toString(), "", new ArrayList<>());
+ JetonSymbol symbol1 = null;
+ JetonSymbol symbol2 = null;
+ Action action;
+ ActionSwapJeton actionSwapJeton;
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(SWAP_JETONS)) {
+ actionSwapJeton = (ActionSwapJeton) action;
+ symbol1 = actionSwapJeton.getJetonSymbol1();
+ symbol2 = actionSwapJeton.getJetonSymbol2();
+ }
+ } while(symbol1 == null || symbol2 == null || symbol1 == symbol2);
+ return new Pair<>(symbol1, symbol2);
+ }
+
+ public Map associateCardNamesToPlaces(int idPlayer, List cardsToAssociate) {
+ TAskAction askAction = createTActionForAssociateCardNamesToPlaces(cardsToAssociate);
+ Map cardNamePlaceMap = new HashMap<>();
+ Map auxiliaryMap;
+ Action action;
+ do{
+ action = askAction(idPlayer, askAction);
+ if(action.getActionType().equals(ActionType.ASSOCIATE_CARDNAMES_TO_PLACES)) {
+ auxiliaryMap = ((ActionAssociateCardNamesToPlaces) action).getCardNamePlaceMap();
+ cardNamePlaceMap = computeMapCardToPlaceFromMapCardNamesToPlace(auxiliaryMap, cardsToAssociate);
+ }
+ } while (cardNamePlaceMap.size() != cardsToAssociate.size());
+ return cardNamePlaceMap;
+ }
+
+ private TAskAction createTActionForAssociateCardNamesToPlaces(List cardsToAssociate){
+ List params = new ArrayList<>();
+ for(int i = 0 ; i < cardsToAssociate.size() ; ++i) {
+ params.add(new TPair("" + (i+1), cardsToAssociate.get(i).getCardName().toString()));
+ }
+ String message = "Place the cards";
+ return new TAskAction(ASSOCIATE_CARDNAMES_TO_PLACES.toString(), message, params);
+ }
+
+ private Map computeMapCardToPlaceFromMapCardNamesToPlace(Map cardNamePlaceMap, List cards) {
+ Map map = new HashMap<>();
+ for(Card card : cards){
+ if(cardNamePlaceMap.containsKey(card.getCardName())){
+ map.put(card, cardNamePlaceMap.get(card.getCardName()));
+ }
+ }
+ return map;
+ }
+
+ private boolean isJetonCibleOnThisPlace(List places) {
+ List jetonCiblePlaces = planet.findPlacesWhereJetonIs(CIBLE);
+ Iterator iterator = places.iterator();
+ boolean isJetonCibleOnThisPlace = false;
+ while (!isJetonCibleOnThisPlace && iterator.hasNext()) {
+ if(jetonCiblePlaces.contains(iterator.next())) {
+ isJetonCibleOnThisPlace = true;
+ }
+ }
+ return isJetonCibleOnThisPlace;
+ }
+
+ public TDescription createDescription(int playerId) {
+ Player player = playersMap.getOrDefault(playerId, null);
+ if(player == null) {
+ throw new IllegalArgumentException(playerId + " is not a valid id");
+ }
+ TScore tScore = Conversion.toTScore(board);
+ TPlanet tPlanet = Conversion.toTPlanet(planet);
+ List reserves = Conversion.toTCardReserveList(reserve);
+ List variables = Conversion.toTGameVariable(gameRoundVariables);
+ List