omyl s jar souborem, par vylepseni, java 11
This commit is contained in:
parent
43b2701151
commit
5e5e6f26da
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
*.class
|
*.class
|
||||||
|
jecnak-tui.jar
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"java.configuration.updateBuildConfiguration": "interactive"
|
"java.configuration.updateBuildConfiguration": "automatic"
|
||||||
}
|
}
|
BIN
jecnak-tui.jar
BIN
jecnak-tui.jar
Binary file not shown.
12
pom.xml
12
pom.xml
@ -14,8 +14,8 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.source>1.8</maven.compiler.source>
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
<maven.compiler.target>1.8</maven.compiler.target>
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -26,14 +26,6 @@
|
|||||||
<version>1.15.3</version>
|
<version>1.15.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.gson</groupId>
|
|
||||||
<artifactId>gson</artifactId>
|
|
||||||
<version>2.10.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.googlecode.lanterna</groupId>
|
<groupId>com.googlecode.lanterna</groupId>
|
||||||
<artifactId>lanterna</artifactId>
|
<artifactId>lanterna</artifactId>
|
||||||
|
@ -13,7 +13,6 @@ public class App {
|
|||||||
MainWindow window = new MainWindow();
|
MainWindow window = new MainWindow();
|
||||||
window.run();
|
window.run();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ public class App {
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
// TO DO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (SecurityException e)
|
} catch (SecurityException e)
|
||||||
{
|
{
|
||||||
|
@ -29,12 +29,13 @@ public class OmluvnyList extends JecnaContent{
|
|||||||
{
|
{
|
||||||
omluvnyPanel.addComponent(new Label(p.getValue0() + " - " + p.getValue1()));
|
omluvnyPanel.addComponent(new Label(p.getValue0() + " - " + p.getValue1()));
|
||||||
}
|
}
|
||||||
|
hasStarted = true;
|
||||||
}catch(UnknownHostException e)
|
}catch(UnknownHostException e)
|
||||||
{
|
{
|
||||||
omluvnyPanel.addComponent(new Label("A connection error occurred"));
|
// omluvnyPanel.addComponent(new Label("A connection error occurred"));
|
||||||
}catch(IOException e)
|
}catch(IOException e)
|
||||||
{
|
{
|
||||||
omluvnyPanel.addComponent(new Label("An error occurred"));
|
// omluvnyPanel.addComponent(new Label("An error occurred"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,6 @@ import com.googlecode.lanterna.gui2.Label;
|
|||||||
import com.googlecode.lanterna.gui2.Panel;
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
|
|
||||||
import xyz.thastertyn.Tuples.Pair;
|
|
||||||
|
|
||||||
public class Sdeleni extends JecnaContent {
|
public class Sdeleni extends JecnaContent {
|
||||||
|
|
||||||
private Panel sdeleniPanel = new Panel();
|
private Panel sdeleniPanel = new Panel();
|
||||||
@ -28,29 +26,17 @@ public class Sdeleni extends JecnaContent {
|
|||||||
if(!hasStarted)
|
if(!hasStarted)
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
|
|
||||||
sdeleniPanel.setLayoutManager(new GridLayout(1)
|
sdeleniPanel.setLayoutManager(new GridLayout(1)
|
||||||
.setLeftMarginSize(1)
|
.setLeftMarginSize(1)
|
||||||
.setRightMarginSize(1));
|
.setRightMarginSize(1));
|
||||||
|
|
||||||
sdeleni.downloadSdeleni();
|
sdeleni.downloadSdeleni();
|
||||||
|
|
||||||
ArrayList<Pair<String, Boolean>> sdeleniList = sdeleni.getSdeleni();
|
ArrayList<String> sdeleniList = sdeleni.getSdeleni();
|
||||||
|
|
||||||
for(Pair<String, Boolean> p : sdeleniList)
|
for(String s : sdeleniList)
|
||||||
{
|
{
|
||||||
String label = "";
|
sdeleniPanel.addComponent(new Label(s));
|
||||||
|
|
||||||
if(p.getValue1())
|
|
||||||
{
|
|
||||||
label += "✅";
|
|
||||||
}else{
|
|
||||||
label += "❌";
|
|
||||||
}
|
|
||||||
|
|
||||||
label += " " + p.getValue0();
|
|
||||||
|
|
||||||
sdeleniPanel.addComponent(new Label(label));
|
|
||||||
}
|
}
|
||||||
hasStarted = true;
|
hasStarted = true;
|
||||||
}catch(UnknownHostException e)
|
}catch(UnknownHostException e)
|
||||||
|
@ -18,10 +18,9 @@ import xyz.thastertyn.Tuples.Triplet;
|
|||||||
|
|
||||||
public class LoginController {
|
public class LoginController {
|
||||||
|
|
||||||
|
private WindowBasedTextGUI textGUI;
|
||||||
|
private xyz.thastertyn.ContentDisplay.CredentialsInput dialog;
|
||||||
private xyz.thastertyn.JecnaParse.Login login = new xyz.thastertyn.JecnaParse.Login();
|
private xyz.thastertyn.JecnaParse.Login login = new xyz.thastertyn.JecnaParse.Login();
|
||||||
private xyz.thastertyn.ContentDisplay.CredentialsInput dialog = new CredentialsInput();
|
|
||||||
|
|
||||||
private WindowBasedTextGUI textGUI = null;
|
|
||||||
|
|
||||||
public LoginController(WindowBasedTextGUI textGUI)
|
public LoginController(WindowBasedTextGUI textGUI)
|
||||||
{
|
{
|
||||||
@ -30,6 +29,7 @@ public class LoginController {
|
|||||||
|
|
||||||
public void login()
|
public void login()
|
||||||
{
|
{
|
||||||
|
dialog = new CredentialsInput();
|
||||||
if(checkForCredentials()) // Credentials exist
|
if(checkForCredentials()) // Credentials exist
|
||||||
{
|
{
|
||||||
if(loginUsingCredentials()) // They are accessible and can read them
|
if(loginUsingCredentials()) // They are accessible and can read them
|
||||||
@ -38,27 +38,27 @@ public class LoginController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Triplet<String, String, Boolean> data = dialog.showDialog(textGUI); // Failed to get credentials to log in, get them from user
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Triplet<String, String, Boolean> data = dialog.showDialog(textGUI); // Failed to get credentials to log in, get them from user
|
|
||||||
login.loginJecna(data.getValue0(), data.getValue1());
|
login.loginJecna(data.getValue0(), data.getValue1());
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
MessageDialog.showMessageDialog(textGUI, "No Internet connection",
|
MessageDialog.showMessageDialog(textGUI, "No Internet connection",
|
||||||
"There seems to be no internet connection, reverting to cached data",
|
"There seems to be no internet connection, reverting to cached data",
|
||||||
MessageDialogButton.OK);
|
MessageDialogButton.OK);
|
||||||
return;
|
login();
|
||||||
} catch (CredentialException e)
|
} catch (CredentialException e)
|
||||||
{
|
{
|
||||||
MessageDialog.showMessageDialog(textGUI, "Incorrect username or password",
|
MessageDialog.showMessageDialog(textGUI, "Incorrect username or password",
|
||||||
"The username or password you entered is incorrect",
|
"The username or password you entered is incorrect",
|
||||||
MessageDialogButton.OK);
|
MessageDialogButton.OK);
|
||||||
return;
|
login();
|
||||||
} catch (IOException e)
|
} catch (IOException e)
|
||||||
{
|
{
|
||||||
MessageDialog.showMessageDialog(textGUI, "There was an error",
|
MessageDialog.showMessageDialog(textGUI, "There was an error",
|
||||||
"Maybe try again and it will go away",
|
"Maybe try again and it will go away",
|
||||||
MessageDialogButton.Retry);
|
MessageDialogButton.Retry);
|
||||||
return;
|
login();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ public class MainWindow {
|
|||||||
LoginController controller = new LoginController(textGUI);
|
LoginController controller = new LoginController(textGUI);
|
||||||
controller.login();
|
controller.login();
|
||||||
|
|
||||||
window.addWindowListener(new WindowSwitchListener(content, title));
|
window.addWindowListener(new WindowSwitchListener(content, title, textGUI));
|
||||||
|
|
||||||
textGUI.addWindowAndWait(window);
|
textGUI.addWindowAndWait(window);
|
||||||
|
|
||||||
|
@ -10,7 +10,10 @@ import com.googlecode.lanterna.gui2.Label;
|
|||||||
import com.googlecode.lanterna.gui2.LinearLayout;
|
import com.googlecode.lanterna.gui2.LinearLayout;
|
||||||
import com.googlecode.lanterna.gui2.Panel;
|
import com.googlecode.lanterna.gui2.Panel;
|
||||||
import com.googlecode.lanterna.gui2.Window;
|
import com.googlecode.lanterna.gui2.Window;
|
||||||
|
import com.googlecode.lanterna.gui2.WindowBasedTextGUI;
|
||||||
import com.googlecode.lanterna.gui2.WindowListener;
|
import com.googlecode.lanterna.gui2.WindowListener;
|
||||||
|
import com.googlecode.lanterna.gui2.dialogs.MessageDialog;
|
||||||
|
import com.googlecode.lanterna.gui2.dialogs.MessageDialogButton;
|
||||||
import com.googlecode.lanterna.input.KeyStroke;
|
import com.googlecode.lanterna.input.KeyStroke;
|
||||||
import com.googlecode.lanterna.input.KeyType;
|
import com.googlecode.lanterna.input.KeyType;
|
||||||
|
|
||||||
@ -22,20 +25,29 @@ import xyz.thastertyn.ContentDisplay.Content.Znamky;
|
|||||||
|
|
||||||
public class WindowSwitchListener implements WindowListener {
|
public class WindowSwitchListener implements WindowListener {
|
||||||
|
|
||||||
private JecnaContent[] contents = {new Rozvrh(), new Znamky(), new Sdeleni(), new OmluvnyList()};
|
private WindowBasedTextGUI textGUI;
|
||||||
|
|
||||||
|
private JecnaContent[] contents = {
|
||||||
|
new Rozvrh(),
|
||||||
|
new Znamky(),
|
||||||
|
new Sdeleni(),
|
||||||
|
new OmluvnyList()
|
||||||
|
};
|
||||||
|
|
||||||
private Label[] tabs = new Label[contents.length];
|
private Label[] tabs = new Label[contents.length];
|
||||||
|
|
||||||
private Panel tabsPanel = new Panel().setLayoutManager(new LinearLayout(Direction.HORIZONTAL));
|
private Panel tabsPanel = new Panel().setLayoutManager(new LinearLayout(Direction.HORIZONTAL));
|
||||||
private Panel content = new Panel();
|
private Panel holderPanel = new Panel();
|
||||||
|
|
||||||
private Panel errorPanel = new Panel().addComponent(new Label("Something went wrong"));
|
private Panel errorPanel = new Panel().addComponent(new Label("Something went wrong"));
|
||||||
|
|
||||||
int current = contents.length - 1;
|
int current = contents.length - 1;
|
||||||
|
|
||||||
public WindowSwitchListener(Panel holder, String title)
|
public WindowSwitchListener(Panel holder, String title, WindowBasedTextGUI textGUI)
|
||||||
{
|
{
|
||||||
|
this.textGUI = textGUI;
|
||||||
holder.addComponent(tabsPanel);
|
holder.addComponent(tabsPanel);
|
||||||
holder.addComponent(content.withBorder(Borders.singleLine()));
|
holder.addComponent(holderPanel.withBorder(Borders.singleLine()));
|
||||||
|
|
||||||
for(int i = 0; i < contents.length; i++)
|
for(int i = 0; i < contents.length; i++)
|
||||||
{
|
{
|
||||||
@ -60,7 +72,7 @@ public class WindowSwitchListener implements WindowListener {
|
|||||||
contents[current].download();
|
contents[current].download();
|
||||||
}
|
}
|
||||||
|
|
||||||
content.removeAllComponents();
|
holderPanel.removeAllComponents();
|
||||||
tabsPanel.removeAllComponents();
|
tabsPanel.removeAllComponents();
|
||||||
|
|
||||||
if(contents[current].hasStarted())
|
if(contents[current].hasStarted())
|
||||||
@ -69,15 +81,15 @@ public class WindowSwitchListener implements WindowListener {
|
|||||||
|
|
||||||
if(contents[current].getPanel().getSize().getColumns() < tabColumns)
|
if(contents[current].getPanel().getSize().getColumns() < tabColumns)
|
||||||
{
|
{
|
||||||
content.addComponent(
|
holderPanel.addComponent(
|
||||||
contents[current].getPanel().setPreferredSize(new TerminalSize(tabColumns,
|
contents[current].getPanel().setPreferredSize(new TerminalSize(tabColumns,
|
||||||
contents[current].getPanel().getPreferredSize().getRows())));
|
contents[current].getPanel().getPreferredSize().getRows())));
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
content.addComponent(contents[current].getPanel());
|
holderPanel.addComponent(contents[current].getPanel());
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
content.addComponent(errorPanel);
|
holderPanel.addComponent(errorPanel);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < tabs.length; i++)
|
for(int i = 0; i < tabs.length; i++)
|
||||||
@ -100,6 +112,15 @@ public class WindowSwitchListener implements WindowListener {
|
|||||||
case Tab:
|
case Tab:
|
||||||
next();
|
next();
|
||||||
break;
|
break;
|
||||||
|
case Character:
|
||||||
|
if(keyStroke.getCharacter() == ' ')
|
||||||
|
{
|
||||||
|
MessageDialog.showMessageDialog(textGUI, "Space pressed", "Good job", MessageDialogButton.OK);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Escape:
|
||||||
|
MessageDialog.showMessageDialog(textGUI, "Options", "Loging out and some other stuff soon", MessageDialogButton.OK);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
5
src/main/java/xyz/thastertyn/JecnaParse/JecnaParser.java
Normal file
5
src/main/java/xyz/thastertyn/JecnaParse/JecnaParser.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package xyz.thastertyn.JecnaParse;
|
||||||
|
|
||||||
|
public class JecnaParser {
|
||||||
|
|
||||||
|
}
|
@ -14,8 +14,6 @@ public class OmluvnyList {
|
|||||||
|
|
||||||
private ArrayList<Pair<String, String>> data = new ArrayList<>();
|
private ArrayList<Pair<String, String>> data = new ArrayList<>();
|
||||||
|
|
||||||
private boolean wasDownloaded = false;
|
|
||||||
|
|
||||||
public void downloadOmluvnyList() throws UnknownHostException, IOException
|
public void downloadOmluvnyList() throws UnknownHostException, IOException
|
||||||
{
|
{
|
||||||
Document doc = Downloader.download("https://www.spsejecna.cz/absence/student").get();
|
Document doc = Downloader.download("https://www.spsejecna.cz/absence/student").get();
|
||||||
@ -29,12 +27,16 @@ public class OmluvnyList {
|
|||||||
|
|
||||||
data.add(new Pair<String, String>(date, text));
|
data.add(new Pair<String, String>(date, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
wasDownloaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Pair<String, String>> getData()
|
public ArrayList<Pair<String, String>> getData()
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return (!data.isEmpty()) ? data.toString() : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,9 @@ import org.jsoup.nodes.Document;
|
|||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
import org.jsoup.select.Elements;
|
import org.jsoup.select.Elements;
|
||||||
|
|
||||||
import xyz.thastertyn.Tuples.Pair;
|
|
||||||
|
|
||||||
public class Sdeleni {
|
public class Sdeleni {
|
||||||
|
|
||||||
ArrayList<Pair<String, Boolean>> sdeleniList = new ArrayList<>();
|
ArrayList<String> sdeleniList = new ArrayList<>();
|
||||||
|
|
||||||
public void downloadSdeleni() throws UnknownHostException, IOException
|
public void downloadSdeleni() throws UnknownHostException, IOException
|
||||||
{
|
{
|
||||||
@ -30,18 +28,18 @@ public class Sdeleni {
|
|||||||
isPositive = spans.get(0).hasClass("sprite-icon-tick-16");
|
isPositive = spans.get(0).hasClass("sprite-icon-tick-16");
|
||||||
label = spans.get(1).text();
|
label = spans.get(1).text();
|
||||||
|
|
||||||
//if(!label.startsWith(" "))
|
if(isPositive)
|
||||||
//{
|
{
|
||||||
// label = " " + label;
|
label = "✅" + " " + label;
|
||||||
//}
|
}else{
|
||||||
|
label = "❌" + " " + label;
|
||||||
|
}
|
||||||
|
|
||||||
//label = label.replaceAll("\\s+$", "");
|
sdeleniList.add(label);
|
||||||
|
|
||||||
sdeleniList.add(new Pair<String, Boolean>(label, isPositive));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Pair<String, Boolean>> getSdeleni()
|
public ArrayList<String> getSdeleni()
|
||||||
{
|
{
|
||||||
return sdeleniList;
|
return sdeleniList;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ public class Znamky {
|
|||||||
private ArrayList<Pair<String, Pair<ArrayList<Pair<Integer, Double>>,Double>>> grades = new ArrayList<>();
|
private ArrayList<Pair<String, Pair<ArrayList<Pair<Integer, Double>>,Double>>> grades = new ArrayList<>();
|
||||||
|
|
||||||
// Integer znaci id roku, boolean jestli je jen prvni nebo i druhe pololeti
|
// Integer znaci id roku, boolean jestli je jen prvni nebo i druhe pololeti
|
||||||
private ArrayList<Pair<Integer, Boolean>> options = new ArrayList<>();
|
private Pair<ArrayList<String>, ArrayList<String>> options = new Pair<>();
|
||||||
|
|
||||||
public void downloadZnamky(/*, int schoolYearId, int schoolYearHalfId*/) throws UnknownHostException, IOException
|
public void downloadZnamky(/*, int schoolYearId, int schoolYearHalfId*/) throws UnknownHostException, IOException
|
||||||
{
|
{
|
||||||
@ -75,24 +75,28 @@ public class Znamky {
|
|||||||
subj++;
|
subj++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Element optionsPanel = znamkyDoc.selectFirst("form.listConfigure");
|
||||||
|
|
||||||
/*
|
Elements schoolYear = optionsPanel.select("select[id=schoolYearId]").select("option");
|
||||||
Elements roky = znamkyDoc.select("select[name=schoolYearId]");
|
Elements schoolYearId = optionsPanel.select("select[id=schoolYearHalfId]").select("option");
|
||||||
Elements pololetiSelect = znamkyDoc.select("select[name=schoolYearHalfId]");
|
|
||||||
|
|
||||||
for(Element e : roky)
|
/*
|
||||||
{
|
Elements roky = znamkyDoc.select("select[name=schoolYearId]");
|
||||||
boolean jeCelyRok = false;
|
Elements pololetiSelect = znamkyDoc.select("select[name=schoolYearHalfId]");
|
||||||
|
|
||||||
if(pololetiSelect.size() == 2)
|
for(Element e : roky)
|
||||||
{
|
{
|
||||||
jeCelyRok = true;
|
boolean jeCelyRok = false;
|
||||||
}
|
|
||||||
|
|
||||||
int rok = Integer.parseInt(e.attr("value"));
|
if(pololetiSelect.size() == 2)
|
||||||
|
{
|
||||||
|
jeCelyRok = true;
|
||||||
|
}
|
||||||
|
|
||||||
options.add(new Pair<Integer, Boolean>(rok, jeCelyRok));
|
int rok = Integer.parseInt(e.attr("value"));
|
||||||
}*/
|
|
||||||
|
options.add(new Pair<Integer, Boolean>(rok, jeCelyRok));
|
||||||
|
}*/
|
||||||
|
|
||||||
wasDownloaded = true;
|
wasDownloaded = true;
|
||||||
|
|
||||||
@ -143,11 +147,6 @@ public class Znamky {
|
|||||||
return grades;
|
return grades;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<Pair<Integer, Boolean>> getOptions()
|
|
||||||
{
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
@ -17,4 +17,23 @@ public class AppTest
|
|||||||
{
|
{
|
||||||
assertTrue( true );
|
assertTrue( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void hasJavaAbove11()
|
||||||
|
{
|
||||||
|
// https://stackoverflow.com/questions/2591083/getting-java-version-at-runtime#2591122
|
||||||
|
String version = System.getProperty("java.version");
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if(version.startsWith("1."))
|
||||||
|
{
|
||||||
|
version = version.substring(2, 3);
|
||||||
|
}else {
|
||||||
|
int dot = version.indexOf(".");
|
||||||
|
if(dot != -1) { version = version.substring(0, dot); }
|
||||||
|
}
|
||||||
|
v = Integer.parseInt(version);
|
||||||
|
|
||||||
|
assertTrue("Java >= 11 is required", (v >= 11));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user