mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
485 Upgrade Project and Build to Java 11 (#496)
* Updates gradle to 5.1.1 * Updated to run application from intellij using installed Java 11. Resolves issues with Java 9 deprecations. * Updates gradle build dependencies and other deprecation issues. * Updates gradle to produce OS-specific builds. * Updates the beryx runtime plugin to 1.1.1 to resolve issue with zipping each of the target distributions. * Import cleanup * Resolves issue with Look and Feel error on Max OSX Resolves issue with building OSX package Resolves issue with excessive logging about JMBE library.
This commit is contained in:
@@ -29,15 +29,11 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.text.MaskFormatter;
|
||||
import java.awt.Color;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
@@ -229,29 +225,4 @@ public class TalkgroupEditor extends DocumentListenerEditor<AliasID>
|
||||
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Talkgroup talkgroup = new Talkgroup();
|
||||
talkgroup.setProtocol(Protocol.APCO25);
|
||||
talkgroup.setValue(12345678 );
|
||||
|
||||
JFrame frame = new JFrame("Talkgroup Editor");
|
||||
frame.setSize(new Dimension(500, 400));
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
JPanel panel = new JPanel();
|
||||
TalkgroupEditor talkgroupEditor = new TalkgroupEditor(null);
|
||||
panel.add(talkgroupEditor);
|
||||
frame.setContentPane(panel);
|
||||
|
||||
EventQueue.invokeLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
frame.setVisible(true);
|
||||
talkgroupEditor.setItem(talkgroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -35,7 +35,6 @@ import io.github.dsheirer.message.IMessageListener;
|
||||
import io.github.dsheirer.module.Module;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.event.ActivitySummaryProvider;
|
||||
import io.github.dsheirer.module.decode.event.CallEvent;
|
||||
import io.github.dsheirer.module.decode.event.IDecodeEvent;
|
||||
import io.github.dsheirer.module.decode.event.IDecodeEventProvider;
|
||||
import io.github.dsheirer.sample.Broadcaster;
|
||||
@@ -64,7 +63,6 @@ public abstract class DecoderState extends Module implements ActivitySummaryProv
|
||||
private ConfigurationIdentifierListener mConfigurationIdentifierListener = new ConfigurationIdentifierListener();
|
||||
|
||||
private IChannelDescriptor mCurrentChannel;
|
||||
protected CallEvent mCurrentCallEvent;
|
||||
|
||||
public DecoderState()
|
||||
{
|
||||
@@ -107,7 +105,7 @@ public abstract class DecoderState extends Module implements ActivitySummaryProv
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides subclass reference to the call event broadcaster
|
||||
* Provides subclass reference to the decode event broadcaster
|
||||
*/
|
||||
protected Broadcaster<IDecodeEvent> getDecodeEventBroadcaster()
|
||||
{
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
/*******************************************************************************
|
||||
* SDR Trunk
|
||||
* Copyright (C) 2014,2015 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.dsp.filter.halfband.real;
|
||||
|
||||
import io.github.dsheirer.sample.buffer.ReusableBufferQueue;
|
||||
import io.github.dsheirer.sample.buffer.ReusableFloatBuffer;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
@Deprecated
|
||||
public class HalfBandFilter
|
||||
{
|
||||
private float[] mBuffer;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
package io.github.dsheirer.gui;
|
||||
|
||||
import com.jidesoft.plaf.LookAndFeelFactory;
|
||||
import com.jidesoft.swing.JideSplitPane;
|
||||
import io.github.dsheirer.alias.AliasModel;
|
||||
import io.github.dsheirer.audio.AudioPacketManager;
|
||||
@@ -71,6 +72,8 @@ import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.metal.MetalLookAndFeel;
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Dimension;
|
||||
@@ -87,6 +90,7 @@ import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SDRTrunk implements Listener<TunerEvent>
|
||||
{
|
||||
@@ -118,6 +122,21 @@ public class SDRTrunk implements Listener<TunerEvent>
|
||||
mApplicationLog = new ApplicationLog(mUserPreferences);
|
||||
mApplicationLog.start();
|
||||
|
||||
String operatingSystem = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
|
||||
|
||||
if(operatingSystem.contains("mac") || operatingSystem.contains("nux"))
|
||||
{
|
||||
try
|
||||
{
|
||||
UIManager.setLookAndFeel(MetalLookAndFeel.class.getName());
|
||||
LookAndFeelFactory.installJideExtension();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error trying to set Metal look and feel for OS [" + operatingSystem + "]");
|
||||
}
|
||||
}
|
||||
|
||||
//Setup the application home directory
|
||||
Path home = getHomePath();
|
||||
|
||||
|
||||
@@ -451,7 +451,7 @@ public class MultipleFrequencyEditor extends JPanel
|
||||
}
|
||||
catch(Exception exc)
|
||||
{
|
||||
return new Double(0);
|
||||
return 0.0d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,359 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
package io.github.dsheirer.module.decode.event;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.channel.IChannelDescriptor;
|
||||
import io.github.dsheirer.identifier.Identifier;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
public abstract class CallEvent implements Comparable<CallEvent>
|
||||
{
|
||||
protected long mEventStart = System.currentTimeMillis();
|
||||
protected long mEventEnd;
|
||||
|
||||
private SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd");
|
||||
private SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("HHmmss");
|
||||
|
||||
protected DecoderType mDecoderType;
|
||||
protected CallEventType mCallEventType;
|
||||
protected AliasList mAliasList;
|
||||
protected String mFromID;
|
||||
protected String mToID;
|
||||
protected String mDetails;
|
||||
|
||||
//New call event format member variables
|
||||
protected IChannelDescriptor mChannelDescriptor;
|
||||
protected Collection<Identifier> mIdentifiers;
|
||||
|
||||
private boolean mValid = true;
|
||||
|
||||
/**
|
||||
* Constructs a call event
|
||||
* @param decoder type
|
||||
* @param callEventType description
|
||||
* @param channelDescriptor that identifies the channel and frequency value(s)
|
||||
* @param identifiers for to, from, comments, etc.
|
||||
*/
|
||||
public CallEvent(DecoderType decoder, CallEventType callEventType, IChannelDescriptor channelDescriptor, Collection<Identifier> identifiers)
|
||||
{
|
||||
mDecoderType = decoder;
|
||||
mCallEventType = callEventType;
|
||||
mChannelDescriptor = channelDescriptor;
|
||||
mIdentifiers = identifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy call event constructor
|
||||
*/
|
||||
@Deprecated //Remove once all decoder states have been updated to new constructor
|
||||
public CallEvent(DecoderType decoder, CallEventType callEventType, AliasList aliasList, String fromID,
|
||||
String toID, String details)
|
||||
{
|
||||
mDecoderType = decoder;
|
||||
mCallEventType = callEventType;
|
||||
mAliasList = aliasList;
|
||||
mFromID = fromID;
|
||||
mToID = toID;
|
||||
mDetails = details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifier collection for this call event
|
||||
*/
|
||||
public Collection<Identifier> getIdentifiers()
|
||||
{
|
||||
return mIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this event is valid. Use this method to mark a previously
|
||||
* dispatched event as invalid and resend it so that any downstream
|
||||
* processing can remove the invalid event.
|
||||
*/
|
||||
public void setValid(boolean valid)
|
||||
{
|
||||
mValid = valid;
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return mValid;
|
||||
}
|
||||
|
||||
public void setEnd(long end)
|
||||
{
|
||||
mEventEnd = end;
|
||||
}
|
||||
|
||||
public void end()
|
||||
{
|
||||
setEnd(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public DecoderType getDecoderType()
|
||||
{
|
||||
return mDecoderType;
|
||||
}
|
||||
|
||||
public CallEventType getCallEventType()
|
||||
{
|
||||
return mCallEventType;
|
||||
}
|
||||
|
||||
public void setCallEventType(CallEventType type)
|
||||
{
|
||||
mCallEventType = type;
|
||||
}
|
||||
|
||||
public AliasList getAliasList()
|
||||
{
|
||||
return mAliasList;
|
||||
}
|
||||
|
||||
public void setAliasList(AliasList aliasList)
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
}
|
||||
|
||||
public boolean hasAliasList()
|
||||
{
|
||||
return mAliasList != null;
|
||||
}
|
||||
|
||||
public long getEventStartTime()
|
||||
{
|
||||
return mEventStart;
|
||||
}
|
||||
|
||||
public long getEventEndTime()
|
||||
{
|
||||
return mEventEnd;
|
||||
}
|
||||
|
||||
public String getFromID()
|
||||
{
|
||||
return mFromID;
|
||||
}
|
||||
|
||||
public boolean hasFromID()
|
||||
{
|
||||
return mFromID != null;
|
||||
}
|
||||
|
||||
public void setFromID(String id)
|
||||
{
|
||||
mFromID = id;
|
||||
}
|
||||
|
||||
public String getToID()
|
||||
{
|
||||
return mToID;
|
||||
}
|
||||
|
||||
public boolean hasToID()
|
||||
{
|
||||
return mToID != null;
|
||||
}
|
||||
|
||||
public void setToID(String id)
|
||||
{
|
||||
mToID = id;
|
||||
}
|
||||
|
||||
public String getDetails()
|
||||
{
|
||||
return mDetails;
|
||||
}
|
||||
|
||||
public void setDetails(String details)
|
||||
{
|
||||
mDetails = details;
|
||||
}
|
||||
|
||||
public abstract Alias getFromIDAlias();
|
||||
|
||||
public abstract Alias getToIDAlias();
|
||||
|
||||
public abstract String getChannel();
|
||||
|
||||
public abstract long getFrequency();
|
||||
|
||||
public static String getCSVHeader()
|
||||
{
|
||||
return "START_DATE,START_TIME,END_DATE,END_TIME,DECODER,EVENT,FROM,FROM_ALIAS,TO,TO_ALIAS,CHANNEL_NUMBER," +
|
||||
"FREQUENCY,DETAILS";
|
||||
}
|
||||
|
||||
public String toCSV()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("'");
|
||||
|
||||
Date eventStart = new Date(getEventStartTime());
|
||||
sb.append(DATE_FORMATTER.format(eventStart));
|
||||
sb.append("','");
|
||||
sb.append(TIME_FORMATTER.format(eventStart));
|
||||
sb.append("','");
|
||||
if(mEventEnd != 0)
|
||||
{
|
||||
Date eventEnd = new Date(getEventEndTime());
|
||||
sb.append(DATE_FORMATTER.format(eventEnd));
|
||||
sb.append("','");
|
||||
sb.append(TIME_FORMATTER.format(eventEnd));
|
||||
sb.append("','");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("','',");
|
||||
}
|
||||
sb.append("','");
|
||||
sb.append(getDecoderType().toString());
|
||||
sb.append("','");
|
||||
sb.append(getCallEventType().toString());
|
||||
sb.append("',");
|
||||
if(getFromID() != null)
|
||||
{
|
||||
sb.append("'");
|
||||
sb.append(getFromID());
|
||||
sb.append("'");
|
||||
}
|
||||
sb.append(",");
|
||||
|
||||
Alias fromAlias = getFromIDAlias();
|
||||
|
||||
if(fromAlias != null)
|
||||
{
|
||||
sb.append("'");
|
||||
sb.append(fromAlias.getName());
|
||||
sb.append("'");
|
||||
}
|
||||
sb.append(",");
|
||||
|
||||
if(getToID() != null)
|
||||
{
|
||||
sb.append("'");
|
||||
sb.append(getToID());
|
||||
sb.append("'");
|
||||
}
|
||||
sb.append(",");
|
||||
|
||||
Alias toAlias = getToIDAlias();
|
||||
|
||||
if(toAlias != null)
|
||||
{
|
||||
sb.append("'");
|
||||
sb.append(toAlias.getName());
|
||||
sb.append("'");
|
||||
}
|
||||
sb.append(",'");
|
||||
sb.append(getChannel());
|
||||
sb.append("','");
|
||||
sb.append(getFrequency());
|
||||
sb.append("',");
|
||||
if(getDetails() != null)
|
||||
{
|
||||
sb.append("'");
|
||||
sb.append(getDetails());
|
||||
sb.append("'");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public enum CallEventType
|
||||
{
|
||||
ANNOUNCEMENT("Announcement"),
|
||||
AUTOMATIC_REGISTRATION_SERVICE("Motorola ARS"),
|
||||
CALL("Call"),
|
||||
CALL_ALERT("Call Alert"),
|
||||
CALL_DETECT("Call Detect"),
|
||||
CALL_DO_NOT_MONITOR("Call-Do Not Monitor"),
|
||||
CALL_END("Call End"),
|
||||
CALL_UNIQUE_ID("UID Call"),
|
||||
CALL_NO_TUNER("Call - No Tuner"),
|
||||
CALL_TIMEOUT("Call Timeout"),
|
||||
COMMAND("Command"),
|
||||
DATA_CALL("Data Call"),
|
||||
DATA_PACKET("Data Packet"),
|
||||
DEREGISTER("Deregister"),
|
||||
EMERGENCY("EMERGENCY"),
|
||||
ENCRYPTED_CALL("Encrypted Call"),
|
||||
FUNCTION("Function"),
|
||||
GPS("GPS"),
|
||||
GROUP_CALL("Group Call"),
|
||||
ID_ANI("ANI"),
|
||||
ID_UNIQUE("Unique ID"),
|
||||
IP_PACKET("IP Packet"),
|
||||
NOTIFICATION("Notification"),
|
||||
PAGE("Page"),
|
||||
PATCH_GROUP_ADD("Patch Group Add"),
|
||||
PATCH_GROUP_CALL("Patch Group Call"),
|
||||
PATCH_GROUP_DELETE("Patch Group Delete"),
|
||||
QUERY("Query"),
|
||||
REGISTER("Register"),
|
||||
REGISTER_ESN("ESN"),
|
||||
RESPONSE("Response"),
|
||||
RESPONSE_PACKET("Response Packet"),
|
||||
SDM("Short Data Message"),
|
||||
SNDCP_PACKET("SNDCP Packet"),
|
||||
STATION_ID("Station ID"),
|
||||
STATUS("Status"),
|
||||
TCP_PACKET("TCP/IP Packet"),
|
||||
TELEPHONE_INTERCONNECT("Telephone Interconnect"),
|
||||
UDP_PACKET("UDP/IP Packet"),
|
||||
UNIT_TO_UNIT_CALL("Unit To Unit Call"),
|
||||
UNKNOWN("Unknown"),
|
||||
INVALID("Invalid");
|
||||
|
||||
private String mLabel;
|
||||
|
||||
private CallEventType(String label)
|
||||
{
|
||||
mLabel = label;
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return mLabel;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(CallEvent other)
|
||||
{
|
||||
if(other != null && other == this)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Long.compare(mEventStart, other.getEventStartTime());
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.lj1200;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.event.CallEvent;
|
||||
|
||||
public class LJ1200CallEvent extends CallEvent
|
||||
{
|
||||
public LJ1200CallEvent(CallEventType callEventType, AliasList aliasList, String fromID, String toID, String details)
|
||||
{
|
||||
super(DecoderType.LJ_1200, callEventType, aliasList, fromID, toID, details);
|
||||
}
|
||||
|
||||
private Alias getAlias(String ident)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
return getAlias(getFromID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return getAlias(getToID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrequency()
|
||||
{
|
||||
return 173075000;
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
/* Required parameters */
|
||||
private CallEventType mCallEventType;
|
||||
|
||||
/* Optional parameters */
|
||||
private AliasList mAliasList;
|
||||
private String mFromID;
|
||||
private String mToID;
|
||||
private String mDetails;
|
||||
|
||||
public Builder(CallEventType callEventType)
|
||||
{
|
||||
mCallEventType = callEventType;
|
||||
}
|
||||
|
||||
public Builder aliasList(AliasList aliasList)
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder from(String val)
|
||||
{
|
||||
mFromID = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder details(String details)
|
||||
{
|
||||
mDetails = details;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder to(String toID)
|
||||
{
|
||||
mToID = toID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LJ1200CallEvent build()
|
||||
{
|
||||
return new LJ1200CallEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for the builder
|
||||
*/
|
||||
private LJ1200CallEvent(Builder builder)
|
||||
{
|
||||
this(builder.mCallEventType,
|
||||
builder.mAliasList,
|
||||
builder.mFromID,
|
||||
builder.mToID,
|
||||
builder.mDetails);
|
||||
}
|
||||
|
||||
public static LJ1200CallEvent getLJ1200Event(LJ1200Message message)
|
||||
{
|
||||
CallEventType type = CallEventType.COMMAND;
|
||||
return new LJ1200CallEvent.Builder(type).to(message.getAddress()).details(message.toString()).build();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -307,12 +307,6 @@ public class MPT1327DecoderState extends DecoderState
|
||||
{
|
||||
broadcast(new ChangeChannelTimeoutEvent(this, mChannelType,
|
||||
DecodeConfiguration.DEFAULT_CALL_TIMEOUT_SECONDS * 1000));
|
||||
|
||||
if(mCurrentCallEvent != null)
|
||||
{
|
||||
mCurrentCallEvent.end();
|
||||
mCurrentCallEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,6 +222,11 @@ public class P25AudioModule extends AbstractAudioModule implements Listener<IMes
|
||||
{
|
||||
try
|
||||
{
|
||||
if(!mLibraryLoadStatusLogged)
|
||||
{
|
||||
mLog.info("Loading JMBE library from [" + path.toString() + "]");
|
||||
}
|
||||
|
||||
URLClassLoader childClassLoader = new URLClassLoader(new URL[]{path.toUri().toURL()},
|
||||
this.getClass().getClassLoader());
|
||||
|
||||
@@ -301,6 +306,10 @@ public class P25AudioModule extends AbstractAudioModule implements Listener<IMes
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.info("JMBE audio library path is NOT SET in your User Preferences.");
|
||||
}
|
||||
|
||||
if(audioConverter != null)
|
||||
{
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.p25.message.pdu;
|
||||
|
||||
import io.github.dsheirer.bits.CorrectedBinaryMessage;
|
||||
@@ -22,6 +26,7 @@ import io.github.dsheirer.module.decode.p25.identifier.talkgroup.APCO25ToTalkgro
|
||||
import io.github.dsheirer.module.decode.p25.message.P25Message;
|
||||
import io.github.dsheirer.module.decode.p25.message.tsbk.Opcode;
|
||||
import io.github.dsheirer.module.decode.p25.reference.DataUnitID;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Direction;
|
||||
import io.github.dsheirer.module.decode.p25.reference.PDUFormat;
|
||||
import io.github.dsheirer.module.decode.p25.reference.ServiceAccessPoint;
|
||||
import io.github.dsheirer.module.decode.p25.reference.Vendor;
|
||||
@@ -196,7 +201,7 @@ public class PDUMessage extends P25Message
|
||||
{
|
||||
if(getFormat() == PDUFormat.ALTERNATE_MULTI_BLOCK_TRUNKING_CONTROL)
|
||||
{
|
||||
return Opcode.fromValue(getMessage().getInt(OPCODE));
|
||||
return Opcode.fromValue(getMessage().getInt(OPCODE), Direction.OUTBOUND, getVendor());
|
||||
}
|
||||
|
||||
return Opcode.OSP_UNKNOWN;
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.module.decode.tait;
|
||||
|
||||
import io.github.dsheirer.alias.Alias;
|
||||
import io.github.dsheirer.alias.AliasList;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.event.CallEvent;
|
||||
|
||||
public class Tait1200CallEvent extends CallEvent
|
||||
{
|
||||
public Tait1200CallEvent(CallEventType callEventType,
|
||||
AliasList aliasList,
|
||||
String fromID,
|
||||
String toID,
|
||||
String details)
|
||||
{
|
||||
super(DecoderType.TAIT_1200, callEventType,
|
||||
aliasList, fromID, toID, details);
|
||||
}
|
||||
|
||||
private Alias getAlias(String ident)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getFromIDAlias()
|
||||
{
|
||||
return getAlias(getFromID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alias getToIDAlias()
|
||||
{
|
||||
return getAlias(getToID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChannel()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrequency()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static class Builder
|
||||
{
|
||||
/* Required parameters */
|
||||
private CallEventType mCallEventType;
|
||||
|
||||
/* Optional parameters */
|
||||
private AliasList mAliasList;
|
||||
private String mFromID;
|
||||
private String mToID;
|
||||
private String mDetails;
|
||||
|
||||
public Builder(CallEventType callEventType)
|
||||
{
|
||||
mCallEventType = callEventType;
|
||||
}
|
||||
|
||||
public Builder aliasList(AliasList aliasList)
|
||||
{
|
||||
mAliasList = aliasList;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder from(String val)
|
||||
{
|
||||
mFromID = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder details(String details)
|
||||
{
|
||||
mDetails = details;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder to(String toID)
|
||||
{
|
||||
mToID = toID;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tait1200CallEvent build()
|
||||
{
|
||||
return new Tait1200CallEvent(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor for the builder
|
||||
*/
|
||||
private Tait1200CallEvent(Builder builder)
|
||||
{
|
||||
this(builder.mCallEventType, builder.mAliasList, builder.mFromID, builder.mToID, builder.mDetails);
|
||||
}
|
||||
|
||||
public static Tait1200CallEvent getLJ1200Event(Tait1200GPSMessage message)
|
||||
{
|
||||
CallEventType type = CallEventType.COMMAND;
|
||||
|
||||
return new Tait1200CallEvent.Builder(type).details(message.toString()).build();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
/*******************************************************************************
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,8 +15,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.record.wave;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
@@ -171,14 +172,6 @@ public class WaveWriter implements AutoCloseable
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws IOException
|
||||
{
|
||||
mFileChannel.force(true);
|
||||
mFileChannel.close();
|
||||
mFileChannel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the buffer contents to the file. Assumes that the buffer is full
|
||||
* and the first byte of data is at position 0.
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.sample.buffer;
|
||||
|
||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
||||
@@ -255,7 +259,6 @@ public class ReusableAudioPacket extends AbstractReusableBuffer
|
||||
*
|
||||
* @param audio to load
|
||||
*/
|
||||
@Deprecated
|
||||
public void loadAudioFrom(float[] audio)
|
||||
{
|
||||
mAudioSamples = audio;
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
/*******************************************************************************
|
||||
* sdr-trunk
|
||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
|
||||
* later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program.
|
||||
* If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
******************************************************************************/
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.spectrum;
|
||||
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
@@ -145,8 +149,8 @@ public class ChannelSpectrumPanel extends JPanel implements ChannelEventListener
|
||||
mOverlayPanel.addMouseListener(mouser);
|
||||
mOverlayPanel.addMouseMotionListener(mouser);
|
||||
|
||||
mLayeredPane.add(mSpectrumPanel, new Integer(0), 0);
|
||||
mLayeredPane.add(mOverlayPanel, new Integer(1), 0);
|
||||
mLayeredPane.add(mSpectrumPanel, 0, 0);
|
||||
mLayeredPane.add(mOverlayPanel, 1, 0);
|
||||
|
||||
add(mLayeredPane);
|
||||
}
|
||||
|
||||
@@ -365,8 +365,8 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
||||
mOverlayPanel.addMouseWheelListener(mouser);
|
||||
|
||||
//Add the spectrum and channel panels to the layered panel
|
||||
mLayeredPanel.add(mSpectrumPanel, new Integer(0), 0);
|
||||
mLayeredPanel.add(mOverlayPanel, new Integer(1), 0);
|
||||
mLayeredPanel.add(mSpectrumPanel, 0, 0);
|
||||
mLayeredPanel.add(mOverlayPanel, 1, 0);
|
||||
|
||||
//Create the waterfall
|
||||
mWaterfallPanel.addMouseListener(mouser);
|
||||
@@ -878,13 +878,13 @@ public class SpectralDisplayPanel extends JPanel implements Listener<ReusableCom
|
||||
mWindowOffset = windowOffset;
|
||||
|
||||
Hashtable<Integer,JComponent> labels = new Hashtable<>();
|
||||
labels.put(new Integer(0), new JLabel("1x"));
|
||||
labels.put(new Integer(1), new JLabel("2x"));
|
||||
labels.put(new Integer(2), new JLabel("4x"));
|
||||
labels.put(new Integer(3), new JLabel("8x"));
|
||||
labels.put(new Integer(4), new JLabel("16x"));
|
||||
labels.put(new Integer(5), new JLabel("32x"));
|
||||
labels.put(new Integer(6), new JLabel("64x"));
|
||||
labels.put(0, new JLabel("1x"));
|
||||
labels.put(1, new JLabel("2x"));
|
||||
labels.put(2, new JLabel("4x"));
|
||||
labels.put(3, new JLabel("8x"));
|
||||
labels.put(4, new JLabel("16x"));
|
||||
labels.put(5, new JLabel("32x"));
|
||||
labels.put(6, new JLabel("64x"));
|
||||
|
||||
setLabelTable(labels);
|
||||
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* sdrtrunk
|
||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.spectrum.menu;
|
||||
|
||||
import io.github.dsheirer.dsp.filter.smoothing.SmoothingFilter;
|
||||
import io.github.dsheirer.spectrum.SpectralDisplayAdjuster;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
@@ -16,60 +37,71 @@ public class SmoothingItem extends JSlider implements ChangeListener
|
||||
|
||||
private SpectralDisplayAdjuster mAdjuster;
|
||||
private int mDefaultValue;
|
||||
|
||||
public SmoothingItem( SpectralDisplayAdjuster adjuster, int defaultValue )
|
||||
{
|
||||
super( JSlider.HORIZONTAL,
|
||||
SmoothingFilter.SMOOTHING_MINIMUM,
|
||||
SmoothingFilter.SMOOTHING_MAXIMUM,
|
||||
adjuster.getSmoothing() );
|
||||
|
||||
mDefaultValue = defaultValue;
|
||||
mAdjuster = adjuster;
|
||||
|
||||
setSnapToTicks( true );
|
||||
setMajorTickSpacing( 6 );
|
||||
setMinorTickSpacing( 2 );
|
||||
setPaintTicks( true );
|
||||
setPaintLabels( true );
|
||||
|
||||
Hashtable<Integer,JLabel> labels = new Hashtable<>();
|
||||
labels.put( new Integer( 3 ), new JLabel( "3" ) );
|
||||
labels.put( new Integer( 9 ), new JLabel( "9" ) );
|
||||
labels.put( new Integer( 15 ), new JLabel( "15" ) );
|
||||
labels.put( new Integer( 21 ), new JLabel( "21" ) );
|
||||
labels.put( new Integer( 27 ), new JLabel( "27" ) );
|
||||
|
||||
setLabelTable( labels );
|
||||
|
||||
addChangeListener( this );
|
||||
|
||||
addMouseListener( new MouseListener()
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked( MouseEvent event )
|
||||
{
|
||||
if( event.getClickCount() == 2 )
|
||||
{
|
||||
SmoothingItem.this.setValue( mDefaultValue );
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseReleased( MouseEvent arg0 ) {}
|
||||
public void mousePressed( MouseEvent arg0 ) {}
|
||||
public void mouseExited( MouseEvent arg0 ) {}
|
||||
public void mouseEntered( MouseEvent arg0 ) {}
|
||||
} );
|
||||
public SmoothingItem(SpectralDisplayAdjuster adjuster, int defaultValue)
|
||||
{
|
||||
super(JSlider.HORIZONTAL,
|
||||
SmoothingFilter.SMOOTHING_MINIMUM,
|
||||
SmoothingFilter.SMOOTHING_MAXIMUM,
|
||||
adjuster.getSmoothing());
|
||||
|
||||
mDefaultValue = defaultValue;
|
||||
mAdjuster = adjuster;
|
||||
|
||||
setSnapToTicks(true);
|
||||
setMajorTickSpacing(6);
|
||||
setMinorTickSpacing(2);
|
||||
setPaintTicks(true);
|
||||
setPaintLabels(true);
|
||||
|
||||
Hashtable<Integer,JLabel> labels = new Hashtable<>();
|
||||
labels.put(3, new JLabel("3"));
|
||||
labels.put(9, new JLabel("9"));
|
||||
labels.put(15, new JLabel("15"));
|
||||
labels.put(21, new JLabel("21"));
|
||||
labels.put(27, new JLabel("27"));
|
||||
|
||||
setLabelTable(labels);
|
||||
|
||||
addChangeListener(this);
|
||||
|
||||
addMouseListener(new MouseListener()
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent event)
|
||||
{
|
||||
if(event.getClickCount() == 2)
|
||||
{
|
||||
SmoothingItem.this.setValue(mDefaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent arg0)
|
||||
{
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent arg0)
|
||||
{
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent arg0)
|
||||
{
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent arg0)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent event )
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent event)
|
||||
{
|
||||
int value = ((JSlider)event.getSource()).getValue();
|
||||
int value = ((JSlider)event.getSource()).getValue();
|
||||
|
||||
if( value % 2 == 1 )
|
||||
{
|
||||
mAdjuster.setSmoothing( value );
|
||||
}
|
||||
if(value % 2 == 1)
|
||||
{
|
||||
mAdjuster.setSmoothing(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user