Initial commit
This commit is contained in:
commit
70a9eb0be6
2
arduino/.gitignore
vendored
Normal file
2
arduino/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.pioenvs
|
||||
.piolibdeps
|
18
arduino/platformio.ini
Normal file
18
arduino/platformio.ini
Normal file
@ -0,0 +1,18 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; http://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:megaatmega2560]
|
||||
platform = atmelavr
|
||||
board = megaatmega2560
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
EnableInterrupt
|
||||
Keypad
|
||||
LiquidCrystal_I2C
|
543
arduino/src/main.ino
Normal file
543
arduino/src/main.ino
Normal file
@ -0,0 +1,543 @@
|
||||
#include <EnableInterrupt.h>
|
||||
#include <Keypad.h> //http://www.arduino.cc/playground/uploads/Code/Keypad.zip
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
#define CommandSerial Serial
|
||||
#define LogSerial Serial
|
||||
|
||||
//##########################RUNTIME##########################
|
||||
//ilosc zadan:
|
||||
#define N_TASKS 10
|
||||
//dlugosc sekundy w ms:
|
||||
#define TICK 1000
|
||||
//czas odswiezania potencjometru w ms:
|
||||
#define TICK2 200
|
||||
|
||||
//obecne czasy zycia LEDow na panelu
|
||||
int taskLifetimes[N_TASKS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
//tekst ostatnio wpisany na keypadzie
|
||||
String keypadInput = "";
|
||||
|
||||
//liczniki klikniec
|
||||
int foambtn_clicks = 0;
|
||||
int dynamo1_clicks = 0;
|
||||
int dynamo2_clicks = 0;
|
||||
int dynamo3_clicks = 0;
|
||||
|
||||
unsigned long previousMillis = 0;
|
||||
unsigned long previousMillis2 = 0;
|
||||
|
||||
//liczniki i teksty z potencjometru
|
||||
int prevKnobInput = 0;
|
||||
bool added = false;
|
||||
String knobInputTotal = "";
|
||||
|
||||
//czas zwolnienia zamka szuflady
|
||||
#define DRAWER_OPEN_DELAY 2000
|
||||
//##########################GAMEPLAY##########################
|
||||
//ile razy trzeba wcisnac piankowy guzik?
|
||||
#define FOAM_MAXSCORE 10
|
||||
//ile razy trzeba przekrecic korba w kazdym gniezdzie?
|
||||
#define DYNAMO_MAXSCORE1 50
|
||||
#define DYNAMO_MAXSCORE2 20
|
||||
#define DYNAMO_MAXSCORE3 30
|
||||
//ile czasu zyje kazda dioda po zapaleniu? (w sekundach)
|
||||
int taskMaxLifetimes[N_TASKS] = {600, 180, 180, 180, 180, 180, 180, 180, 180, 180};
|
||||
//haslo do otwarcia szuflady
|
||||
String pass1 = "1234";
|
||||
//haslo do zagadki z mp3
|
||||
String pass2 = "ABCD";
|
||||
//kod do sejfu
|
||||
String knob_pass = "354";
|
||||
|
||||
//wiadomosc poczatkowa na LCD
|
||||
#define LCD_PROMPT "Podaj haslo:"
|
||||
|
||||
//wiadomosc na LCD po dobrym kodzie
|
||||
#define LCD_CORRECT "DOBRZE"
|
||||
|
||||
//wiadomosc na LCD po zlym kodzie
|
||||
#define LCD_INCORRECT "ZLE"
|
||||
|
||||
//##########################PINY##########################
|
||||
//piny do RPi
|
||||
|
||||
int pin_rpi_neg = 45; //
|
||||
int pin_rpi_pos = 47; //
|
||||
//gpio
|
||||
int pin_rpi_slide1 = 37; //RPi GPIO25
|
||||
int pin_rpi_slide2 = 39; //RPi GPIO8
|
||||
int pin_rpi_slide3 = 41; //RPi GPIO7
|
||||
int pin_rpi_slide5 = 43; //RPi GPIO12
|
||||
int pin_rpi_slide6 = 49; //RPi GPIO16
|
||||
//pin slajdu zwyciestwa
|
||||
int pin_rpi_slide_win = 51; //RPi GPIO20
|
||||
|
||||
//piny od RPi
|
||||
int pin_rpi_win9 = 11; //RPi GPIO3
|
||||
int pin_rpi_win4 = 12; //RPi GPIO2
|
||||
int pin_rpi_win10 = 10; //RPi GPIO4
|
||||
//piny kontrolerow zagadek
|
||||
int pin_key = 14;
|
||||
int pin_foambtn = 15;
|
||||
int pin_maze = A8;
|
||||
int pin_dynamo1 = A11;
|
||||
int pin_dynamo2 = A9;
|
||||
int pin_dynamo3 = A10;
|
||||
|
||||
//piny ledow do korby
|
||||
int pin_dyna_led1 = A2;
|
||||
int pin_dyna_led2 = A6;
|
||||
int pin_dyna_led3 = A4;
|
||||
int pin_dyna_led4 = A3;
|
||||
int pin_dyna_led5 = A1;
|
||||
int pin_dyna_led6 = A5;
|
||||
|
||||
//piny ledow na panelu - w kolejnosci zagadek
|
||||
int taskPins[N_TASKS] = {34, 36, 38, 40, 42, 44, 46, 48, 50, 52};
|
||||
|
||||
//pin pokretla sejfu
|
||||
int pin_knob = A0;
|
||||
|
||||
//pin otwarcia szuflady
|
||||
int pin_drawer_relay = A7;
|
||||
//piny klawiatury
|
||||
const byte ROWS = 4; // Four rows
|
||||
const byte COLS = 4; // columns
|
||||
// Define the Keymap
|
||||
char keys[ROWS][COLS] = {
|
||||
{'1', '2', '3', 'A'},
|
||||
{'4', '5', '6', 'B'},
|
||||
{'7', '8', '9', 'C'},
|
||||
{'*', '0', '#', 'D'}
|
||||
};
|
||||
byte rowPins[ROWS] = {A12, A13, A14, A15};
|
||||
byte colPins[COLS] = {2, 3, 4, 5};
|
||||
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
|
||||
|
||||
LiquidCrystal_I2C lcd(0x3F,16,2);
|
||||
|
||||
void log(String in){
|
||||
LogSerial.println(in);
|
||||
}
|
||||
|
||||
void taskDone(int n){
|
||||
taskLifetimes[n] = taskMaxLifetimes[n];
|
||||
LogSerial.print("task done: ");
|
||||
LogSerial.println(n+1);
|
||||
}
|
||||
|
||||
void taskUnDone(int n){
|
||||
taskLifetimes[n] = 0;
|
||||
//wylaczanie ledow korby
|
||||
if(n == 4){
|
||||
dynamo1_clicks = 0;
|
||||
dynamo2_clicks = 0;
|
||||
dynamo3_clicks = 0;
|
||||
digitalWrite(pin_dyna_led1, LOW);
|
||||
digitalWrite(pin_dyna_led2, LOW);
|
||||
digitalWrite(pin_dyna_led3, LOW);
|
||||
digitalWrite(pin_dyna_led4, LOW);
|
||||
digitalWrite(pin_dyna_led5, LOW);
|
||||
digitalWrite(pin_dyna_led6, LOW);
|
||||
log("turning off dynamo leds.");
|
||||
}
|
||||
LogSerial.print("task undone: ");
|
||||
LogSerial.println(n+1);
|
||||
}
|
||||
|
||||
void updateDynamo(){
|
||||
if(dynamo1_clicks > DYNAMO_MAXSCORE1 && dynamo2_clicks > DYNAMO_MAXSCORE2 && dynamo3_clicks > DYNAMO_MAXSCORE3 && taskLifetimes[4] == 0){
|
||||
taskDone(4);
|
||||
}
|
||||
|
||||
if (taskLifetimes[4] == 1){
|
||||
dynamo1_clicks = 0;
|
||||
dynamo2_clicks = 0;
|
||||
dynamo3_clicks = 0;
|
||||
|
||||
digitalWrite(pin_dyna_led1, LOW);
|
||||
digitalWrite(pin_dyna_led2, LOW);
|
||||
digitalWrite(pin_dyna_led3, LOW);
|
||||
digitalWrite(pin_dyna_led4, LOW);
|
||||
digitalWrite(pin_dyna_led5, LOW);
|
||||
digitalWrite(pin_dyna_led6, LOW);
|
||||
log("turning off dynamo leds.");
|
||||
}
|
||||
}
|
||||
|
||||
void updateTasks(){
|
||||
bool win = true;
|
||||
updateDynamo();
|
||||
for(int i=0; i<N_TASKS; i++){
|
||||
if(taskLifetimes[i] > 0){
|
||||
digitalWrite(taskPins[i], HIGH);
|
||||
taskLifetimes[i]--;
|
||||
}
|
||||
else{
|
||||
digitalWrite(taskPins[i], LOW);
|
||||
win = false;
|
||||
}
|
||||
}
|
||||
if (win){
|
||||
setSlide(9);
|
||||
log("GAME OVER - YOU WIN.");
|
||||
}
|
||||
}
|
||||
|
||||
void logTasks(){
|
||||
LogSerial.print("tasks: ");
|
||||
for(int i=0; i<N_TASKS; i++){
|
||||
LogSerial.print(i+1);
|
||||
LogSerial.print(": ");
|
||||
LogSerial.print(taskLifetimes[i]);
|
||||
LogSerial.print("\t\t");
|
||||
|
||||
CommandSerial.print(i);
|
||||
CommandSerial.print(":");
|
||||
if(taskLifetimes[i]) CommandSerial.print(("y")); else CommandSerial.print(("n"));
|
||||
CommandSerial.print("#");
|
||||
}
|
||||
LogSerial.println();
|
||||
CommandSerial.println();
|
||||
}
|
||||
|
||||
void setSlide(int n){
|
||||
switch(n){
|
||||
case 1:
|
||||
log("signalling slide 1.");
|
||||
digitalWrite(pin_rpi_slide1, LOW);
|
||||
delay(800);
|
||||
digitalWrite(pin_rpi_slide1, HIGH);
|
||||
break;
|
||||
case 2:
|
||||
log("signalling slide 2.");
|
||||
digitalWrite(pin_rpi_slide2, LOW);
|
||||
delay(800);
|
||||
digitalWrite(pin_rpi_slide2, HIGH);
|
||||
break;
|
||||
case 3:
|
||||
log("signalling slide 3.");
|
||||
digitalWrite(pin_rpi_slide3, LOW);
|
||||
delay(800);
|
||||
digitalWrite(pin_rpi_slide3, HIGH);
|
||||
break;
|
||||
case 5:
|
||||
log("signalling slide 5.");
|
||||
digitalWrite(pin_rpi_slide5, LOW);
|
||||
delay(800);
|
||||
digitalWrite(pin_rpi_slide5, HIGH);
|
||||
break;
|
||||
case 6:
|
||||
log("signalling slide 6.");
|
||||
digitalWrite(pin_rpi_slide6, LOW);
|
||||
delay(800);
|
||||
digitalWrite(pin_rpi_slide6, HIGH);
|
||||
break;
|
||||
case 9:
|
||||
log("signalling win slide.");
|
||||
pinMode(pin_rpi_slide_win, OUTPUT);
|
||||
digitalWrite(pin_rpi_slide_win, LOW);
|
||||
delay(800);
|
||||
digitalWrite(pin_rpi_slide_win, HIGH);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void win4ISR() {
|
||||
if(digitalRead(pin_rpi_win4) == LOW) taskDone(3);
|
||||
}
|
||||
|
||||
void win9ISR() {
|
||||
if(digitalRead(pin_rpi_win9) == LOW) taskDone(8);
|
||||
}
|
||||
|
||||
void win10ISR() {
|
||||
if(digitalRead(pin_rpi_win10) == LOW) taskDone(9);
|
||||
}
|
||||
|
||||
void pin_keyISR() {
|
||||
if(digitalRead(pin_key) == LOW){
|
||||
taskDone(0);
|
||||
setSlide(1);
|
||||
}
|
||||
}
|
||||
|
||||
void pin_foambtnISR() {
|
||||
if(digitalRead(pin_foambtn) == LOW){
|
||||
foambtn_clicks++;
|
||||
setSlide(3);
|
||||
}
|
||||
if(foambtn_clicks > FOAM_MAXSCORE){
|
||||
taskDone(2);
|
||||
foambtn_clicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void pin_dynamo1ISR() {
|
||||
if(digitalRead(pin_dynamo1) == LOW){
|
||||
dynamo1_clicks++;
|
||||
log("dynamo 1 up.");
|
||||
|
||||
if(dynamo1_clicks > DYNAMO_MAXSCORE1){
|
||||
digitalWrite(pin_dyna_led1, HIGH);
|
||||
log("dynamo 1 done.");
|
||||
}
|
||||
else if(dynamo1_clicks > DYNAMO_MAXSCORE1/2){
|
||||
digitalWrite(pin_dyna_led2, HIGH);
|
||||
log("dynamo 1 half done.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void pin_dynamo2ISR() {
|
||||
if(digitalRead(pin_dynamo2) == LOW){
|
||||
dynamo2_clicks++;
|
||||
log("dynamo 2 up.");
|
||||
|
||||
if(dynamo2_clicks > DYNAMO_MAXSCORE2){
|
||||
digitalWrite(pin_dyna_led3, HIGH);
|
||||
log("dynamo 2 done.");
|
||||
}
|
||||
else if(dynamo2_clicks > DYNAMO_MAXSCORE2/2){
|
||||
digitalWrite(pin_dyna_led4, HIGH);
|
||||
log("dynamo 2 half done.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void pin_dynamo3ISR() {
|
||||
if(digitalRead(pin_dynamo3) == LOW){
|
||||
dynamo3_clicks++;
|
||||
log("dynamo 3 up.");
|
||||
|
||||
if(dynamo3_clicks > DYNAMO_MAXSCORE3){
|
||||
digitalWrite(pin_dyna_led5, HIGH);
|
||||
log("dynamo 3 done.");
|
||||
}
|
||||
else if(dynamo3_clicks > DYNAMO_MAXSCORE3/2){
|
||||
digitalWrite(pin_dyna_led6, HIGH);
|
||||
log("dynamo 3 half done.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void pin_mazeISR() {
|
||||
if(digitalRead(pin_maze) == LOW) taskDone(6);
|
||||
}
|
||||
|
||||
void openDrawer(){
|
||||
log("The drawer is open.");
|
||||
digitalWrite(pin_drawer_relay, HIGH);
|
||||
delay(DRAWER_OPEN_DELAY);
|
||||
digitalWrite(pin_drawer_relay, LOW);
|
||||
}
|
||||
|
||||
void checkPassword(){
|
||||
if(keypadInput == pass1){
|
||||
taskDone(5);
|
||||
openDrawer();
|
||||
log("Password 1 ok.");
|
||||
}
|
||||
if(keypadInput == pass2){
|
||||
taskDone(7);
|
||||
log("Password 2 ok.");
|
||||
}
|
||||
keypadInput = "";
|
||||
}
|
||||
|
||||
void clearPassword(){
|
||||
keypadInput = "";
|
||||
}
|
||||
|
||||
void keypadEvent(KeypadEvent event){
|
||||
if (keypad.getState() == PRESSED){
|
||||
switch (event){
|
||||
case '*': checkPassword(); break;
|
||||
case '#': clearPassword(); break;
|
||||
default: keypadInput += event;
|
||||
}
|
||||
LogSerial.print("Key pressed: ");
|
||||
LogSerial.print(event);
|
||||
LogSerial.print(" password now: ");
|
||||
LogSerial.println(keypadInput);
|
||||
setSlide(6);
|
||||
}
|
||||
}
|
||||
|
||||
void lcdPrint(String in){
|
||||
lcd.setCursor(0,1);
|
||||
lcd.print(" ");
|
||||
lcd.setCursor(0,1);
|
||||
lcd.print(in);
|
||||
}
|
||||
|
||||
void updateKnob(){
|
||||
int knobInput = 0;
|
||||
knobInput = map(analogRead(pin_knob), 0, 1024, 10, 0)-1;
|
||||
|
||||
if (knobInput != prevKnobInput) {
|
||||
LogSerial.print("Knob input: ");
|
||||
LogSerial.println(knobInputTotal);
|
||||
setSlide(2);
|
||||
//LogSerial.print("Analog: ");
|
||||
//LogSerial.println(analogRead(pin_knob));
|
||||
|
||||
added = false;
|
||||
prevKnobInput = knobInput;
|
||||
}
|
||||
else if (!added){
|
||||
knobInputTotal += String(knobInput);
|
||||
lcdPrint(knobInputTotal);
|
||||
added = true;
|
||||
//LogSerial.print("Knob current: ");
|
||||
//LogSerial.println(knobInput);
|
||||
}
|
||||
if(knobInputTotal == knob_pass){
|
||||
knobInputTotal = "";
|
||||
taskDone(1);
|
||||
lcdPrint(LCD_CORRECT);
|
||||
log("knob password ok.");
|
||||
}
|
||||
else if(knobInputTotal.length() == knob_pass.length()){
|
||||
knobInputTotal = "";
|
||||
lcdPrint(LCD_INCORRECT);
|
||||
}
|
||||
}
|
||||
|
||||
void setupPins(){
|
||||
|
||||
//inicjalizacja pinow idacych do RPi
|
||||
//piny do konwertera poziomow
|
||||
pinMode(pin_rpi_neg, OUTPUT);
|
||||
digitalWrite(pin_rpi_neg, LOW);
|
||||
pinMode(pin_rpi_pos, OUTPUT);
|
||||
digitalWrite(pin_rpi_pos, HIGH);
|
||||
|
||||
//inicjalizacja przerwan PCINT idacych od RPi
|
||||
pinMode(pin_rpi_win4, INPUT); //nie moze byc pullup, bo podciagalby do 5V - te piny trzyma w stanie wysokim RPi
|
||||
enableInterrupt(pin_rpi_win4, win4ISR, CHANGE);
|
||||
pinMode(pin_rpi_win9, INPUT);
|
||||
enableInterrupt(pin_rpi_win9, win9ISR, CHANGE);
|
||||
pinMode(pin_rpi_win10, INPUT);
|
||||
enableInterrupt(pin_rpi_win10, win10ISR, CHANGE);
|
||||
|
||||
//piny slajdow
|
||||
pinMode(pin_rpi_slide1, OUTPUT);
|
||||
digitalWrite(pin_rpi_slide1, HIGH); //tu moze byc wysoki, bo jestesmy za konwerterem poziomow
|
||||
pinMode(pin_rpi_slide2, OUTPUT);
|
||||
digitalWrite(pin_rpi_slide2, HIGH);
|
||||
pinMode(pin_rpi_slide3, OUTPUT);
|
||||
digitalWrite(pin_rpi_slide3, HIGH);
|
||||
pinMode(pin_rpi_slide5, OUTPUT);
|
||||
digitalWrite(pin_rpi_slide5, HIGH);
|
||||
pinMode(pin_rpi_slide6, OUTPUT);
|
||||
digitalWrite(pin_rpi_slide6, HIGH);
|
||||
pinMode(pin_rpi_slide_win, INPUT);
|
||||
//pinMode(pin_rpi_slide_win, OUTPUT);
|
||||
//digitalWrite(pin_rpi_slide_win, HIGH); //zostawiamy plywajacy, zeby pullup robilo RPi, ale tylko to na scianie A
|
||||
|
||||
//inicjalizacja przerwan PCINT podlaczonych do kontrolerow zagadek
|
||||
pinMode(pin_key, INPUT_PULLUP);
|
||||
enableInterrupt(pin_key, pin_keyISR, CHANGE);
|
||||
pinMode(pin_foambtn, INPUT_PULLUP);
|
||||
enableInterrupt(pin_foambtn, pin_foambtnISR, CHANGE);
|
||||
pinMode(pin_maze, INPUT_PULLUP);
|
||||
enableInterrupt(pin_maze, pin_mazeISR, CHANGE);
|
||||
|
||||
//inicjalizacja PCINT wejsc korby
|
||||
pinMode(pin_dynamo1, INPUT_PULLUP);
|
||||
enableInterrupt(pin_dynamo1, pin_dynamo1ISR, CHANGE);
|
||||
pinMode(pin_dynamo2, INPUT_PULLUP);
|
||||
enableInterrupt(pin_dynamo2, pin_dynamo2ISR, CHANGE);
|
||||
pinMode(pin_dynamo3, INPUT_PULLUP);
|
||||
enableInterrupt(pin_dynamo3, pin_dynamo3ISR, CHANGE);
|
||||
|
||||
pinMode(pin_drawer_relay, OUTPUT);
|
||||
digitalWrite(pin_drawer_relay, LOW);
|
||||
|
||||
|
||||
//inicjalizacja pinow LEDow korby
|
||||
for(int i=0; i<6; i++){
|
||||
pinMode(A1+i, OUTPUT);
|
||||
digitalWrite(A1+i, LOW);
|
||||
}
|
||||
|
||||
|
||||
//inicjalizacja pinow LEDów na panelu
|
||||
for(int i=0; i<N_TASKS; i++){
|
||||
pinMode(taskPins[i], OUTPUT);
|
||||
digitalWrite(taskPins[i], LOW);
|
||||
}
|
||||
|
||||
log("pin setup done.");
|
||||
}
|
||||
|
||||
void setup() {
|
||||
// set the digital pin as output:
|
||||
pinMode(13, OUTPUT);
|
||||
LogSerial.begin(115200);
|
||||
CommandSerial.begin(9600);
|
||||
setupPins();
|
||||
keypad.addEventListener(keypadEvent);
|
||||
prevKnobInput = map(analogRead(pin_knob), 0, 1024, 0, 10);
|
||||
lcd.init();
|
||||
// Print a message to the LCD.
|
||||
lcd.backlight();
|
||||
lcd.setCursor(0,0);
|
||||
lcd.print(LCD_PROMPT);
|
||||
log("program starts.");
|
||||
/*taskDone(0);
|
||||
taskDone(3);
|
||||
taskDone(4);
|
||||
taskDone(5);*/
|
||||
|
||||
}
|
||||
|
||||
int incomingByte;
|
||||
void loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
|
||||
if (CommandSerial.available() > 0) {
|
||||
// read the oldest byte in the serial buffer:
|
||||
incomingByte = CommandSerial.read();
|
||||
/* if (incomingByte == 'A') {
|
||||
taskDone(0);
|
||||
}
|
||||
if (incomingByte == 'a') {
|
||||
taskUnDone(0);
|
||||
}*/
|
||||
//komunikacja po UART z arduwifi
|
||||
if (incomingByte > 64 && incomingByte < 75){
|
||||
taskDone(incomingByte-65);
|
||||
}else if(incomingByte > 96 && incomingByte < 107){
|
||||
taskUnDone(incomingByte-97);
|
||||
}else if(incomingByte == 'X'){
|
||||
for(int i=0; i<N_TASKS; i++){
|
||||
taskDone(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
//aktualizowanie stanu zagadek
|
||||
if (currentMillis - previousMillis >= TICK) {
|
||||
// save the last time you blinked the LED
|
||||
previousMillis = currentMillis;
|
||||
logTasks();
|
||||
updateTasks();
|
||||
}
|
||||
//aktualizowanie kodu z potencjometru
|
||||
if (currentMillis - previousMillis2 >= TICK2) {
|
||||
// save the last time you blinked the LED
|
||||
previousMillis2 = currentMillis;
|
||||
updateKnob();
|
||||
}
|
||||
keypad.getKey();
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user