-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 40a3357
Showing
24 changed files
with
13,075 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# GroupMatcher | ||
|
||
The program GroupMatcher is based on Go and helps to allocate persons to | ||
groups while trying to fulfill all the given wishes as good as possible. | ||
The program matches the persons with first, second and third wish into | ||
the groups while taking care of the maximum and minimum size that can be | ||
specified for every group. | ||
|
||
This useful tool was developed as an IT-project by Justus Roßmeier, Christian Obermaier and Max Obermeier. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
\documentclass[a4paper,11pt]{article} | ||
\usepackage{listings} \lstset{numbers=left, numberstyle=\tiny, xleftmargin=30pt} | ||
\usepackage{ucs} | ||
\usepackage[utf8x]{inputenc} | ||
\usepackage[T1]{fontenc} | ||
\usepackage[ngerman]{babel} | ||
\usepackage{graphicx} | ||
\usepackage{geometry} | ||
\usepackage{caption} | ||
\author{Justus~Roßmeier, | ||
Christian~Obermaier, | ||
Max~Obermeier} | ||
\title{GroupMatcher} | ||
\begin{document} | ||
\newgeometry{a4paper, top=20mm} | ||
\begin{center} | ||
\begin{Huge} | ||
Group Matcher \\ | ||
\end{Huge} | ||
\vspace{10pt} | ||
\copyright\ Justus Roßmeier, | ||
Christian Obermaier, | ||
Max Obermeier \\ | ||
\begin{abstract} | ||
\label{sec:introduction} | ||
Das Programm "GroupMatcher" , dass auf Go oder "golang"\ basiert, dient zur Verteilung von Personen auf Gruppen unter berücksichtigung ihrer Wünsche. | ||
Dabei können die Personen, die über Erst-, Zweit- und Drittwahl verfügen, auf eine beliebige Anzahl von Gruppen mit Minimal- und Maximalkapazität verteilt werden. Es wurde im Rahmen eines Q11 Informatik-Projekts von Justus Roßmeier, Christian Obermaier und Max Obermeier entwickelt. Besonderer Dank geht dabei an Herrn Christian Hoffelner, für die Unterstützung und Überprüfung des Programms, sowie an Fabian Müller, für die lateinische Übersetzung. | ||
\end{abstract} | ||
\end{center} | ||
\tableofcontents | ||
\section{Die Benutzeroberfläche} | ||
\label{sec:user-interface} | ||
Das Programm startet einen lokalen Server, der dann über einen beliebigen Browser aufgerufen werden kann, wobei allerdings wegen browserseitig entstehenden Grafikbuggs die Verwendung von Internet Explorer oder Edge vermieden werden sollte. Das Programm verwendet immer den im System festgelegten Standardbrowser, falls jedoch ein anderer Browser als der Standardbrowser bevorzugt wird, kann die URL auch in diesen kopiert werden. | ||
|
||
\subsection{Die Bedienzeile} | ||
\label{ssec:top-bar} | ||
Die Bedienzeile befindet sich am oberen Bildschirmrand, und enthält alle Bedienmöglichkeiten, die im aktuellen Modus verfügbar sind, sowie eine Button zum Beenden des Programms. Dieser ist unbedingt zu tätigen, bevor der Browser-Tab geschlossen wird, da ansonsten das Programm im Hintergrund bis zum nächsten Neustart weiterläuft. \\ \\ | ||
Im normalen Modus enthält die Bedienzeile ansonsten folgende Befehle: | ||
\begin{itemize} | ||
\item Löschen: der gesamte Datensatz wird gelöscht | ||
\item Zurücksetzen: alle bereits verteilten Personen werden wieder aus den Gruppen entfernt | ||
\item Verteilen: für diesen Prozess darf keine Person bereits zugeordnet sein. Er startet den automatischen Verteilungsprozess, und versucht die Personen bestmöglich ihren Wünschen entsprechend den Gruppen zuzuordnen. | ||
\end{itemize} | ||
In allen anderen Modi ist ansonsten nur die Option Zurück vorhanden, welche den Nutzer zum Standartmodus zurückbringt. | ||
|
||
\subsection{Die Randspalte} | ||
\label{ssec:side-bar} | ||
Die Randspalte befindet sich am linken Bildschirmrand. Ganz oben wird die aktuelle Quote zum einen angegeben, aber auch visuell mit einer Halbkreisskala dargestellt. Darunter befindet sich eine Liste aller Gruppen. Klickt man auf eine Gruppe, wird der entsprechende Abschnitt im Hauptfenster angezeigt. Sobald nicht mehr alle Personen unzugeordnet sind, färben sich Gruppen, bei denen die Bestimmungen für Minimal- und Maximalgröße nicht eingehalten wurden rot. Beim automatischen Verteilungsprozess kommt dies zwar nicht vor, allerdings dient es zur besseren Übersicht, wenn man eine Nachverteilung vornehmen will. \\ | ||
Am unteren Ende der Randspalte kann man Zwischen den einzelnen Modi des Programms und den verschiedenen Sprachen wechseln. Der aktive Modus wird dabei blau markiert. Sind alle Modi grau, befindet man sich im Standartmodus. | ||
|
||
\subsection{Benachrichtigungen und Fehlermeldungen} | ||
\label{ssec:errwindow} | ||
Benachrichtigungen und Fehlermeldungen werden rechts unten eingeblendet. Benachrichtigungen sind dabei blau markiert, und verschwinden nach einigen Sekunden, Fehler sind hingegen rot markiert, und verschwinden nicht automatisch, können aber durch einen Klick beseitigt werden. Alle Fehlermeldungen und ihre Bedeutung finden sie im Kapitel Fehlermeldungen. | ||
|
||
|
||
\subsection{Das Hauptfenster} | ||
\label{ssec:main-window} | ||
Das Hauptfenster nimmt den größten Teil der Benutzeroberfläche ein, und ist je nach Modus unterschiedlich gefüllt: | ||
\paragraph{Standartmodus} | ||
Hier werden falls vorhanden zunächst unzugeordnete Personen, und dann die Gruppen mit ihren Mitgliedern in tabellenform aufgelistet. Neben den Gruppennamen werden dabei stets die aktuelle Besetzung, sowie Minimal- und Maximalgrenze angezeigt. \\ | ||
Bei jeder Person werden Erst-, Zweit-, und Drittwunsch angezeigt. Der zugeteilte Wunsch ist dabei Blau gefärbt. Klickt man auf einen grauen Wunsch, wird die Person in diese Gruppe verschoben. Bei den blauen Wünschen befindet sich die Person ja bereits in dieser Gruppe, daher wird sie dann aus dieser entfernt, und ist somit wieder unzugeordnet. \\ | ||
Ist ein Wunsch z.B. durch das entfallen einer Gruppe vom Programm entfernt worden, wird statdessen ein Strich angezeigt. | ||
|
||
\paragraph{Importmodus} | ||
Im Importmodus kann eine Datei im Group Matcher .gm Format eingelesen werden. Dazu muss durch einen Klick auf 'Datei auswählen' im darauffolgenden Dialogfenster die entsprechende Datei gesucht, und dann durch einen Klick auf 'Hochladen' an den Server gesendet werden. | ||
|
||
\paragraph{Exportmodus} | ||
Im Exportmodus ist lediglich ein Dropdown-Menü, dass zum Auswählen des Exportmodus dient, sowie der 'Export' Button verfügbar, der den Exportvorgang startet. Danach wird die Datei im Browser zum Download angeboten, bzw. in Download-Ordner gespeichert. Eine genauere Beschreibung der Exportmodi ist im Kapitel 'Export der Daten' gegeben. | ||
|
||
\paragraph{Bearbeitungsmodus} | ||
Hier befindet sich ein Textfeld, sowie der 'Speichern' Button. Im Textfeld wird, sofern vorhanden, der aktuelle Datensatz im Group Matcher Format angezeigt. Dieser kann dann Bearbeitet werden. Hier kann aber natürlich auch ein neuer erstellt werden. Nach dem Speichern wird der erstellte Datensatz überprüft. Treten keine Fehler auf, kehrt das Programm zum Standartmodus zurück, andernfalls wird der Fehler als Fehlermeldung ausgegeben, und das Textfeld springt zur Zeile, in der der Fehler festgestellt wurde, und färbt deren Zeilennummer rot. | ||
|
||
|
||
\section{Die Quote} | ||
\label{sec:rate} | ||
|
||
Der bestmögliche Wert der Quote ist 1, der Schlechteste die Anzahl der Wünsche, also im Normalfall 3. Die Quote wird berechnet, indem die Summe der Positionen (1, 2, 3, ...) der vergebenen Wünsche durch die Anzahl der bereits zugeteilten Personen geteilt wird. | ||
|
||
\section{Der Verteilungsalgorithmus} | ||
\label{sec:match} | ||
|
||
Da kein Algorithmus für dieses komplexe Problem existiert, der keine endlos lange Rechenzeit hat (bei durchschnittlicher Konfiguration ca. $10^{40}$ Jahre), kann das Programm nur versuchen eine möglichst gute Verteilung zu erreichen. Diese kann zwar die Bestmögliche sein, dies ist aber eher unwarscheinlich. Es wird versucht, durch möglichst intellegente Zuweisungen, eine gute Verteilung zu erreichen. Dabei werden 50 Versuche gestartet, bei denen die Personen unterschiedlich gemischt werden. Danach durchlaufen sie alle den selben Algorithmus, und aufgrund der unterschliedlichen Reihenfolge der Personen entsteht immer ein anderes Ergebnis. Zuletzt wird der beste ausgewählt und angezeigt. | ||
|
||
\section{Einlesen der Daten} | ||
\label{sec:input-from-file} | ||
GroupMatcher unterstützt das Einlesen der Personen- und Gruppendaten aus einer Textdatei. Dabei muss es sich um den Datentyp .txt handeln. Die Datei kann zum Beispiel durch das Exportieren aus einer Excel-Tabelle erzeugt werden. | ||
\subsection{Allgemeine Syntax} | ||
\label{ssec:input-syntax} | ||
Um das korrekte Einlesen zu ermöglichen muss eine strenge Syntax eingehalten werden. Diese ist folgendermaßen aufgebaut: | ||
\begin{lstlisting} | ||
S;MIN;MAX | ||
GRUPPENNAME;MIN;MAX | ||
GRUPPENNAME | ||
GRUPPENNAME | ||
... | ||
P | ||
PERSONENNAME;WUNSCH1;WUNSCH2;WUNSCH3/GRUPPE | ||
PERSONENNAME;WUNSCH1;WUNSCH2 | ||
PERSONENNAME;WUNSCH1;WUNSCH2;WUNSCH3 | ||
... | ||
\end{lstlisting} | ||
\paragraph{Gruppenindikator} | ||
Die erste Zeile muss mit dem Indikator für die Gruppen 'S' beginnen. In der selben Zeile stehen in gleicher Reihenfolge die Mindest- und Maximalgröße der Gruppen. Alle Parameter sind durch einen Strichpunkt zu trennen. Am Ende der Zeile ist aber kein Strichpunkt zu setzen. | ||
\paragraph{Gruppenauflistung} | ||
Danach werden die Gruppen aufgelistet. Dabei ist nichts weiter anzugeben als ein Gruppenname pro Zeile. Danach können wie beim Gruppenindikator Mindest- und Maximalgröße angegeben werden. Fehlen diese, werden die beim Indikator angegebenen Werte verwendet. Zu beachten ist, dass der Name keinen Strichpunkt enthalten darf. Dies gilt natürlich auch für die weiter unten behandelten Personennamen. | ||
\paragraph{Personenindikator} | ||
Nach der Auflistung der Gruppen folgt in der nächsten Zeile der Indikator für die Personen "P". | ||
\paragraph{Personenauflistung} | ||
Daraufhin werden die Personen aufgelistet, indem in einer Zeile zunächst der Name bzw. die Nummer der Person, und dann die Wünsche notiert werden. Es muss mindestens ein Wunsch vorhanden sein, nach oben gibt es dabei keine Grenze, auch wenn in der Benutzeroberfläche nur die ersten drei Wünsche angezeigt werden. Die letzteren müssen natürlich alle in der obigen Gruppenliste enthalten sein. Diese Parameter sind wiederum durch Strichpunkte getrennt. Zusätzlich kann nach einem Schrägstrich die Gruppe eingefügt werden, in die die Person tatsächlich zugeteilt ist. | ||
\paragraph{Dateiende} | ||
Nach der Auflistung der Personen darf die Datei keinerlei weiteren Zeichen enthalten. | ||
\subsection{Beispiel} | ||
\label{ssec:input-example} | ||
Im folgenden ist ein Beispiel für die Verteilung von W-Seminaren zu sehen. Die Liste der Personen ist allerdings verkürzt. | ||
\begin{lstlisting} | ||
S;12;18 | ||
W_C | ||
W_E | ||
W_F | ||
W_Geo | ||
W_M | ||
W_K | ||
W_L | ||
W_Inf | ||
W_Ph;10;14 | ||
P | ||
1;W_Geo;W_C;W_K | ||
2;W_E;W_K;W_L/W_E | ||
3;W_K;W_E;W_L | ||
4;W_K;W_Geo;W_E | ||
5;W_L;W_K;W_Geo | ||
6;W_E;W_Geo;W_K | ||
7;W_K;W_Geo;W_C | ||
8;W_K;W_Geo;W_E | ||
9;W_E;W_K;W_L | ||
10;W_K;W_Geo;W_E | ||
11;W_E;W_K;W_Geo | ||
12;W_Geo;W_L;W_C | ||
13;W_Geo;W_K;W_E | ||
14;W_F;W_K;W_E | ||
15;W_E;W_Geo;W_C | ||
16;W_Geo;W_E;W_L | ||
17;W_E;W_F;W_Geo | ||
18;W_K;W_Geo;W_C | ||
19;W_L;W_Geo;W_K | ||
20;W_K;W_E;W_L | ||
\end{lstlisting} | ||
|
||
|
||
\section{Export der Daten} | ||
\label{sec:export} | ||
|
||
GroupMatcher unterstützt das Exportieren der aktuellen Daten in drei verschiedene Dateiformate. Das GroupMatcher Dateiformat für die erneute Bearbeitung der Daten mit dem Programm, sowie zwei verschiedene Modi zur schöneren Ansicht in Excel. | ||
|
||
\subsection{GroupMatcher-Export} | ||
\label{ssec:exportgm} | ||
|
||
Das Programm bietet unter anderem die Möglichkeit in das .gm, also GroupMatcher Dateiformat zu exportieren. Dies dient primär zur Aufbewahrung der Daten. Falls diese eventuell später noch einmal benötigt werden können sie dann über die Importierfunktion eingelesen werden. | ||
|
||
\subsection{kompletter Excelexport} | ||
\label{ssec:exportexf} | ||
|
||
Exportieren nach Excel in der kompletten Ausführung liefert eine .xlsx Datei. Diese enthält alle vorhandenen Informationen, also die Gruppen mit Name, Minimalgröße, Maximalgröße und tatsächlicher Gruppenstärke bei aktueller konfiguration, sowie alle Personen mit Name, und allen Wünschen. Dabei wird der zugewiesene Wunsch, falls vorhanden, grau hinterlegt. | ||
|
||
\subsection{begrenzter Excelexport} | ||
\label{ssec:exportexl} | ||
|
||
Die Exportierfunktion in der eingeschränkten Excelversion erzeugt eine .xlsx Datei, welche allerdings nur die wichtigsten Informationen enthält. Sie ist vor allem für den Aushang der Endkonfiguration gedacht, da sie nur die Namen der Personen mit dem zugeteilten Wunsch enthält. | ||
|
||
|
||
\section{Fehlermeldungen} | ||
\label{sec:errors} | ||
|
||
\begin{itemize} | ||
\item Verteilen nicht möglich: Zu viele oder zu wenige Personen für gewählte Gruppenkonfiguration \\ | ||
Die Gesamtanzahl der Personen ist zu groß oder zu klein für die Gruppengrößen. | ||
\item Importfehler: \\ | ||
Alle Fehlermeldungen, beziehen sich auf den Importvorgang. | ||
\item Syntaxfehler \\ | ||
Die Group Matcher Syntax wurde nicht eingehalten. | ||
\item Identifikator für Gruppen nicht gefunden \\ | ||
Das S, der Identifikator für die Gruppen wurde nicht gefunden. | ||
\item mehrfache Benutzung eines Gruppennamens \\ | ||
Jede Gruppe muss einen einzigartigen Namen haben. Achten sie dabei auch auf den Personenidentifikator P, der nicht alleinstehend als Gruppenname benutzt werden darf. | ||
\item mehrfache Benutzung eines Personennamens \\ | ||
Jede Person muss einen einzigartigen Namen haben. | ||
\item leere Datei \\ | ||
Die importierte Datei ist leer. | ||
\item Identifikator für Personen nicht gefunden \\ | ||
Der Personenidentifikator P sollte direkt unter der Gruppenauflistung stehen. | ||
\item leeres Argument \\ | ||
Hinter einem Semikolon muss immer ein Inhalt sein. Wenn sie einer Person z.B. nur zwei Wünsche zuordnen wollen, darf diese Zeile auch nur zwei Semikolons enthalten. | ||
\item fehlendes Argument \\ | ||
Jede Person muss mindestens einen Wunsch haben. Die Gruppenstärken müssen entweder allgemein hinter dem Gruppenidentifikator, oder speziell für jede einzelne Gruppen bei der Gruppenaufzählung festgelegt werden. | ||
\item eine Gruppe ist nicht vorhanden \\ | ||
Alle Gruppen, die in Wünschen auftauchen, müssen vorher in der Gruppenauflistung definiert werden. | ||
\item eine Person konnte nicht zugeteilt werden \\ | ||
Dieser Fehler kann auftreten, wenn bei einer Person alle Wünsche ungültig sind, weil die entsprechenden Gruppen aufgrund von unterbesetzung entfernt wurden. | ||
\item Folgende Gruppe(n) kam(en) nicht zusammen: \\ | ||
Ist eine Gruppe unterbesetzt, d.h. kann die Mindestgröße nicht erreicht werden, wird sie automatisch gelöscht, und entsprechende Wünsche entfernt. Danach wird versucht, ohne diese Gruppe eine Verteilung zu finden. | ||
\item Sprache nicht gefunden \\ | ||
Dieser Fehler kann nur auftreten, wenn in der URL, oder im Programmverzeichnis manuelle Änderungen vorgenommen wurden. | ||
\item Keine Gruppen vorhanden \\ | ||
Tritt auf, wenn beim Exportieren, oder beim Wechseln in den Bearbeitungsmodus keine Gruppen vorhanden sind. | ||
\item Es sind bereits Personen zugeteilt \\ | ||
Der automatische Verteilungsvorgang kann nur gestartet werden, wenn alle Personen unzugeordnet sind. | ||
\item Gruppenkombination(en) überfüllt: \\ | ||
Es werden alle Gruppenkombinationen aufgelistet, die überfüllt sind. Dies tritt auf, wenn z.B. die Gruppen x,y eine Maximalgröße von je zwei Personen haben, aber fünf Personen nur die Wünsche x und y haben. | ||
\item Zeitüberschreitung - keine Lösung gefunden \\ | ||
Dieser Fehler tritt auf, wenn der Verteilungsprozess nach einer Minute immer noch keine Lösung gefunden hat. Dies passiert in der Regel nur dann, wenn eine komplexe Form eine Gruppenkombinationsfehlers vorliegt, die vom Algorithmus nicht erfasst wird, und keine Lösung möglich ist. | ||
\item Zeitüberschreitung - Lösung gefunden \\ | ||
Dieser Fehler tritt auf, wenn der Verteilungsprozess nach zehn Sekunden noch nicht für alle Versuche Lösungen gefunden wurden. Dies tritt v.a. dann auf, wenn die Gruppengrößen sehr eng gewählt wurden, und somit nur sehr wenige Lösungsmöglichkeiten vorhanden sind. | ||
\end{itemize} | ||
|
||
\end{document} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{ | ||
"#name": "De", | ||
"group": "Gruppe", | ||
"groups": "Gruppen", | ||
"person": "Person", | ||
"group name": "Gruppenname", | ||
"person name": "Personenname", | ||
"rate": "Quote", | ||
"reset": "Löschen", | ||
"genrandom": "Generieren", | ||
"exit": "Beenden", | ||
"unassigned": "Unzugeordnet", | ||
"name": "Name", | ||
"1stchoice": "Erstwunsch", | ||
"2ndchoice": "Zweitwunsch", | ||
"3rdchoice": "Drittwunsch", | ||
"add_to_group": "Zu Gruppe hinzufügen", | ||
"match_selected": "Verteilen", | ||
"rem_from_group": "Von Gruppe entfernen", | ||
"none": "keine", | ||
"close_now": "Sie können dieses Fenster jetzt schließen", | ||
"err_matching": "Fehler beim Verteilen", | ||
"err_matching_too_few_many": "Verteilen nicht möglich: Zu viele oder zu wenige Personen für gewählte Gruppenkonfiguration", | ||
"cleared": "Entfernt", | ||
"generated": "Erzeugt", | ||
"session_invalid": "Sitzung abgelaufen und wurde neu erstellt", | ||
"import_success": "Datei erfolgreich importiert", | ||
"import_error": "Importfehler: ", | ||
"syntax_error": "Syntaxfehler", | ||
"group_initializer_not_found": "Identifikator für Gruppen nicht gefunden", | ||
"group_name_not_unique": "mehrfache Benutzung eines Gruppennamens", | ||
"person_name_not_unique": "mehrfache Benutzung eines Personennamens", | ||
"empty_file": "leere Datei", | ||
"person_initializer_not_found": "Identifikator für Personen nicht gefunden", | ||
"empty_argument": "leeres Argument", | ||
"missing_argument": "fehlendes Argument", | ||
"group_not_found": "eine Gruppe ist nicht vorhanden", | ||
"line": " in Zeile ", | ||
"restore": "Zurücksetzen", | ||
"restored": "Zurückgesetzt", | ||
"person_no_pref": "eine Person konnte nicht zugeteilt werden", | ||
"group_deleted": "Folgende Gruppe(n) kam(en) nicht zusammen: ", | ||
"save": "Speichern", | ||
"edit": "Bearbeiten", | ||
"lang_not_found": "Sprache nicht gefunden", | ||
"lang": "Sprache", | ||
"groups_empty": "Keine Gruppen vorhanden", | ||
"thanks": "Danke, dass sie sich für Group Matcher entschieden haben", | ||
"min_size": "Mindestgröße", | ||
"max_size": "Maximalgröße", | ||
"group_size": "Gruppengröße", | ||
"group_assigned": "zugeteilte Gruppe", | ||
"exlimited": "Excel (begrenzt)", | ||
"extotal": "Excel (komplett)", | ||
"assigned_persons": "Es sind bereits Personen zugeteilt", | ||
"combination_overfilled": "Gruppenkombination(en) überfüllt: ", | ||
"export": "Export", | ||
"upload": "Hochladen", | ||
"import": "Import", | ||
"group-overview": "Gruppenübersicht", | ||
"return": "Zurück", | ||
"hardtimeout": "Zeitüberschreitung - keine Lösung gefunden", | ||
"softtimeout": "Zeitüberschreitung - Lösung gefunden", | ||
"about":"Das Programm GroupMatcher, dass auf Go basiert, dient zur Verteilung von Personen auf Gruppen unter berücksichtigung ihrer Wünsche. Dabei können die Personen, die über Erst-, Zweit- und Drittwahl verfügen, auf eine beliebige Anzahl von Gruppen mit Minimal- und Maximalkapazität verteilt werden. Es wurde im Rahmen eines Q11 Informatik-Projekts von Justus Roßmeier, Christian Obermaier und Max Obermeier entwickelt." | ||
} |
Oops, something went wrong.