mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-09 08:38:03 -06:00
Mostly random stuff
This commit is contained in:
@@ -17,6 +17,8 @@ import com.astatin3.scoutingapp2025.databinding.ActivityMainBinding;
|
||||
|
||||
import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
|
||||
@@ -36,6 +38,8 @@ public class MainActivity extends AppCompatActivity {
|
||||
fields.save(fields.pitsFieldsFilename, fields.default_pit_fields);
|
||||
}
|
||||
|
||||
Objects.requireNonNull(getSupportActionBar()).hide();
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
|
||||
@@ -55,7 +55,7 @@ public class ScoutingDataWriter {
|
||||
dataType[] dataTypes = new dataType[objects.size()-2];
|
||||
|
||||
int version = ((int)objects.get(0).get());
|
||||
System.out.println(version);
|
||||
// System.out.println(version);
|
||||
String username = (String) objects.get(1).get();
|
||||
|
||||
for(int i = 0; i < values[version].length; i++){
|
||||
|
||||
@@ -25,7 +25,7 @@ public class fields {
|
||||
new sliderType("Test", 128, 64, 256),
|
||||
new notesType("notes", "<no-notes>"),
|
||||
},{
|
||||
new sliderType("How good is robot", 5, 1, 10),
|
||||
new sliderType("How good is robot", 5, 5, 10),
|
||||
new sliderType("Test", 128, 64, 256),
|
||||
new dropdownType("test-dropdown", new String[]{"Test1", "test2", "Three"}, 1),
|
||||
new notesType("notes", "<no-notes>"),
|
||||
@@ -70,7 +70,7 @@ public class fields {
|
||||
public static inputType[][] load(String filename){
|
||||
byte[] bytes = fileEditor.readFile(filename);
|
||||
|
||||
System.out.println(bytes);
|
||||
// System.out.println(bytes);
|
||||
|
||||
try {
|
||||
BuiltByteParser bbp = new BuiltByteParser(bytes);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.astatin3.scoutingapp2025.types.input;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -10,10 +11,17 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.astatin3.scoutingapp2025.R;
|
||||
import com.astatin3.scoutingapp2025.types.data.dataType;
|
||||
import com.astatin3.scoutingapp2025.types.data.intType;
|
||||
import com.astatin3.scoutingapp2025.utility.BuiltByteParser;
|
||||
import com.astatin3.scoutingapp2025.utility.ByteBuilder;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
import com.github.mikephil.charting.charts.PieChart;
|
||||
import com.github.mikephil.charting.data.Entry;
|
||||
import com.github.mikephil.charting.data.PieData;
|
||||
import com.github.mikephil.charting.data.PieDataSet;
|
||||
import com.github.mikephil.charting.data.PieEntry;
|
||||
import com.skydoves.powerspinner.IconSpinnerAdapter;
|
||||
import com.skydoves.powerspinner.IconSpinnerItem;
|
||||
import com.skydoves.powerspinner.OnSpinnerItemSelectedListener;
|
||||
@@ -69,6 +77,7 @@ public class dropdownType extends inputType {
|
||||
|
||||
dropdown.setPadding(10,10,10,10);
|
||||
dropdown.setBackgroundColor(0xf0000000);
|
||||
dropdown.setTextColor(0xff00ff00);
|
||||
dropdown.setTextSize(15);
|
||||
dropdown.setArrowGravity(SpinnerGravity.END);
|
||||
dropdown.setArrowPadding(8);
|
||||
@@ -114,16 +123,47 @@ public class dropdownType extends inputType {
|
||||
tv.setTextSize(18);
|
||||
parent.addView(tv);
|
||||
}
|
||||
private static int[] generateEquidistantColors(int N) {
|
||||
int[] colors = new int[N];
|
||||
float[] hsv = new float[3]; // Hue, Saturation, Value
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
float hue = i * 1.0F / N;
|
||||
hsv[0] = hue * 360; // Convert hue to degrees (0 to 360)
|
||||
hsv[1] = 1; // Maximum saturation
|
||||
hsv[2] = 1; // Maximum brightness (value)
|
||||
|
||||
colors[i] = Color.HSVToColor(hsv);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
public void add_compiled_view(LinearLayout parent, dataType[] data){
|
||||
TextView tv = new TextView(parent.getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
PieChart chart = new PieChart(parent.getContext());
|
||||
FrameLayout.LayoutParams layout = new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("<add pie chart thing here>");
|
||||
tv.setTextSize(20);
|
||||
parent.addView(tv);
|
||||
);
|
||||
layout.height = 350;
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
parent.addView(chart);
|
||||
|
||||
int[] data_2 = new int[text_options.length];
|
||||
for(int i = 0; i < data.length; i++)
|
||||
data_2[(int) data[i].get()]++;
|
||||
|
||||
List<PieEntry> entries = new ArrayList<>();
|
||||
for(int i = 0; i < data_2.length; i++) {
|
||||
PieEntry entry = new PieEntry((float) data_2[i], text_options[i]);
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
PieDataSet pieDataSet = new PieDataSet(entries, name);
|
||||
pieDataSet.setColors(generateEquidistantColors(text_options.length));
|
||||
PieData pieData = new PieData(pieDataSet);
|
||||
chart.setDrawHoleEnabled(false);
|
||||
chart.setData(pieData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class sliderType extends inputType {
|
||||
public View createView(Context context, Function<dataType, Integer> onUpdate){
|
||||
slider = new Slider(context);
|
||||
setViewValue(default_value);
|
||||
slider.setStepSize((float) 1 / max);
|
||||
slider.setStepSize((float) 1 / (max-min));
|
||||
slider.addOnChangeListener(new Slider.OnChangeListener() {
|
||||
@Override
|
||||
public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
|
||||
@@ -75,7 +75,7 @@ public class sliderType extends inputType {
|
||||
public void setViewValue(Object value) {
|
||||
if(slider == null) return;
|
||||
float slider_position = (float) ((int) value-min) / (max-min);
|
||||
float step_size = (float) 1/max;
|
||||
float step_size = (float) 1/(max-min);
|
||||
int round_position = Math.round(slider_position / step_size);
|
||||
slider.setValue(round_position*step_size);
|
||||
}
|
||||
@@ -136,9 +136,9 @@ public class sliderType extends inputType {
|
||||
chart.setLayoutParams(layout);
|
||||
chart.setBackgroundColor(0xff252025);
|
||||
|
||||
int[] values = new int[max-min];
|
||||
int[] values = new int[max-min+1];
|
||||
for (int i = 0; i < data.length; i++)
|
||||
values[(int) data[i].get()-min-1]++;
|
||||
values[(int) data[i].get()-min]++;
|
||||
|
||||
|
||||
int[] temp = new int[data.length];
|
||||
@@ -165,7 +165,7 @@ public class sliderType extends inputType {
|
||||
float stdDev = calculateStandardDeviation(temp, mean);
|
||||
|
||||
// Generate normal distribution curve
|
||||
List<Entry> normalDistEntries = generateNormalDistribution(mean-min, stdDev, max-min, (max-min)/data.length);
|
||||
List<Entry> normalDistEntries = generateNormalDistribution(mean-min, stdDev, max-min+1, (max-min)/data.length);
|
||||
|
||||
|
||||
LineDataSet normalDistSet = new LineDataSet(normalDistEntries, "Normal Distribution");
|
||||
@@ -191,12 +191,12 @@ public class sliderType extends inputType {
|
||||
|
||||
dataSet.setValueTextColor(Color.RED);
|
||||
|
||||
chart.getXAxis().setTextColor(Color.BLUE);
|
||||
chart.getAxisLeft().setTextColor(Color.GREEN);
|
||||
chart.getAxisRight().setTextColor(Color.GREEN);
|
||||
chart.getXAxis().setTextColor(Color.WHITE);
|
||||
chart.getAxisLeft().setTextColor(Color.WHITE);
|
||||
chart.getAxisRight().setTextColor(Color.WHITE);
|
||||
|
||||
Legend legend = chart.getLegend();
|
||||
legend.setTextColor(Color.MAGENTA);
|
||||
legend.setTextColor(Color.WHITE);
|
||||
|
||||
parent.addView(chart);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class dataFragment extends Fragment {
|
||||
|
||||
frcEvent event = frcEvent.decode(fileEditor.readFile(evcode + ".eventdata"));
|
||||
|
||||
binding.overviewButton.setOnClickListener(v -> {
|
||||
binding.overviewView.setOnClickListener(v -> {
|
||||
binding.buttons.setVisibility(View.GONE);
|
||||
binding.overviewView.setVisibility(View.VISIBLE);
|
||||
binding.overviewView.start(binding, event);
|
||||
|
||||
+10
-9
@@ -15,17 +15,18 @@ import com.astatin3.scoutingapp2025.databinding.FragmentDataBinding;
|
||||
import com.astatin3.scoutingapp2025.utility.fileEditor;
|
||||
import com.astatin3.scoutingapp2025.types.frcEvent;
|
||||
import com.astatin3.scoutingapp2025.types.frcMatch;
|
||||
import com.astatin3.scoutingapp2025.types.frcTeam;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class overviewView extends ScrollView {
|
||||
public overviewView(@NonNull Context context) {
|
||||
public class statusView extends ScrollView {
|
||||
public statusView(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
public overviewView(Context context, AttributeSet attributeSet){
|
||||
public statusView(Context context, AttributeSet attributeSet){
|
||||
super(context, attributeSet);
|
||||
}
|
||||
public static int color_found = 0x7f00ff00;
|
||||
public static int color_not_found = 0x7f7f0000;
|
||||
private void addTableText(TableRow tr, String textStr){
|
||||
TextView text = new TextView(getContext());
|
||||
text.setTextSize(18);
|
||||
@@ -34,6 +35,7 @@ public class overviewView extends ScrollView {
|
||||
tr.addView(text);
|
||||
}
|
||||
public void start(FragmentDataBinding binding, frcEvent event) {
|
||||
binding.matchTable.removeAllViews();
|
||||
binding.matchTable.setStretchAllColumns(true);
|
||||
add_pit_scouting(binding, event);
|
||||
add_match_scouting(binding, event);
|
||||
@@ -75,9 +77,9 @@ public class overviewView extends ScrollView {
|
||||
|
||||
text.setText(String.valueOf(num));
|
||||
if(fileEditor.fileExist(event.eventCode + "-" + num + ".pitscoutdata")){
|
||||
text.setBackgroundColor(0x3000FF00);
|
||||
text.setBackgroundColor(color_found);
|
||||
}else{
|
||||
text.setBackgroundColor(0x30FF0000);
|
||||
text.setBackgroundColor(color_not_found);
|
||||
}
|
||||
tr.addView(text);
|
||||
}
|
||||
@@ -108,7 +110,6 @@ public class overviewView extends ScrollView {
|
||||
addTableText(tr, "Blue-3");
|
||||
binding.matchTable.addView(tr);
|
||||
|
||||
boolean toggle = false;
|
||||
for(frcMatch match : event.matches){
|
||||
|
||||
tr = new TableRow(getContext());
|
||||
@@ -132,9 +133,9 @@ public class overviewView extends ScrollView {
|
||||
|
||||
text.setText(String.valueOf(team_num));
|
||||
if(fileEditor.fileExist(event.eventCode + "-" + match.matchIndex + "-" + alliance_position + "-" + team_num + ".matchscoutdata")){
|
||||
text.setBackgroundColor(0x3000FF00);
|
||||
text.setBackgroundColor(color_found);
|
||||
}else{
|
||||
text.setBackgroundColor(0x30FF0000);
|
||||
text.setBackgroundColor(color_not_found);
|
||||
}
|
||||
tr.addView(text);
|
||||
}
|
||||
+99
-11
@@ -16,7 +16,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.astatin3.scoutingapp2025.SettingsVersionStack.latestSettings;
|
||||
import com.astatin3.scoutingapp2025.databinding.FragmentDataBinding;
|
||||
import com.astatin3.scoutingapp2025.scoutingData.ScoutingDataWriter;
|
||||
import com.astatin3.scoutingapp2025.scoutingData.fields;
|
||||
import com.astatin3.scoutingapp2025.scoutingData.transfer.transferType;
|
||||
@@ -25,18 +24,19 @@ import com.astatin3.scoutingapp2025.types.frcEvent;
|
||||
import com.astatin3.scoutingapp2025.types.frcTeam;
|
||||
import com.astatin3.scoutingapp2025.types.input.inputType;
|
||||
import com.astatin3.scoutingapp2025.utility.fileEditor;
|
||||
import com.google.android.material.divider.MaterialDivider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class searchView extends ConstraintLayout {
|
||||
public searchView(@NonNull Context context) {
|
||||
public class teamsView extends ConstraintLayout {
|
||||
public teamsView(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
public searchView(Context context, AttributeSet attributeSet){
|
||||
public teamsView(Context context, AttributeSet attributeSet){
|
||||
super(context, attributeSet);
|
||||
}
|
||||
|
||||
FragmentDataBinding binding;
|
||||
com.astatin3.scoutingapp2025.databinding.FragmentDataBinding binding;
|
||||
String evcode;
|
||||
frcEvent event;
|
||||
|
||||
@@ -47,7 +47,7 @@ public class searchView extends ConstraintLayout {
|
||||
inputType[] latest_pit_values;
|
||||
transferType[][] pit_transferValues;
|
||||
|
||||
public void init(FragmentDataBinding binding, frcEvent event){
|
||||
public void init(com.astatin3.scoutingapp2025.databinding.FragmentDataBinding binding, frcEvent event){
|
||||
this.binding = binding;
|
||||
this.evcode = event.eventCode;
|
||||
this.event = event;
|
||||
@@ -115,7 +115,7 @@ public class searchView extends ConstraintLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadTeam(frcTeam team, boolean compiled_mode){
|
||||
public void loadTeam(frcTeam team, boolean compiled_mode) {
|
||||
binding.searchArea.removeAllViews();
|
||||
|
||||
LinearLayout ll = new LinearLayout(getContext());
|
||||
@@ -148,6 +148,16 @@ public class searchView extends ConstraintLayout {
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(String.valueOf(team.teamNumber));
|
||||
tv.setTextSize(28);
|
||||
ll.addView(tv);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(team.teamName);
|
||||
tv.setTextSize(28);
|
||||
ll.addView(tv);
|
||||
@@ -162,8 +172,87 @@ public class searchView extends ConstraintLayout {
|
||||
tv.setTextSize(16);
|
||||
ll.addView(tv);
|
||||
|
||||
add_pit_data(ll, team);
|
||||
add_match_data(ll, team, compiled_mode);
|
||||
}
|
||||
|
||||
String[] files = fileEditor.getMatchesByTeamNum(team.teamNumber);
|
||||
public void add_pit_data(LinearLayout ll, frcTeam team){
|
||||
final String filename = evcode+"-"+team.teamNumber+".pitscoutdata";
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setPadding(0,10,0,10);
|
||||
tv.setText("----- Pit data -----");
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
if(!fileEditor.fileExist(filename)){
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("No pit data has been collected!");
|
||||
tv.setTextSize(23);
|
||||
ll.addView(tv);
|
||||
return;
|
||||
}
|
||||
|
||||
ScoutingDataWriter.ParsedScoutingDataResult psda = ScoutingDataWriter.load(filename, pit_values, pit_transferValues);
|
||||
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Pit scouting by " + psda.username);
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
for (int a = 0; a < psda.data.array.length; a++) {
|
||||
tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText(psda.data.array[a].name);
|
||||
tv.setTextSize(25);
|
||||
ll.addView(tv);
|
||||
|
||||
|
||||
latest_pit_values[a].add_individual_view(ll, psda.data.array[a]);
|
||||
}
|
||||
}
|
||||
|
||||
public void add_match_data(LinearLayout ll, frcTeam team, boolean compiled_mode){
|
||||
String[] files = fileEditor.getMatchesByTeamNum(evcode, team.teamNumber);
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setLayoutParams(new FrameLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("----- Match data -----");
|
||||
tv.setPadding(0,10,0,10);
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
ll.addView(new MaterialDivider(getContext()));
|
||||
|
||||
if(files.length == 0){
|
||||
tv = new TextView(getContext());
|
||||
@@ -179,7 +268,6 @@ public class searchView extends ConstraintLayout {
|
||||
}
|
||||
|
||||
if(!compiled_mode){
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
String[] split = files[i].split("-");
|
||||
int match_num = Integer.parseInt(split[1]);
|
||||
@@ -191,9 +279,9 @@ public class searchView extends ConstraintLayout {
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
tv.setPadding(0, 20, 0, 5);
|
||||
tv.setPadding(0, 40, 0, 5);
|
||||
tv.setGravity(Gravity.CENTER_HORIZONTAL);
|
||||
tv.setText("Match " + (match_num) + " by " + psda.username);
|
||||
tv.setText("M" + (match_num) + " " + split[2] + "-" + split[3] + " by " + psda.username);
|
||||
tv.setTextSize(30);
|
||||
ll.addView(tv);
|
||||
|
||||
@@ -294,6 +294,9 @@ public class matchScoutingView extends ConstraintLayout {
|
||||
types[i] = latest_values[i].getViewValue();
|
||||
}
|
||||
|
||||
System.out.println(ScoutingDataWriter.save(values.length-1, username, filename, types));
|
||||
if(ScoutingDataWriter.save(values.length-1, username, filename, types))
|
||||
System.out.println("Saved!");
|
||||
else
|
||||
System.out.println("Error saving");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ public class pitScoutingView extends ConstraintLayout {
|
||||
ArrayList<dataType> dataTypes;
|
||||
|
||||
public void save(){
|
||||
System.out.println("Saved!");
|
||||
edited = false;
|
||||
set_indicator_color(saved_color);
|
||||
|
||||
@@ -66,7 +65,10 @@ public class pitScoutingView extends ConstraintLayout {
|
||||
types[i] = latest_values[i].getViewValue();
|
||||
}
|
||||
|
||||
System.out.println(ScoutingDataWriter.save(values.length-1, username, filename, types));
|
||||
if(ScoutingDataWriter.save(values.length-1, username, filename, types))
|
||||
System.out.println("Saved!");
|
||||
else
|
||||
System.out.println("Error saving");
|
||||
}
|
||||
|
||||
public void set_indicator_color(int color){
|
||||
|
||||
@@ -219,7 +219,7 @@ public final class fileEditor {
|
||||
}
|
||||
|
||||
|
||||
public static String[] getMatchesByTeamNum(int teamNum){
|
||||
public static String[] getMatchesByTeamNum(String evcode, int teamNum){
|
||||
File f = new File(baseDir);
|
||||
File[] files = f.listFiles();
|
||||
|
||||
@@ -228,7 +228,8 @@ public final class fileEditor {
|
||||
if(files == null){return new String[0];}
|
||||
|
||||
for (File file : files) {
|
||||
if(!file.isDirectory() && file.getName().endsWith(teamNum+".matchscoutdata")) {
|
||||
String name = file.getName();
|
||||
if(!file.isDirectory() && name.startsWith(evcode+"-") && name.endsWith("-"+teamNum+".matchscoutdata")) {
|
||||
outFiles.add(file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user