forked from JavaTX/JavaCompilerCore
modified: ../../src/de/dhbwstuttgart/core/JavaTXCompiler.java
modified: ../../src/de/dhbwstuttgart/typeinference/unify/RuleSet.java modified: ../../src/de/dhbwstuttgart/typeinference/unify/TypeUnify.java modified: ../../src/de/dhbwstuttgart/typeinference/unify/TypeUnifyTask.java modified: ../../target/JavaTXcompiler-0.1-jar-with-dependencies.jar Log-File entfernt
This commit is contained in:
parent
03ef170b6e
commit
dd8dbd755e
@ -110,39 +110,32 @@ public class JavaTXCompiler {
|
|||||||
|
|
||||||
TypeUnify unify = new TypeUnify();
|
TypeUnify unify = new TypeUnify();
|
||||||
Set<Set<UnifyPair>> results = new HashSet<>();
|
Set<Set<UnifyPair>> results = new HashSet<>();
|
||||||
try {
|
Set<List<Constraint<UnifyPair>>> cardProd = unifyCons.cartesianProduct();
|
||||||
FileWriter logFile = new FileWriter(new File(System.getProperty("user.dir")+"/test/logFiles/"+"log"));
|
for (List<Constraint<UnifyPair>> xCons : cardProd ){
|
||||||
logFile.write("FC:\\" + finiteClosure.toString()+"\n");
|
Set<UnifyPair> xConsSet = new HashSet<>();
|
||||||
for(SourceFile sf : this.sourceFiles.values()) {
|
for (Constraint<UnifyPair> constraint : xCons) {
|
||||||
logFile.write(ASTTypePrinter.print(sf));
|
xConsSet.addAll(constraint);
|
||||||
}
|
}
|
||||||
logFile.flush();
|
//.collect(Collectors.toCollection(ArrayList::new))))
|
||||||
Set<List<Constraint<UnifyPair>>> cardProd = unifyCons.cartesianProduct();
|
System.out.println(xConsSet);
|
||||||
for (List<Constraint<UnifyPair>> xCons : cardProd ){
|
Set<String> paraTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist()
|
||||||
Set<UnifyPair> xConsSet = new HashSet<>();
|
|
||||||
for (Constraint<UnifyPair> constraint : xCons) {
|
|
||||||
xConsSet.addAll(constraint);
|
|
||||||
}
|
|
||||||
//.collect(Collectors.toCollection(ArrayList::new))))
|
|
||||||
System.out.println(xConsSet);
|
|
||||||
Set<String> paraTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().map(y -> y.getParameterList().getFormalparalist()
|
|
||||||
.stream().filter(z -> z.getType() instanceof TypePlaceholder)
|
.stream().filter(z -> z.getType() instanceof TypePlaceholder)
|
||||||
.map(z -> ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection(HashSet::new)))
|
.map(z -> ((TypePlaceholder)z.getType()).getName()).collect(Collectors.toCollection(HashSet::new)))
|
||||||
.reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) )
|
.reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;}, (a,b) -> { a.addAll(b); return a;} ) )
|
||||||
.reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;} );
|
.reduce(new HashSet<String>(), (a,b) -> { a.addAll(b); return a;} );
|
||||||
|
|
||||||
Set<String> returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder)
|
Set<String> returnTypeVarNames = allClasses.stream().map(x -> x.getMethods().stream().filter(y -> y.getReturnType() instanceof TypePlaceholder)
|
||||||
.map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get();
|
.map(z -> ((TypePlaceholder)z.getReturnType()).getName()).collect(Collectors.toCollection(HashSet::new))).reduce((a,b) -> { a.addAll(b); return a;} ).get();
|
||||||
|
|
||||||
|
|
||||||
xConsSet = xConsSet.stream().map(x -> {
|
xConsSet = xConsSet.stream().map(x -> {
|
||||||
//Hier muss ueberlegt werden, ob
|
//Hier muss ueberlegt werden, ob
|
||||||
//1. alle Argument- und Retuntyp-Variablen in allen UnifyPairs
|
//1. alle Argument- und Retuntyp-Variablen in allen UnifyPairs
|
||||||
// mit disableWildcardtable() werden.
|
// mit disableWildcardtable() werden.
|
||||||
//2. alle Typvariablen mit Argument- oder Retuntyp-Variablen
|
//2. alle Typvariablen mit Argument- oder Retuntyp-Variablen
|
||||||
//in Beziehung auch auf disableWildcardtable() gesetzt werden muessen
|
//in Beziehung auch auf disableWildcardtable() gesetzt werden muessen
|
||||||
//PL 2018-04-23
|
//PL 2018-04-23
|
||||||
if ((x.getLhsType() instanceof PlaceholderType)) {
|
if ((x.getLhsType() instanceof PlaceholderType)) {
|
||||||
if (paraTypeVarNames.contains(x.getLhsType().getName())) {
|
if (paraTypeVarNames.contains(x.getLhsType().getName())) {
|
||||||
((PlaceholderType)x.getLhsType()).setVariance((byte)1);
|
((PlaceholderType)x.getLhsType()).setVariance((byte)1);
|
||||||
((PlaceholderType)x.getLhsType()).disableWildcardtable();
|
((PlaceholderType)x.getLhsType()).disableWildcardtable();
|
||||||
@ -151,8 +144,8 @@ public class JavaTXCompiler {
|
|||||||
((PlaceholderType)x.getLhsType()).setVariance((byte)-1);
|
((PlaceholderType)x.getLhsType()).setVariance((byte)-1);
|
||||||
((PlaceholderType)x.getLhsType()).disableWildcardtable();
|
((PlaceholderType)x.getLhsType()).disableWildcardtable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((x.getRhsType() instanceof PlaceholderType)) {
|
if ((x.getRhsType() instanceof PlaceholderType)) {
|
||||||
if (paraTypeVarNames.contains(x.getRhsType().getName())) {
|
if (paraTypeVarNames.contains(x.getRhsType().getName())) {
|
||||||
((PlaceholderType)x.getRhsType()).setVariance((byte)1);
|
((PlaceholderType)x.getRhsType()).setVariance((byte)1);
|
||||||
((PlaceholderType)x.getRhsType()).disableWildcardtable();
|
((PlaceholderType)x.getRhsType()).disableWildcardtable();
|
||||||
@ -161,8 +154,8 @@ public class JavaTXCompiler {
|
|||||||
((PlaceholderType)x.getRhsType()).setVariance((byte)-1);
|
((PlaceholderType)x.getRhsType()).setVariance((byte)-1);
|
||||||
((PlaceholderType)x.getRhsType()).disableWildcardtable();
|
((PlaceholderType)x.getRhsType()).disableWildcardtable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x;//HIER DIE JEWEILS RECHT BZW. LINKE SEITE AUF GLEICHE VARIANZ SETZEN WIE DIE JEWEILS ANDERE SEITE
|
return x;//HIER DIE JEWEILS RECHT BZW. LINKE SEITE AUF GLEICHE VARIANZ SETZEN WIE DIE JEWEILS ANDERE SEITE
|
||||||
}).map( y -> {
|
}).map( y -> {
|
||||||
if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) {
|
if ((y.getLhsType() instanceof PlaceholderType) && (y.getRhsType() instanceof PlaceholderType)) {
|
||||||
if (((PlaceholderType)y.getLhsType()).getVariance() != 0 && ((PlaceholderType)y.getRhsType()).getVariance() == 0) {
|
if (((PlaceholderType)y.getLhsType()).getVariance() != 0 && ((PlaceholderType)y.getRhsType()).getVariance() == 0) {
|
||||||
@ -175,15 +168,12 @@ public class JavaTXCompiler {
|
|||||||
return y; } )
|
return y; } )
|
||||||
.collect(Collectors.toCollection(HashSet::new));
|
.collect(Collectors.toCollection(HashSet::new));
|
||||||
varianceInheritance(xConsSet);
|
varianceInheritance(xConsSet);
|
||||||
Set<Set<UnifyPair>> result = unify.unifySequential(xConsSet, finiteClosure, logFile, log);
|
Set<Set<UnifyPair>> result = unify.unifySequential(xConsSet, finiteClosure);
|
||||||
//Set<Set<UnifyPair>> result = unify.unify(xConsSet, finiteClosure);
|
//Set<Set<UnifyPair>> result = unify.unify(xConsSet, finiteClosure);
|
||||||
System.out.println("RESULT: " + result);
|
System.out.println("RESULT: " + result);
|
||||||
logFile.write("RES: " + result.toString()+"\n");
|
|
||||||
logFile.flush();
|
|
||||||
results.addAll(result);
|
results.addAll(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (IOException e) { }
|
|
||||||
|
|
||||||
return results.stream().map((unifyPairs ->
|
return results.stream().map((unifyPairs ->
|
||||||
new ResultSet(UnifyTypeFactory.convert(unifyPairs, generateTPHMap(cons))))).collect(Collectors.toList());
|
new ResultSet(UnifyTypeFactory.convert(unifyPairs, generateTPHMap(cons))))).collect(Collectors.toList());
|
||||||
|
@ -36,16 +36,10 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class RuleSet implements IRuleSet{
|
public class RuleSet implements IRuleSet{
|
||||||
|
|
||||||
FileWriter logFile;
|
|
||||||
|
|
||||||
RuleSet() {
|
RuleSet() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
RuleSet(FileWriter logFile) {
|
|
||||||
this.logFile = logFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<UnifyPair> reduceUp(UnifyPair pair) {
|
public Optional<UnifyPair> reduceUp(UnifyPair pair) {
|
||||||
// Check if reduce up is applicable
|
// Check if reduce up is applicable
|
||||||
|
@ -8,16 +8,16 @@ import de.dhbwstuttgart.typeinference.unify.interfaces.IFiniteClosure;
|
|||||||
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
import de.dhbwstuttgart.typeinference.unify.model.UnifyPair;
|
||||||
|
|
||||||
public class TypeUnify {
|
public class TypeUnify {
|
||||||
public Set<Set<UnifyPair>> unify(Set<UnifyPair> eq, IFiniteClosure fc, FileWriter logFile, Boolean log) {
|
public Set<Set<UnifyPair>> unify(Set<UnifyPair> eq, IFiniteClosure fc) {
|
||||||
TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, true, logFile, log);
|
TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, true);
|
||||||
ForkJoinPool pool = new ForkJoinPool();
|
ForkJoinPool pool = new ForkJoinPool();
|
||||||
pool.invoke(unifyTask);
|
pool.invoke(unifyTask);
|
||||||
Set<Set<UnifyPair>> res = unifyTask.join();
|
Set<Set<UnifyPair>> res = unifyTask.join();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Set<UnifyPair>> unifySequential(Set<UnifyPair> eq, IFiniteClosure fc, FileWriter logFile, Boolean log) {
|
public Set<Set<UnifyPair>> unifySequential(Set<UnifyPair> eq, IFiniteClosure fc) {
|
||||||
TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, false, logFile, log);
|
TypeUnifyTask unifyTask = new TypeUnifyTask(eq, fc, false);
|
||||||
Set<Set<UnifyPair>> res = unifyTask.compute();
|
Set<Set<UnifyPair>> res = unifyTask.compute();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -48,10 +48,7 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static int i = 0;
|
private static int i = 0;
|
||||||
private boolean printtag = false;
|
private boolean printtag = false;
|
||||||
Boolean log = true; //gibt an ob ein Log-File nach System.getProperty("user.dir")+"/test/logFiles/log" geschrieben werden soll?
|
|
||||||
|
|
||||||
public static final String rootDirectory = System.getProperty("user.dir")+"/test/logFiles/";
|
|
||||||
FileWriter logFile;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The implementation of setOps that will be used during the unification
|
* The implementation of setOps that will be used during the unification
|
||||||
@ -88,14 +85,12 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
rules = new RuleSet();
|
rules = new RuleSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeUnifyTask(Set<UnifyPair> eq, IFiniteClosure fc, boolean parallel, FileWriter logFile, Boolean log) {
|
public TypeUnifyTask(Set<UnifyPair> eq, IFiniteClosure fc, boolean parallel) {
|
||||||
this.eq = eq;
|
this.eq = eq;
|
||||||
this.fc = fc;
|
this.fc = fc;
|
||||||
this.oup = new OrderingUnifyPair(fc);
|
this.oup = new OrderingUnifyPair(fc);
|
||||||
this.parallel = parallel;
|
this.parallel = parallel;
|
||||||
this.logFile = logFile;
|
rules = new RuleSet();
|
||||||
this.log = log;
|
|
||||||
rules = new RuleSet(logFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -155,7 +150,6 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
* Step 1: Repeated application of reduce, adapt, erase, swap
|
* Step 1: Repeated application of reduce, adapt, erase, swap
|
||||||
*/
|
*/
|
||||||
nOfUnify++;
|
nOfUnify++;
|
||||||
writeLog(nOfUnify.toString() + " Unifikation: " + eq.toString());
|
|
||||||
//eq = eq.stream().map(x -> {x.setVariance((byte)-1); return x;}).collect(Collectors.toCollection(HashSet::new));
|
//eq = eq.stream().map(x -> {x.setVariance((byte)-1); return x;}).collect(Collectors.toCollection(HashSet::new));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -231,10 +225,6 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
// those pairs are contradictory and the unification is impossible.
|
// those pairs are contradictory and the unification is impossible.
|
||||||
if(!undefinedPairs.isEmpty()) {
|
if(!undefinedPairs.isEmpty()) {
|
||||||
noUndefPair++;
|
noUndefPair++;
|
||||||
for (UnifyPair up : undefinedPairs) {
|
|
||||||
writeLog(noUndefPair.toString() + " UndefinedPairs; " + up);
|
|
||||||
writeLog("BasePair; " + up.getBasePair());
|
|
||||||
}
|
|
||||||
Set<Set<UnifyPair>> error = new HashSet<>();
|
Set<Set<UnifyPair>> error = new HashSet<>();
|
||||||
undefinedPairs = undefinedPairs.stream().map(x -> { x.setUndefinedPair(); return x;}).collect(Collectors.toCollection(HashSet::new));
|
undefinedPairs = undefinedPairs.stream().map(x -> { x.setUndefinedPair(); return x;}).collect(Collectors.toCollection(HashSet::new));
|
||||||
error.add(undefinedPairs);
|
error.add(undefinedPairs);
|
||||||
@ -323,13 +313,13 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
eqPrimePrimeSet.add(eqPrime);
|
eqPrimePrimeSet.add(eqPrime);
|
||||||
else if(eqPrimePrime.isPresent()) {
|
else if(eqPrimePrime.isPresent()) {
|
||||||
//System.out.println("nextStep: " + eqPrimePrime.get());
|
//System.out.println("nextStep: " + eqPrimePrime.get());
|
||||||
TypeUnifyTask fork = new TypeUnifyTask(eqPrimePrime.get(), fc, true, logFile, log);
|
TypeUnifyTask fork = new TypeUnifyTask(eqPrimePrime.get(), fc, true);
|
||||||
forks.add(fork);
|
forks.add(fork);
|
||||||
fork.fork();
|
fork.fork();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//System.out.println("nextStep: " + eqPrime);
|
//System.out.println("nextStep: " + eqPrime);
|
||||||
TypeUnifyTask fork = new TypeUnifyTask(eqPrime, fc, true, logFile, log);
|
TypeUnifyTask fork = new TypeUnifyTask(eqPrime, fc, true);
|
||||||
forks.add(fork);
|
forks.add(fork);
|
||||||
fork.fork();
|
fork.fork();
|
||||||
}
|
}
|
||||||
@ -340,13 +330,6 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
//PL 2017-09-29 dies ersetzt //(!eqPrimePrime.isPresent())
|
//PL 2017-09-29 dies ersetzt //(!eqPrimePrime.isPresent())
|
||||||
//PL 2018-05-18 beide Bedingungen muessen gelten, da eqPrime Veränderungen in allem ausser subst
|
//PL 2018-05-18 beide Bedingungen muessen gelten, da eqPrime Veränderungen in allem ausser subst
|
||||||
//eqPrimePrime Veraenderungen in subst repraesentieren.
|
//eqPrimePrime Veraenderungen in subst repraesentieren.
|
||||||
try {
|
|
||||||
if (isSolvedForm(eqPrime)) {
|
|
||||||
logFile.write(eqPrime.toString()+"\n");
|
|
||||||
logFile.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) { }
|
|
||||||
eqPrimePrimeSet.add(eqPrime);
|
eqPrimePrimeSet.add(eqPrime);
|
||||||
}
|
}
|
||||||
else if(eqPrimePrime.isPresent()) {
|
else if(eqPrimePrime.isPresent()) {
|
||||||
@ -377,8 +360,7 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
* Step 7: Filter empty sets;
|
* Step 7: Filter empty sets;
|
||||||
*/
|
*/
|
||||||
eqPrimePrimeSet = eqPrimePrimeSet.stream().filter(x -> isSolvedForm(x) || this.isUndefinedPairSet(x)).collect(Collectors.toCollection(HashSet::new));
|
eqPrimePrimeSet = eqPrimePrimeSet.stream().filter(x -> isSolvedForm(x) || this.isUndefinedPairSet(x)).collect(Collectors.toCollection(HashSet::new));
|
||||||
if (!eqPrimePrimeSet.isEmpty() && !isUndefinedPairSetSet(eqPrimePrimeSet))
|
|
||||||
writeLog("Result1 " + eqPrimePrimeSet.toString());
|
|
||||||
return eqPrimePrimeSet;
|
return eqPrimePrimeSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,7 +380,7 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
Set<Set<UnifyPair>> nextSet = remainingSets.remove(0);
|
Set<Set<UnifyPair>> nextSet = remainingSets.remove(0);
|
||||||
writeLog("nextSet: " + nextSet.toString());
|
|
||||||
List<Set<UnifyPair>> nextSetasList =new ArrayList<>(nextSet);
|
List<Set<UnifyPair>> nextSetasList =new ArrayList<>(nextSet);
|
||||||
try {
|
try {
|
||||||
//List<Set<UnifyPair>>
|
//List<Set<UnifyPair>>
|
||||||
@ -448,7 +430,7 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
System.out.print("");
|
System.out.print("");
|
||||||
if (nextSetasList.iterator().next().stream().filter(x -> x.getLhsType().getName().equals("D")).findFirst().isPresent() && nextSetasList.size()>1)
|
if (nextSetasList.iterator().next().stream().filter(x -> x.getLhsType().getName().equals("D")).findFirst().isPresent() && nextSetasList.size()>1)
|
||||||
System.out.print("");
|
System.out.print("");
|
||||||
writeLog("nextSetasList: " + nextSetasList.toString());
|
|
||||||
while (nextSetasList.size() > 0) { //(nextSetasList.size() != 0) {
|
while (nextSetasList.size() > 0) { //(nextSetasList.size() != 0) {
|
||||||
Set<UnifyPair> a = null;
|
Set<UnifyPair> a = null;
|
||||||
if (variance == 1) {
|
if (variance == 1) {
|
||||||
@ -569,16 +551,11 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
//}
|
//}
|
||||||
return (!x.containsAll(durchschnitt));
|
return (!x.containsAll(durchschnitt));
|
||||||
}).collect(Collectors.toCollection(ArrayList::new));
|
}).collect(Collectors.toCollection(ArrayList::new));
|
||||||
writeLog("abhSubst: " + abhSubst.toString());
|
|
||||||
writeLog("a: " + a.toString());
|
|
||||||
writeLog("Durchschnitt: " + durchschnitt.toString());
|
|
||||||
writeLog("nextSet: " + nextSet.toString());
|
|
||||||
writeLog("nextSetasList: " + nextSetasList.toString());
|
|
||||||
writeLog("Number erased Elements (undef): " + (len - nextSetasList.size()));
|
|
||||||
noAllErasedElements = noAllErasedElements + (len - nextSetasList.size());
|
noAllErasedElements = noAllErasedElements + (len - nextSetasList.size());
|
||||||
writeLog("Number erased Elements (undef): " + noAllErasedElements.toString());
|
|
||||||
noBacktracking++;
|
noBacktracking++;
|
||||||
writeLog("Number of Backtracking: " + noBacktracking);
|
|
||||||
System.out.println("");
|
System.out.println("");
|
||||||
}
|
}
|
||||||
//if (nextSetasList.size() == 0 && isUndefinedPairSetSet(result) && nextSet.size() > 1) {
|
//if (nextSetasList.size() == 0 && isUndefinedPairSetSet(result) && nextSet.size() > 1) {
|
||||||
@ -1238,15 +1215,4 @@ public class TypeUnifyTask extends RecursiveTask<Set<Set<UnifyPair>>> {
|
|||||||
permuteParams(candidates, idx+1, result, current);
|
permuteParams(candidates, idx+1, result, current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeLog(String str) {
|
|
||||||
if (log) {
|
|
||||||
try {
|
|
||||||
logFile.write(str+"\n");
|
|
||||||
logFile.flush();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (IOException e) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user