mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
some code formatting
This commit is contained in:
@@ -70,9 +70,9 @@ public class Capture extends PImage implements PConstants {
|
||||
indexPropertyName = "device-index";
|
||||
} else if (PApplet.platform == LINUX) {
|
||||
sourceElementName = "v4l2src";
|
||||
// The "device" property in v4l2src expects the device location (/dev/video0, etc).
|
||||
// v4l2src has "device-name", which requires the human-readable name... but how
|
||||
// to query in linux?.
|
||||
// The "device" property in v4l2src expects the device location
|
||||
// (/dev/video0, etc). v4l2src has "device-name", which requires the
|
||||
// human-readable name... but how to query in linux?.
|
||||
devicePropertyName = "device";
|
||||
indexPropertyName = "device-fd";
|
||||
} else {}
|
||||
@@ -126,14 +126,16 @@ public class Capture extends PImage implements PConstants {
|
||||
String idName;
|
||||
Object idValue;
|
||||
if (devicePropertyName.equals("")) {
|
||||
// For plugins without device name property, the name is casted as an index
|
||||
// For plugins without device name property, the name is casted
|
||||
// as an index
|
||||
idName = indexPropertyName;
|
||||
idValue = new Integer(PApplet.parseInt(name));
|
||||
} else {
|
||||
idName = devicePropertyName;
|
||||
idValue = name;
|
||||
}
|
||||
initGStreamer(parent, size[0], size[1], sourceElementName, idName, idValue, fps);
|
||||
initGStreamer(parent, size[0], size[1], sourceElementName,
|
||||
idName, idValue, fps);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,14 +146,16 @@ public class Capture extends PImage implements PConstants {
|
||||
String idName;
|
||||
Object idValue;
|
||||
if (devicePropertyName.equals("")) {
|
||||
// For plugins without device name property, the name is casted as an index
|
||||
// For plugins without device name property, the name is casted
|
||||
// as an index
|
||||
idName = indexPropertyName;
|
||||
idValue = new Integer(PApplet.parseInt(name));
|
||||
} else {
|
||||
idName = devicePropertyName;
|
||||
idValue = name;
|
||||
}
|
||||
initGStreamer(parent, size[0], size[1], sourceElementName, idName, idValue, fps);
|
||||
initGStreamer(parent, size[0], size[1], sourceElementName,
|
||||
idName, idValue, fps);
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +166,8 @@ public class Capture extends PImage implements PConstants {
|
||||
*/
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight) {
|
||||
super(requestWidth, requestHeight, RGB);
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName, null, null, "");
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName,
|
||||
null, null, "");
|
||||
}
|
||||
|
||||
|
||||
@@ -172,9 +177,11 @@ public class Capture extends PImage implements PConstants {
|
||||
*
|
||||
* @param frameRate number of frames to read per second
|
||||
*/
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight, int frameRate) {
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight,
|
||||
int frameRate) {
|
||||
super(requestWidth, requestHeight, RGB);
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName, null, null, frameRate + "/1");
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName,
|
||||
null, null, frameRate + "/1");
|
||||
}
|
||||
|
||||
|
||||
@@ -184,39 +191,46 @@ public class Capture extends PImage implements PConstants {
|
||||
*
|
||||
* @param cameraName name of the camera
|
||||
*/
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight, String cameraName) {
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight,
|
||||
String cameraName) {
|
||||
super(requestWidth, requestHeight, RGB);
|
||||
String idName;
|
||||
Object idValue;
|
||||
if (devicePropertyName.equals("")) {
|
||||
// For plugins without device name property, the name is casted as an index
|
||||
// For plugins without device name property, the name is casted
|
||||
// as an index
|
||||
idName = indexPropertyName;
|
||||
idValue = new Integer(PApplet.parseInt(cameraName));
|
||||
} else {
|
||||
idName = devicePropertyName;
|
||||
idValue = cameraName;
|
||||
}
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName, idName, idValue, "");
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName,
|
||||
idName, idValue, "");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <h3>Advanced</h3>
|
||||
* This constructor allows to specify the camera name and the desired framerate, in addition to the resolution.
|
||||
* This constructor allows to specify the camera name and the desired
|
||||
* framerate, in addition to the resolution.
|
||||
*/
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight, String cameraName, int frameRate) {
|
||||
public Capture(PApplet parent, int requestWidth, int requestHeight,
|
||||
String cameraName, int frameRate) {
|
||||
super(requestWidth, requestHeight, RGB);
|
||||
String idName;
|
||||
Object idValue;
|
||||
if (devicePropertyName.equals("")) {
|
||||
// For plugins without device name property, the name is casted as an index
|
||||
// For plugins without device name property, the name is casted
|
||||
// as an index
|
||||
idName = indexPropertyName;
|
||||
idValue = new Integer(PApplet.parseInt(cameraName));
|
||||
} else {
|
||||
idName = devicePropertyName;
|
||||
idValue = cameraName;
|
||||
}
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName, idName, idValue, frameRate + "/1");
|
||||
initGStreamer(parent, requestWidth, requestHeight, sourceElementName,
|
||||
idName, idValue, frameRate + "/1");
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +381,8 @@ public class Capture extends PImage implements PConstants {
|
||||
ByteBuffer byteBuffer = natBuffer.getByteBuffer();
|
||||
|
||||
try {
|
||||
sinkCopyMethod.invoke(bufferSink, new Object[] { natBuffer, byteBuffer, bufWidth, bufHeight });
|
||||
sinkCopyMethod.invoke(bufferSink,
|
||||
new Object[] { natBuffer, byteBuffer, bufWidth, bufHeight });
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -425,7 +440,8 @@ public class Capture extends PImage implements PConstants {
|
||||
|
||||
ArrayList<String> configList = new ArrayList<String>();
|
||||
for (String device: devices) {
|
||||
ArrayList<String> resolutions = listResolutions(sourceName, propertyName, device);
|
||||
ArrayList<String> resolutions = listResolutions(sourceName, propertyName,
|
||||
device);
|
||||
if (0 < resolutions.size()) {
|
||||
for (String res: resolutions) {
|
||||
configList.add("name=" + device + "," + res);
|
||||
@@ -444,7 +460,8 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected ArrayList<String> listDevices(String sourceName, String propertyName) {
|
||||
static protected ArrayList<String> listDevices(String sourceName,
|
||||
String propertyName) {
|
||||
ArrayList<String> devices = new ArrayList<String>();
|
||||
try {
|
||||
// Using property-probe interface
|
||||
@@ -481,7 +498,8 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PGraphics.showWarning("The capture plugin doesn't support device query!");
|
||||
PGraphics.showWarning("The capture plugin does not support " +
|
||||
"device query!");
|
||||
devices = new ArrayList<String>();
|
||||
}
|
||||
}
|
||||
@@ -489,7 +507,9 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected ArrayList<String> listResolutions(String sourceName, String propertyName, Object propertyValue) {
|
||||
static protected ArrayList<String> listResolutions(String sourceName,
|
||||
String propertyName,
|
||||
Object propertyValue) {
|
||||
// Creating temporary pipeline so that we can query
|
||||
// the resolutions supported by the device.
|
||||
Pipeline testPipeline = new Pipeline("test");
|
||||
@@ -536,7 +556,8 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected void addResFromSourceImpl(ArrayList<String> res, Element src) {
|
||||
static protected void addResFromSourceImpl(ArrayList<String> res,
|
||||
Element src) {
|
||||
for (Pad pad : src.getPads()) {
|
||||
Caps caps = pad.getCaps();
|
||||
int n = caps.size();
|
||||
@@ -568,7 +589,8 @@ public class Capture extends PImage implements PConstants {
|
||||
// QTKit allows to capture streams at arbitrary resolutions, then the list is
|
||||
// faked by repeatedly dividing the maximum by 2 until the width becomes too
|
||||
// small (or not divisible by 2).
|
||||
static protected void addResFromSourceMacHack(ArrayList<String> res, Element src) {
|
||||
static protected void addResFromSourceMacHack(ArrayList<String> res,
|
||||
Element src) {
|
||||
for (Pad pad : src.getPads()) {
|
||||
Caps caps = pad.getNegotiatedCaps();
|
||||
int n = caps.size();
|
||||
@@ -609,7 +631,8 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected void addResFromString(ArrayList<String> res, String str, int w, int h) {
|
||||
static protected void addResFromString(ArrayList<String> res, String str,
|
||||
int w, int h) {
|
||||
int n0 = str.indexOf("framerate=(fraction)");
|
||||
if (-1 < n0) {
|
||||
String temp = str.substring(n0 + 20, str.length());
|
||||
@@ -646,7 +669,8 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected void addResFromStructure(ArrayList<String> res, Structure str, int w, int h) {
|
||||
static protected void addResFromStructure(ArrayList<String> res,
|
||||
Structure str, int w, int h) {
|
||||
boolean singleFrac = false;
|
||||
try {
|
||||
Fraction fr = str.getFraction("framerate");
|
||||
@@ -676,7 +700,9 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected String makeResolutionString(int width, int height, int fpsNumerator, int fpsDenominator) {
|
||||
static protected String makeResolutionString(int width, int height, int
|
||||
fpsNumerator,
|
||||
int fpsDenominator) {
|
||||
String res = "size=" + width + "x" + height + ",fps=" + fpsNumerator;
|
||||
if (fpsDenominator != 1) {
|
||||
res += "/" + fpsDenominator;
|
||||
@@ -685,7 +711,8 @@ public class Capture extends PImage implements PConstants {
|
||||
}
|
||||
|
||||
|
||||
static protected String makeResolutionString(int width, int height, String fpsStr) {
|
||||
static protected String makeResolutionString(int width, int height,
|
||||
String fpsStr) {
|
||||
String res = "size=" + width + "x" + height;
|
||||
String[] parts = fpsStr.split("/");
|
||||
if (parts.length == 2) {
|
||||
@@ -717,8 +744,10 @@ public class Capture extends PImage implements PConstants {
|
||||
if (!frameRateString.equals("")) {
|
||||
fpsStr = ", " + frameRateString + "fps";
|
||||
}
|
||||
throw new RuntimeException("The requested resolution of " + reqWidth + "x" + reqHeight + fpsStr +
|
||||
" is not supported by the selected capture device.\n");
|
||||
throw new RuntimeException("The requested resolution of " + reqWidth +
|
||||
"x" + reqHeight + fpsStr +
|
||||
" is not supported by the selected capture " +
|
||||
"device.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,7 +760,8 @@ public class Capture extends PImage implements PConstants {
|
||||
devices = listDevices(src, devicePropertyName);
|
||||
}
|
||||
if (devices.size() == 0) {
|
||||
throw new RuntimeException("There are no capture devices connected to this computer.\n");
|
||||
throw new RuntimeException("There are no capture devices connected to " +
|
||||
"this computer.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,7 +878,8 @@ public class Capture extends PImage implements PConstants {
|
||||
Element conv = ElementFactory.make("ffmpegcolorspace", "ColorConverter");
|
||||
|
||||
Element videofilter = ElementFactory.make("capsfilter", "ColorFilter");
|
||||
videofilter.setCaps(new Caps("video/x-raw-rgb, width=" + reqWidth + ", height=" + reqHeight +
|
||||
videofilter.setCaps(new Caps("video/x-raw-rgb, width=" + reqWidth +
|
||||
", height=" + reqHeight +
|
||||
", bpp=32, depth=24" + fpsStr));
|
||||
|
||||
rgbSink = new RGBDataAppSink("rgb",
|
||||
@@ -861,8 +892,8 @@ public class Capture extends PImage implements PConstants {
|
||||
// Setting direct buffer passing in the video sink.
|
||||
rgbSink.setPassDirectBuffer(Video.passDirectBuffer);
|
||||
|
||||
// No need for rgbSink.dispose(), because the addMany() doesn't increment the
|
||||
// refcount of the videoSink object.
|
||||
// No need for rgbSink.dispose(), because the addMany() doesn't increment
|
||||
// the refcount of the videoSink object.
|
||||
|
||||
pipeline.addMany(sourceElement, conv, videofilter, rgbSink);
|
||||
Element.linkMany(sourceElement, conv, videofilter, rgbSink);
|
||||
@@ -923,7 +954,8 @@ public class Capture extends PImage implements PConstants {
|
||||
try {
|
||||
captureEventMethod.invoke(eventHandler, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling captureEvent() for capture object");
|
||||
System.err.println(
|
||||
"error, disabling captureEvent() for capture object");
|
||||
e.printStackTrace();
|
||||
captureEventMethod = null;
|
||||
}
|
||||
@@ -942,7 +974,8 @@ public class Capture extends PImage implements PConstants {
|
||||
try {
|
||||
captureEventMethod.invoke(eventHandler, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
System.err.println("error, disabling captureEvent() for capture object");
|
||||
System.err.println(
|
||||
"error, disabling captureEvent() for capture object");
|
||||
e.printStackTrace();
|
||||
captureEventMethod = null;
|
||||
}
|
||||
@@ -1063,16 +1096,19 @@ public class Capture extends PImage implements PConstants {
|
||||
protected void getSinkMethods() {
|
||||
try {
|
||||
sinkCopyMethod = bufferSink.getClass().getMethod("copyBufferFromSource",
|
||||
new Class[] { Object.class, ByteBuffer.class, int.class, int.class });
|
||||
new Class[] { Object.class, ByteBuffer.class, int.class, int.class });
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Movie: provided sink object doesn't have a copyBufferFromSource method.");
|
||||
throw new RuntimeException("Capture: provided sink object doesn't have " +
|
||||
"a copyBufferFromSource method.");
|
||||
}
|
||||
|
||||
try {
|
||||
sinkSetMethod = bufferSink.getClass().getMethod("setBufferSource", new Class[] { Object.class });
|
||||
sinkSetMethod = bufferSink.getClass().getMethod("setBufferSource",
|
||||
new Class[] { Object.class });
|
||||
sinkSetMethod.invoke(bufferSink, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Movie: provided sink object doesn't have a setBufferSource method.");
|
||||
throw new RuntimeException("Capture: provided sink object doesn't have "+
|
||||
"a setBufferSource method.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,23 +106,30 @@ public class LibraryLoader {
|
||||
{ "gstaudio-0.10", new String[] { "gstbase-0.10" }, true },
|
||||
{ "gstvideo-0.10", new String[] { "gstbase-0.10" }, true }, };
|
||||
|
||||
static final Object[][] dependencies = Platform.isWindows() ? WINDOWS_DEPENDENCIES
|
||||
: Platform.isMac() ? MACOSX_DEPENDENCIES
|
||||
: DEFAULT_DEPENDENCIES;
|
||||
|
||||
static final Object[][] dependencies =
|
||||
Platform.isWindows() ? WINDOWS_DEPENDENCIES :
|
||||
Platform.isMac() ? MACOSX_DEPENDENCIES : DEFAULT_DEPENDENCIES;
|
||||
|
||||
private static final Map<String, Object> loadedMap = new HashMap<String, Object>();
|
||||
|
||||
private static final Map<String, Object> loadedMap =
|
||||
new HashMap<String, Object>();
|
||||
|
||||
|
||||
private static final int RECURSIVE_LOAD_MAX_DEPTH = 5;
|
||||
|
||||
|
||||
private LibraryLoader() {
|
||||
}
|
||||
|
||||
|
||||
private void preLoadLibs() {
|
||||
for (Object[] a : dependencies) {
|
||||
load(a[0].toString(), DummyLibrary.class, true, 0, (Boolean) a[2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String[] findDeps(String name) {
|
||||
|
||||
for (Object[] a : dependencies) {
|
||||
@@ -136,10 +143,12 @@ public class LibraryLoader {
|
||||
// probably client call
|
||||
}
|
||||
|
||||
|
||||
public Object load(String name, Class<?> clazz, boolean reqLib) {
|
||||
return load(name, clazz, true, 0, reqLib);
|
||||
}
|
||||
|
||||
|
||||
private Object load(String name, Class<?> clazz, boolean forceReload,
|
||||
int depth, boolean reqLib) {
|
||||
|
||||
@@ -167,8 +176,8 @@ public class LibraryLoader {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (reqLib)
|
||||
throw new RuntimeException(String.format("can not load required library %s",
|
||||
name, e));
|
||||
throw new RuntimeException(String.format(
|
||||
"can not load required library %s", name, e));
|
||||
else
|
||||
System.out.println(String.format("can not load library %s", name, e));
|
||||
}
|
||||
@@ -177,7 +186,9 @@ public class LibraryLoader {
|
||||
return library;
|
||||
}
|
||||
|
||||
private static Object loadLibrary(String name, Class<?> clazz, boolean reqLib) {
|
||||
|
||||
private static Object loadLibrary(String name, Class<?> clazz,
|
||||
boolean reqLib) {
|
||||
|
||||
// Logger.getAnonymousLogger().info(String.format("loading %s", name));
|
||||
|
||||
@@ -201,28 +212,25 @@ public class LibraryLoader {
|
||||
|
||||
if (reqLib)
|
||||
throw new UnsatisfiedLinkError(
|
||||
String
|
||||
.format(
|
||||
"can't load library %s (%1$s|lib%1$s|lib%1$s-0) with -Djna.library.path=%s. Last error:%s",
|
||||
name, System.getProperty("jna.library.path"), linkError));
|
||||
String.format(
|
||||
"can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " +
|
||||
"-Djna.library.path=%s. Last error:%s",
|
||||
name, System.getProperty("jna.library.path"), linkError));
|
||||
else {
|
||||
System.out
|
||||
.println(String
|
||||
.format(
|
||||
"can't load library %s (%1$s|lib%1$s|lib%1$s-0) with -Djna.library.path=%s. Last error:%s",
|
||||
name, System.getProperty("jna.library.path"), linkError));
|
||||
System.out.println(String.format(
|
||||
"can't load library %s (%1$s|lib%1$s|lib%1$s-0) with " +
|
||||
"-Djna.library.path=%s. Last error:%s",
|
||||
name, System.getProperty("jna.library.path"), linkError));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static synchronized LibraryLoader getInstance() {
|
||||
|
||||
if (null == instance) {
|
||||
instance = new LibraryLoader();
|
||||
instance.preLoadLibs();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -653,9 +653,9 @@ public class Movie extends PImage implements PConstants {
|
||||
|
||||
natSink.setAutoDisposeBuffer(false);
|
||||
playbin.setVideoSink(natSink);
|
||||
// The setVideoSink() method sets the videoSink as a property of the PlayBin,
|
||||
// which increments the refcount of the videoSink element. Disposing here once
|
||||
// to decrement the refcount.
|
||||
// The setVideoSink() method sets the videoSink as a property of the
|
||||
// PlayBin, which increments the refcount of the videoSink element.
|
||||
// Disposing here once to decrement the refcount.
|
||||
natSink.dispose();
|
||||
} else {
|
||||
rgbSink = new RGBDataAppSink("rgb",
|
||||
@@ -668,9 +668,9 @@ public class Movie extends PImage implements PConstants {
|
||||
// Setting direct buffer passing in the video sink.
|
||||
rgbSink.setPassDirectBuffer(Video.passDirectBuffer);
|
||||
playbin.setVideoSink(rgbSink);
|
||||
// The setVideoSink() method sets the videoSink as a property of the PlayBin,
|
||||
// which increments the refcount of the videoSink element. Disposing here once
|
||||
// to decrement the refcount.
|
||||
// The setVideoSink() method sets the videoSink as a property of the
|
||||
// PlayBin, which increments the refcount of the videoSink element.
|
||||
// Disposing here once to decrement the refcount.
|
||||
rgbSink.dispose();
|
||||
}
|
||||
|
||||
@@ -787,8 +787,8 @@ public class Movie extends PImage implements PConstants {
|
||||
|
||||
|
||||
/**
|
||||
* Get the original framerate of the source video. Note: calling this method repeatedly
|
||||
* can slow down playback performance.
|
||||
* Get the original framerate of the source video. Note: calling this method
|
||||
* repeatedly can slow down playback performance.
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
@@ -856,16 +856,19 @@ public class Movie extends PImage implements PConstants {
|
||||
protected void getSinkMethods() {
|
||||
try {
|
||||
sinkCopyMethod = bufferSink.getClass().getMethod("copyBufferFromSource",
|
||||
new Class[] { Object.class, ByteBuffer.class, int.class, int.class });
|
||||
new Class[] { Object.class, ByteBuffer.class, int.class, int.class });
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Movie: provided sink object doesn't have a copyBufferFromSource method.");
|
||||
throw new RuntimeException("Movie: provided sink object doesn't have a " +
|
||||
"copyBufferFromSource method.");
|
||||
}
|
||||
|
||||
try {
|
||||
sinkSetMethod = bufferSink.getClass().getMethod("setBufferSource", new Class[] { Object.class });
|
||||
sinkSetMethod = bufferSink.getClass().getMethod("setBufferSource",
|
||||
new Class[] { Object.class });
|
||||
sinkSetMethod.invoke(bufferSink, new Object[] { this });
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Movie: provided sink object doesn't have a setBufferSource method.");
|
||||
throw new RuntimeException("Movie: provided sink object doesn't have a " +
|
||||
"setBufferSource method.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,8 @@ public class Video implements PConstants {
|
||||
boolean res;
|
||||
res = reg.scanPath(gstreamerPluginPath);
|
||||
if (!res) {
|
||||
System.err.println("Cannot load GStreamer plugins from " + gstreamerPluginPath);
|
||||
System.err.println("Cannot load GStreamer plugins from " +
|
||||
gstreamerPluginPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user