mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-17 22:23:10 +03:00
Factored out some common build variables
This commit is contained in:
@ -29,7 +29,6 @@ import java.io.BufferedReader;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -51,12 +50,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
|
|
||||||
private Sketch sketch;
|
private Sketch sketch;
|
||||||
|
|
||||||
private String buildPath;
|
|
||||||
private String toolsPath;
|
|
||||||
private String corePath;
|
|
||||||
private String variantPath;
|
|
||||||
private String primaryClassName;
|
private String primaryClassName;
|
||||||
private String board;
|
|
||||||
private List<File> objectFiles;
|
private List<File> objectFiles;
|
||||||
|
|
||||||
private PreferencesMap prefs;
|
private PreferencesMap prefs;
|
||||||
@ -77,43 +71,34 @@ public class Compiler implements MessageConsumer {
|
|||||||
String _primaryClassName, boolean _verbose)
|
String _primaryClassName, boolean _verbose)
|
||||||
throws RunnerException {
|
throws RunnerException {
|
||||||
sketch = _sketch;
|
sketch = _sketch;
|
||||||
buildPath = _buildPath;
|
|
||||||
primaryClassName = _primaryClassName;
|
primaryClassName = _primaryClassName;
|
||||||
verbose = _verbose;
|
verbose = _verbose;
|
||||||
objectFiles = new ArrayList<File>();
|
objectFiles = new ArrayList<File>();
|
||||||
|
|
||||||
PreferencesMap boardPreferences = Base.getBoardPreferences();
|
|
||||||
|
|
||||||
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
TargetPlatform targetPlatform = Base.getTargetPlatform();
|
||||||
PreferencesMap platformPreferences = targetPlatform.getPreferences();
|
|
||||||
|
|
||||||
// Merge all the global preference configuration in order of priority
|
// Merge all the global preference configuration in order of priority
|
||||||
prefs = new PreferencesMap();
|
prefs = new PreferencesMap();
|
||||||
prefs.putAll(Preferences.getMap());
|
prefs.putAll(Preferences.getMap());
|
||||||
prefs.putAll(platformPreferences);
|
prefs.putAll(targetPlatform.getPreferences());
|
||||||
prefs.putAll(boardPreferences);
|
prefs.putAll(Base.getBoardPreferences());
|
||||||
for (String k : prefs.keySet()) {
|
for (String k : prefs.keySet()) {
|
||||||
if (prefs.get(k) == null)
|
if (prefs.get(k) == null)
|
||||||
prefs.put(k, "");
|
prefs.put(k, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
toolsPath = prefs.get("compiler.path");
|
prefs.put("build.path", _buildPath);
|
||||||
if (toolsPath == null) {
|
|
||||||
toolsPath = Base.getAvrBasePath();
|
String idePath = System.getProperty("user.dir");
|
||||||
} else {
|
if (Base.isMacOS())
|
||||||
// Put in the system path in the compiler path if available
|
idePath += "/Arduino.app/Contents/Resources/Java";
|
||||||
MessageFormat compileFormat = new MessageFormat(toolsPath);
|
prefs.put("ide.path", idePath);
|
||||||
String basePath = System.getProperty("user.dir");
|
prefs.put("ide.version", "" + Base.REVISION);
|
||||||
if (Base.isMacOS())
|
|
||||||
basePath += "/Arduino.app/Contents/Resources/Java";
|
|
||||||
Object[] Args = { basePath };
|
|
||||||
toolsPath = compileFormat.format(Args);
|
|
||||||
System.out.println("avrBasePath:new: " + toolsPath);
|
|
||||||
}
|
|
||||||
board = prefs.get("board");
|
|
||||||
if (board == "")
|
|
||||||
board = "_UNKNOWN";
|
|
||||||
|
|
||||||
|
if (!prefs.containsKey("compiler.path"))
|
||||||
|
prefs.put("compiler.path", Base.getAvrBasePath());
|
||||||
|
|
||||||
|
// Core folder
|
||||||
String core = prefs.get("build.core");
|
String core = prefs.get("build.core");
|
||||||
if (core == null) {
|
if (core == null) {
|
||||||
RunnerException re = new RunnerException(
|
RunnerException re = new RunnerException(
|
||||||
@ -121,42 +106,49 @@ public class Compiler implements MessageConsumer {
|
|||||||
re.hideStackTrace();
|
re.hideStackTrace();
|
||||||
throw re;
|
throw re;
|
||||||
}
|
}
|
||||||
File coreFolder;
|
TargetPlatform tp;
|
||||||
if (!core.contains(":")) {
|
if (!core.contains(":")) {
|
||||||
TargetPlatform t = Base.getTargetPlatform();
|
tp = targetPlatform;
|
||||||
coreFolder = new File(t.getFolder(), "cores");
|
|
||||||
coreFolder = new File(coreFolder, core);
|
|
||||||
} else {
|
} else {
|
||||||
String[] split = core.split(":", 2);
|
String[] split = core.split(":", 2);
|
||||||
TargetPlatform t = Base.getTargetPlatform(split[0], Preferences
|
tp = Base.getTargetPlatform(split[0], Preferences.get("target_platform"));
|
||||||
.get("target_platform"));
|
core = split[1];
|
||||||
coreFolder = new File(t.getFolder(), "cores");
|
|
||||||
coreFolder = new File(coreFolder, split[1]);
|
|
||||||
}
|
}
|
||||||
corePath = coreFolder.getAbsolutePath();
|
File coreFolder = new File(tp.getFolder(), "cores");
|
||||||
|
coreFolder = new File(coreFolder, core);
|
||||||
String variant = boardPreferences.get("build.variant");
|
prefs.put("build.core.path", coreFolder.getAbsolutePath());
|
||||||
variantPath = null;
|
|
||||||
|
// System Folder
|
||||||
|
File systemFolder = targetPlatform.getFolder();
|
||||||
|
systemFolder = new File(systemFolder, "system");
|
||||||
|
prefs.put("build.system.path", systemFolder.getAbsolutePath());
|
||||||
|
|
||||||
|
// Variant Folder
|
||||||
|
String variantPath;
|
||||||
|
String variant = prefs.get("build.variant");
|
||||||
if (variant != null) {
|
if (variant != null) {
|
||||||
File variantFolder;
|
TargetPlatform t;
|
||||||
if (!variant.contains(":")) {
|
if (!variant.contains(":")) {
|
||||||
TargetPlatform t = Base.getTargetPlatform();
|
t = targetPlatform;
|
||||||
variantFolder = new File(t.getFolder(), "variants");
|
|
||||||
variantFolder = new File(variantFolder, variant);
|
|
||||||
} else {
|
} else {
|
||||||
String[] split = variant.split(":", 2);
|
String[] split = variant.split(":", 2);
|
||||||
TargetPlatform t = Base.getTargetPlatform(split[0], Preferences
|
t = Base.getTargetPlatform(split[0], Preferences
|
||||||
.get("target_platform"));
|
.get("target_platform"));
|
||||||
variantFolder = new File(t.getFolder(), "variants");
|
variant = split[1];
|
||||||
variantFolder = new File(variantFolder, split[1]);
|
|
||||||
}
|
}
|
||||||
|
File variantFolder = new File(t.getFolder(), "variants");
|
||||||
|
variantFolder = new File(variantFolder, variant);
|
||||||
variantPath = variantFolder.getAbsolutePath();
|
variantPath = variantFolder.getAbsolutePath();
|
||||||
|
prefs.put("build.variant.path", variantPath);
|
||||||
|
} else {
|
||||||
|
variantPath = null;
|
||||||
|
prefs.put("build.variant.path", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0. include paths for core + all libraries
|
// 0. include paths for core + all libraries
|
||||||
sketch.setCompilingProgress(20);
|
sketch.setCompilingProgress(20);
|
||||||
List<String> includePaths = new ArrayList<String>();
|
List<String> includePaths = new ArrayList<String>();
|
||||||
includePaths.add(corePath);
|
includePaths.add(prefs.get("build.core.path"));
|
||||||
if (variantPath != null)
|
if (variantPath != null)
|
||||||
includePaths.add(variantPath);
|
includePaths.add(variantPath);
|
||||||
for (File file : sketch.getImportedLibraries())
|
for (File file : sketch.getImportedLibraries())
|
||||||
@ -174,11 +166,11 @@ public class Compiler implements MessageConsumer {
|
|||||||
// 3. compile the core, outputting .o files to <buildPath> and then
|
// 3. compile the core, outputting .o files to <buildPath> and then
|
||||||
// collecting them into the core.a library file.
|
// collecting them into the core.a library file.
|
||||||
sketch.setCompilingProgress(50);
|
sketch.setCompilingProgress(50);
|
||||||
compileCore(variant);
|
compileCore();
|
||||||
|
|
||||||
// 4. link it all together into the .elf file
|
// 4. link it all together into the .elf file
|
||||||
sketch.setCompilingProgress(60);
|
sketch.setCompilingProgress(60);
|
||||||
compileLink(corePath, includePaths);
|
compileLink(includePaths);
|
||||||
|
|
||||||
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
||||||
sketch.setCompilingProgress(70);
|
sketch.setCompilingProgress(70);
|
||||||
@ -316,7 +308,8 @@ public class Compiler implements MessageConsumer {
|
|||||||
stringList.add(string);
|
stringList.add(string);
|
||||||
}
|
}
|
||||||
command = stringList.toArray(new String[stringList.size()]);
|
command = stringList.toArray(new String[stringList.size()]);
|
||||||
|
if (command.length == 0)
|
||||||
|
return;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if (verbose || Preferences.getBoolean("build.verbose")) {
|
if (verbose || Preferences.getBoolean("build.verbose")) {
|
||||||
@ -391,6 +384,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
// can't use replaceAll() because the path may have characters in it which
|
// can't use replaceAll() because the path may have characters in it which
|
||||||
// have meaning in a regular expression.
|
// have meaning in a regular expression.
|
||||||
if (!verbose) {
|
if (!verbose) {
|
||||||
|
String buildPath = prefs.get("build.path");
|
||||||
while ((i = s.indexOf(buildPath + File.separator)) != -1) {
|
while ((i = s.indexOf(buildPath + File.separator)) != -1) {
|
||||||
s = s.substring(0, i) + s.substring(i + (buildPath + File.separator).length());
|
s = s.substring(0, i) + s.substring(i + (buildPath + File.separator).length());
|
||||||
}
|
}
|
||||||
@ -479,8 +473,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
dict.put("includes", includes);
|
dict.put("includes", includes);
|
||||||
dict.put("source_file", sourceName);
|
dict.put("source_file", sourceName);
|
||||||
dict.put("object_file", objectName);
|
dict.put("object_file", objectName);
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("core_path", corePath);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String cmd = prefs.get("recipe.S.o.pattern");
|
String cmd = prefs.get("recipe.S.o.pattern");
|
||||||
@ -500,8 +492,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
dict.put("includes", includes);
|
dict.put("includes", includes);
|
||||||
dict.put("source_file", sourceName);
|
dict.put("source_file", sourceName);
|
||||||
dict.put("object_file", objectName);
|
dict.put("object_file", objectName);
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("core_path", corePath);
|
|
||||||
|
|
||||||
String cmd = prefs.get("recipe.c.o.pattern");
|
String cmd = prefs.get("recipe.c.o.pattern");
|
||||||
try {
|
try {
|
||||||
@ -521,8 +511,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
dict.put("includes", includes);
|
dict.put("includes", includes);
|
||||||
dict.put("source_file", sourceName);
|
dict.put("source_file", sourceName);
|
||||||
dict.put("object_file", objectName);
|
dict.put("object_file", objectName);
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("core_path", corePath);
|
|
||||||
|
|
||||||
String cmd = prefs.get("recipe.cpp.o.pattern");
|
String cmd = prefs.get("recipe.cpp.o.pattern");
|
||||||
try {
|
try {
|
||||||
@ -565,6 +553,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
|
|
||||||
// 1. compile the sketch (already in the buildPath)
|
// 1. compile the sketch (already in the buildPath)
|
||||||
void compileSketch(List<String> includePaths) throws RunnerException {
|
void compileSketch(List<String> includePaths) throws RunnerException {
|
||||||
|
String buildPath = prefs.get("build.path");
|
||||||
objectFiles.addAll(compileFiles(buildPath, new File(buildPath), false,
|
objectFiles.addAll(compileFiles(buildPath, new File(buildPath), false,
|
||||||
includePaths));
|
includePaths));
|
||||||
}
|
}
|
||||||
@ -574,7 +563,8 @@ public class Compiler implements MessageConsumer {
|
|||||||
void compileLibraries(List<String> includePaths) throws RunnerException {
|
void compileLibraries(List<String> includePaths) throws RunnerException {
|
||||||
|
|
||||||
for (File libraryFolder : sketch.getImportedLibraries()) {
|
for (File libraryFolder : sketch.getImportedLibraries()) {
|
||||||
File outputFolder = new File(buildPath, libraryFolder.getName());
|
String outputPath = prefs.get("build.path");
|
||||||
|
File outputFolder = new File(outputPath, libraryFolder.getName());
|
||||||
File utilityFolder = new File(libraryFolder, "utility");
|
File utilityFolder = new File(libraryFolder, "utility");
|
||||||
createFolder(outputFolder);
|
createFolder(outputFolder);
|
||||||
// this library can use includes in its utility/ folder
|
// this library can use includes in its utility/ folder
|
||||||
@ -593,23 +583,28 @@ public class Compiler implements MessageConsumer {
|
|||||||
|
|
||||||
// 3. compile the core, outputting .o files to <buildPath> and then
|
// 3. compile the core, outputting .o files to <buildPath> and then
|
||||||
// collecting them into the core.a library file.
|
// collecting them into the core.a library file.
|
||||||
void compileCore(String variant)
|
void compileCore()
|
||||||
throws RunnerException {
|
throws RunnerException {
|
||||||
|
|
||||||
|
String corePath = prefs.get("build.core.path");
|
||||||
|
String variantPath = prefs.get("build.variant.path");
|
||||||
|
String buildPath = prefs.get("build.path");
|
||||||
|
|
||||||
List<String> includePaths = new ArrayList<String>();
|
List<String> includePaths = new ArrayList<String>();
|
||||||
includePaths.add(corePath); // include core path only
|
includePaths.add(corePath); // include core path only
|
||||||
if (variantPath != null)
|
if (!variantPath.isEmpty())
|
||||||
includePaths.add(variantPath);
|
includePaths.add(variantPath);
|
||||||
|
|
||||||
List<File> coreObjectFiles = compileFiles(buildPath, new File(corePath),
|
List<File> coreObjectFiles = compileFiles(buildPath, new File(corePath),
|
||||||
true, includePaths);
|
true, includePaths);
|
||||||
|
if (!variantPath.isEmpty())
|
||||||
|
coreObjectFiles.addAll(compileFiles(buildPath, new File(variantPath),
|
||||||
|
true, includePaths));
|
||||||
|
|
||||||
for (File file : coreObjectFiles) {
|
for (File file : coreObjectFiles) {
|
||||||
|
|
||||||
PreferencesMap dict = new PreferencesMap(prefs);
|
PreferencesMap dict = new PreferencesMap(prefs);
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("ide_version", "" + Base.REVISION);
|
dict.put("ide_version", "" + Base.REVISION);
|
||||||
dict.put("build_path", buildPath + File.separator);
|
|
||||||
dict.put("archive_file", "core.a");
|
dict.put("archive_file", "core.a");
|
||||||
dict.put("object_file", file.getAbsolutePath());
|
dict.put("object_file", file.getAbsolutePath());
|
||||||
|
|
||||||
@ -625,7 +620,7 @@ public class Compiler implements MessageConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. link it all together into the .elf file
|
// 4. link it all together into the .elf file
|
||||||
void compileLink(String corePath, List<String> includePaths)
|
void compileLink(List<String> includePaths)
|
||||||
throws RunnerException {
|
throws RunnerException {
|
||||||
|
|
||||||
// TODO: Make the --relax thing in configuration files.
|
// TODO: Make the --relax thing in configuration files.
|
||||||
@ -644,14 +639,10 @@ public class Compiler implements MessageConsumer {
|
|||||||
PreferencesMap dict = new PreferencesMap(prefs);
|
PreferencesMap dict = new PreferencesMap(prefs);
|
||||||
dict.put("compiler.c.elf.flags", dict
|
dict.put("compiler.c.elf.flags", dict
|
||||||
.get("compiler.c.elf.flags" + optRelax));
|
.get("compiler.c.elf.flags" + optRelax));
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("build_path", buildPath + File.separator);
|
|
||||||
dict.put("archive_file", "core.a");
|
dict.put("archive_file", "core.a");
|
||||||
dict.put("project_name", primaryClassName);
|
dict.put("project_name", primaryClassName);
|
||||||
dict.put("object_files", objectFileList);
|
dict.put("object_files", objectFileList);
|
||||||
dict.put("ide_version", "" + Base.REVISION);
|
dict.put("ide_version", "" + Base.REVISION);
|
||||||
dict.put("core_path", corePath);
|
|
||||||
dict.put("variant_path", variantPath + File.separator);
|
|
||||||
|
|
||||||
String[] cmdArray;
|
String[] cmdArray;
|
||||||
try {
|
try {
|
||||||
@ -666,8 +657,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
// 5. extract EEPROM data (from EEMEM directive) to .eep file.
|
||||||
void compileEep(List<String> includePaths) throws RunnerException {
|
void compileEep(List<String> includePaths) throws RunnerException {
|
||||||
PreferencesMap dict = new PreferencesMap(prefs);
|
PreferencesMap dict = new PreferencesMap(prefs);
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("build_path", buildPath + File.separator);
|
|
||||||
dict.put("project_name", primaryClassName);
|
dict.put("project_name", primaryClassName);
|
||||||
dict.put("ide_version", "" + Base.REVISION);
|
dict.put("ide_version", "" + Base.REVISION);
|
||||||
|
|
||||||
@ -684,8 +673,6 @@ public class Compiler implements MessageConsumer {
|
|||||||
// 6. build the .hex file
|
// 6. build the .hex file
|
||||||
void compileHex(List<String> includePaths) throws RunnerException {
|
void compileHex(List<String> includePaths) throws RunnerException {
|
||||||
PreferencesMap dict = new PreferencesMap(prefs);
|
PreferencesMap dict = new PreferencesMap(prefs);
|
||||||
dict.put("toolchain_path", toolsPath);
|
|
||||||
dict.put("build_path", buildPath + File.separator);
|
|
||||||
dict.put("project_name", primaryClassName);
|
dict.put("project_name", primaryClassName);
|
||||||
dict.put("ide_version", "" + Base.REVISION);
|
dict.put("ide_version", "" + Base.REVISION);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
name=Arduino
|
name=Arduino
|
||||||
# Default "compiler.path" is correct, change only if you want to overidde the initial value
|
# Default "compiler.path" is correct, change only if you want to overidde the initial value
|
||||||
#compiler.path={0}/hardware/tools/avr/bin/
|
#compiler.path={ide.path}/tools/avr/bin/..
|
||||||
compiler.c.cmd=avr-gcc
|
compiler.c.cmd=avr-gcc
|
||||||
compiler.c.flags=-c -g -Os -w -ffunction-sections -fdata-sections
|
compiler.c.flags=-c -g -Os -w -ffunction-sections -fdata-sections
|
||||||
compiler.c.elf.flags=-Os -Wl,--gc-sections
|
compiler.c.elf.flags=-Os -Wl,--gc-sections
|
||||||
@ -26,22 +26,22 @@ compiler.upload.flags=
|
|||||||
# --------------------
|
# --------------------
|
||||||
|
|
||||||
## Compile c files
|
## Compile c files
|
||||||
recipe.c.o.pattern={toolchain_path}{compiler.c.cmd} {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -D{software}={ide_version} {includes} {source_file} -o {object_file}
|
recipe.c.o.pattern={compiler.path}{compiler.c.cmd} {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -D{software}={ide.version} {includes} {source_file} -o {object_file}
|
||||||
|
|
||||||
## Compile c++ files
|
## Compile c++ files
|
||||||
recipe.cpp.o.pattern={toolchain_path}{compiler.cpp.cmd} {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -D{software}={ide_version} {includes} {source_file} -o {object_file}
|
recipe.cpp.o.pattern={compiler.path}{compiler.cpp.cmd} {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -D{software}={ide.version} {includes} {source_file} -o {object_file}
|
||||||
|
|
||||||
## Create archives
|
## Create archives
|
||||||
recipe.ar.pattern={toolchain_path}{compiler.ar.cmd} {compiler.ar.flags} {build_path}{archive_file} {object_file}
|
recipe.ar.pattern={compiler.path}{compiler.ar.cmd} {compiler.ar.flags} {build.path}/{archive_file} {object_file}
|
||||||
|
|
||||||
## Combine gc-sections, archives, and objects
|
## Combine gc-sections, archives, and objects
|
||||||
recipe.c.combine.pattern={toolchain_path}{compiler.c.elf.cmd} {compiler.c.elf.flags} -mmcu={build.mcu} -o {build_path}{project_name}.elf {object_files} {build_path}{archive_file} -L{build_path} -lm
|
recipe.c.combine.pattern={compiler.path}{compiler.c.elf.cmd} {compiler.c.elf.flags} -mmcu={build.mcu} -o {build.path}/{project_name}.elf {object_files} {build.path}/{archive_file} -L{build.path} -lm
|
||||||
|
|
||||||
## Create eeprom
|
## Create eeprom
|
||||||
recipe.objcopy.eep.pattern={toolchain_path}{compiler.objcopy.cmd} {compiler.objcopy.eep.flags} {build_path}{project_name}.elf {build_path}{project_name}.eep
|
recipe.objcopy.eep.pattern={compiler.path}{compiler.objcopy.cmd} {compiler.objcopy.eep.flags} {build.path}/{project_name}.elf {build.path}/{project_name}.eep
|
||||||
|
|
||||||
## Create hex
|
## Create hex
|
||||||
recipe.objcopy.hex.pattern={toolchain_path}{compiler.elf2hex.cmd} {compiler.elf2hex.flags} {build_path}{project_name}.elf {build_path}{project_name}.hex
|
recipe.objcopy.hex.pattern={compiler.path}{compiler.elf2hex.cmd} {compiler.elf2hex.flags} {build.path}/{project_name}.elf {build.path}/{project_name}.hex
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user