我的JProgressBar有问题。我有一个带有进度条的框架,我想在读取一部分日志后重新绘制。我想更改进度条中绘制的值和字符串。我之前从未使用过进度条,因此我对这些事情很陌生。下面的方法在一个名为Reader的类中,它不在框架类中。
public void readLog(File file){
ArrayList<String> list = getFile(file);
setChanged();
notifyObservers("Start reading log...");
readPlayers(list);
setChanged();
notifyObservers("Reading headshots...")
readHeadshots(list);
setChanged();
notifyObservers("Reading headshots...")
setChanged();
notifyObservers("Done reading log...")
}
这是框架中的进度条。应用程序启动时会调用(写入)此(主)帧。
progressBar = new JProgressBar(0,3);
progressBar.setValue(0);
progressBar.setStringPainted(true)
这是使用notifyObservers时调用的更新。
public void update(Observable o, Object arg) { ;
progressBar.setValue((progressBar.getValue() + 1));
progressBar.setStringPainted(true);
progressBar.setString((String)arg);
progressBar.repaint();
}
我认为它会起作用,但事实并非如此。我已经检查过它是否进入更新方法而且确实如此。当我把它放在system.out.prtln中时,arg(与notifyobservers一起给出的字符串)也可以工作。
有人能帮助我吗?还是指出我的方向好?
更新
好的,这是它的工作原理。我点击下面发布的框架上的阅读日志。我有一个看起来像这个按钮的控制器
if(jb.getText() == "Read Log") {
File selectedFile = FileSelector.getInstance().selectFile();
Reader.getInstance().readLog(selectedFile);
}
我使用JFileChooser来选择文件。
public File selectFile(){
JFileChooser chooser= new JFileChooser();
int returnVal = chooser.showOpenDialog(null);
if(returnVal == JFileChooser.APPROVE_OPTION) {
File selectedFile = chooser.getSelectedFile();
return selectedFile;
}
return null;
}
当我选择了我想要阅读的服务器日志时,我点击JFileChooser上的open,它会将文件发送到我的类阅读器上的方法readLog。
readLog方法:
public void readLog(File file){
this.file = file;
execute(); // if i remove this execute it wont start reading the log.
}
这是我的框架。
package view;
import java.awt.Color;
public class MainFrame extends JFrame {
private TableModelPlayer model;
private JTable playerTable;
private JTextField txtSearchTerm;
JProgressBar progressBar;
public MainFrame() {
initGui();
}
private void initGui(){
setResizable(false);
setAutoRequestFocus(true);
setTitle("WARBAND STATISTICS");
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(1000,900));
JPanel tablePanel = new JPanel();
JPanel buttonPanel = new JPanel();
progressBar = new JProgressBar(0,100);
progressBar.setVisible(true);
progressBar.setStringPainted(true);
SwingWorker myWorker = new Reader();
myWorker.execute(); // if i have this here it doesn't startedreading thelog
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent event) {
switch (event.getPropertyName()) {
case "progress":
progressBar.setIndeterminate(false);
progressBar.setValue((Integer) event.getNewValue());
break;
case "message":
progressBar.setString((String)event.getNewValue());
break;
}
}
});
GroupLayout groupLayout = new GroupLayout(getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(tablePanel, GroupLayout.PREFERRED_SIZE, 748, GroupLayout.PREFERRED_SIZE)
.addGap(18))
.addGroup(Alignment.LEADING, groupLayout.createSequentialGroup()
.addGap(10)
.addComponent(progressBar, GroupLayout.PREFERRED_SIZE, 724, GroupLayout.PREFERRED_SIZE)
.addGap(32)))
.addComponent(buttonPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap())
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addComponent(tablePanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(progressBar, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE))
.addComponent(buttonPanel, GroupLayout.DEFAULT_SIZE, 849, Short.MAX_VALUE))
.addContainerGap())
);
JScrollPane scrollPane = new JScrollPane();
tablePanel.add(scrollPane);
JButton btnReadLog = new JButton("Read Log");
btnReadLog.setBackground(Color.YELLOW);
btnReadLog.addActionListener(new MainFrameController(btnReadLog));
btnReadLog.setPreferredSize(new Dimension(200,40));
btnReadLog.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
JButton btnSelectPlayer = new JButton("Select player");
btnSelectPlayer.setBackground(Color.YELLOW);
btnSelectPlayer.setPreferredSize(new Dimension(200, 40));
btnSelectPlayer.addActionListener(new MainFrameController(btnSelectPlayer, this));
txtSearchTerm = new JTextField();
txtSearchTerm.setColumns(10);
JRadioButton radioBtnId = new JRadioButton("Search by id");
JRadioButton radioBtnName = new JRadioButton("Search by name");
radioBtnName.setSelected(true);
ButtonGroup group = new ButtonGroup();
group.add(radioBtnId);
group.add(radioBtnName);
JButton btnSearch = new JButton("Search");
btnSearch.setBackground(Color.YELLOW);
btnSearch.addActionListener(new MainFrameController(btnSearch, radioBtnId, radioBtnName, txtSearchTerm));
JButton btnReset = new JButton("Reset List");
btnReset.setBackground(Color.YELLOW);
btnReset.addActionListener(new MainFrameController(btnReset));
GroupLayout gl_buttonPanel = new GroupLayout(buttonPanel);
gl_buttonPanel.setHorizontalGroup(
gl_buttonPanel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_buttonPanel.createSequentialGroup()
.addGroup(gl_buttonPanel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_buttonPanel.createSequentialGroup()
.addComponent(btnSearch)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(btnReset, GroupLayout.PREFERRED_SIZE, 104, GroupLayout.PREFERRED_SIZE))
.addComponent(btnReadLog, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(btnSelectPlayer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(txtSearchTerm, GroupLayout.DEFAULT_SIZE, 206, Short.MAX_VALUE)
.addComponent(radioBtnId)
.addComponent(radioBtnName))
.addContainerGap())
);
gl_buttonPanel.setVerticalGroup(
gl_buttonPanel.createParallelGroup(Alignment.LEADING)
.addGroup(gl_buttonPanel.createSequentialGroup()
.addGap(37)
.addComponent(btnReadLog, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addGap(5)
.addComponent(btnSelectPlayer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(txtSearchTerm, GroupLayout.PREFERRED_SIZE, 29, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addComponent(radioBtnId)
.addPreferredGap(ComponentPlacement.RELATED)
.addComponent(radioBtnName)
.addPreferredGap(ComponentPlacement.UNRELATED)
.addGroup(gl_buttonPanel.createParallelGroup(Alignment.BASELINE)
.addComponent(btnSearch)
.addComponent(btnReset))
.addContainerGap(609, Short.MAX_VALUE))
);
buttonPanel.setLayout(gl_buttonPanel);
playerTable = new JTable(model = new TableModelPlayer()){
@Override
public boolean isCellEditable(int row, int column){
return false;
}
};
playerTable.addMouseListener(new MouseListenerTablePlayer(playerTable));
playerTable.getTableHeader().setReorderingAllowed(false);
playerTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
scrollPane.setViewportView(playerTable);
scrollPane.setPreferredSize(new Dimension(720,800));
getContentPane().setLayout(groupLayout);
setVisible(true);
this.pack();
this.setLocationRelativeTo(null);
}
public JTable getPlayerTable() {
return playerTable;
}
public void setPlayerTable(JTable playerTable) {
this.playerTable = playerTable;
}
}
我的读者班:
package model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;
import DataLayer.DatabaseConnector;
public class Reader extends SwingWorker <Void, String>{
private static Reader instance;
File file;
public Reader(){
}
public static Reader getInstance(){
if(instance == null){
instance = new Reader();
}
return instance;
}
public ArrayList<String> getFile(File file){
try (BufferedReader br = new BufferedReader(new FileReader(file.getAbsolutePath())))
{
String sCurrentLine;
ArrayList<String> list = new ArrayList<String>();
while ((sCurrentLine = br.readLine()) != null) {
list.add(sCurrentLine);
}
return list;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void readLog(File file){
this.file = file;
execute();
}
public void readPlayers(ArrayList<String> list){
System.out.println("Reading players...");
ArrayList<String> joinedPlayers = new ArrayList<String>();
for (String string : list) {
if (string.contains("has joined the game with ID: ")) {
joinedPlayers.add(string);
}
}
Player p;
for (String string : joinedPlayers){
String strList[] = string.split(" ");
p = new Player();
p.playerId = strList[10];
p.playerName = strList[3];
if(PlayerContainer.getInstance().checkIfPlayerExists(p) == false){
PlayerContainer.getInstance().getPlayersList().add(p);
DatabaseConnector.getInstance().insertPlayer(p);
}
}
}
public void readHeadshots(ArrayList<String> list){
System.out.println("Reading headshots...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> headshotList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_headshot>")) {
headshotList.add(string);
}
}
for (String string : headshotList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.headshots = p.headshots + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readOneHanderSwordKills(ArrayList<String> list){
System.out.println("Reading one handed sword kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> oneHandSwordKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_swordone>")) {
oneHandSwordKillsList.add(string);
}
}
for (String string : oneHandSwordKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.oneHandSwordKills = p.oneHandSwordKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readTwoHanderSwordKills(ArrayList<String> list){
System.out.println("Reading two handed sword kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> twoHandSwordKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_swordtwo>")) {
twoHandSwordKillsList.add(string);
}
}
for (String string : twoHandSwordKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.twoHandSwordKills = p.twoHandSwordKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readOneHanderAxeKills(ArrayList<String> list){
System.out.println("Reading one handed axe kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> oneHandAxeKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_axeone>")) {
oneHandAxeKillsList.add(string);
}
}
for (String string : oneHandAxeKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.oneHandAxeKills = p.oneHandAxeKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readTwoHanderAxeKills(ArrayList<String> list){
System.out.println("Reading two handed axe kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> twoHandAxeKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_axetwo>")) {
twoHandAxeKillsList.add(string);
}
}
for (String string : twoHandAxeKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.twoHandAxeKills = p.twoHandAxeKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readJavelinKills(ArrayList<String> list){
System.out.println("Reading javelin kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> javelinKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_javelin>")) {
javelinKillsList.add(string);
}
}
for (String string : javelinKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.javelinKills = p.javelinKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readMaulKills(ArrayList<String> list){
System.out.println("Reading maul kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> maulKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_maul>")) {
maulKillsList.add(string);
}
}
for (String string : maulKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.maulKills = p.maulKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readCrossbowKills(ArrayList<String> list){
System.out.println("Reading crossbow kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> crossbowKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_crossbow>")) {
crossbowKillsList.add(string);
}
}
for (String string : crossbowKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.crossbowKills = p.crossbowKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readBowKills(ArrayList<String> list){
System.out.println("Reading bow kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> bowKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_bow>")) {
bowKillsList.add(string);
}
}
for (String string : bowKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.bowKills = p.bowKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readCouchedLanceKills(ArrayList<String> list){
System.out.println("Reading couched lance kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> couchedLanceKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_couchedlance>")) {
couchedLanceKillsList.add(string);
}
}
for (String string : couchedLanceKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.couchedLanceKills = p.couchedLanceKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readSpearKills(ArrayList<String> list){
System.out.println("Reading spear kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> spearKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_spear>")) {
spearKillsList.add(string);
}
}
for (String string : spearKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.spearKills = p.spearKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readDeaths (ArrayList<String> list){
System.out.println("Reading deaths...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> deathList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico")) {
deathList.add(string);
}
}
for (String string : deathList) {
String strList[] = string.split(" ");
String playername = "";
if(strList.length == 6){
playername = strList[5];
}
if(strList.length == 5){
playername = strList[4];
}
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(playername)){
p.deaths = p.deaths + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
public void readBluntKills (ArrayList<String> list){
System.out.println("Reading blunt kills...");
ArrayList<Player> DbList = new ArrayList<Player>();
ArrayList<String> bluntKillsList = new ArrayList<String>();
for (String string : list) {
if (string.contains("<img=ico_blunt>")) {
bluntKillsList.add(string);
}
}
for (String string : bluntKillsList) {
String strList[] = string.split(" ");
for (Player p : PlayerContainer.getInstance().getPlayersList()) {
if(p.getPlayerName().equalsIgnoreCase(strList[3])){
p.bluntKills = p.bluntKills + 1;
DbList.add(p);
}
}
}
DatabaseConnector.getInstance().updatePlayer(DbList);
}
@Override
protected Void doInBackground() throws Exception {
ArrayList<String> list = getFile(file);
String message=null;
message="Start reading log...";
publish(message);
readPlayers(list);
setProgress(0);
message="Start reading headshots...";
publish(message);
readHeadshots(list);
setProgress(7);
message="Start reading one handed sword kills...";
publish(message);
readOneHanderSwordKills(list);
setProgress(14);
message="Start reading two handed sword kills...";
publish(message);
readTwoHanderSwordKills(list);
setProgress(21);
message="Start reading one handed axe kills...";
publish(message);
readOneHanderAxeKills(list);
setProgress(28);
message="Start reading two handed axe kills...";
publish(message);
readTwoHanderAxeKills(list);
setProgress(35);
message="Start reading javelin kills...";
publish(message);
readJavelinKills(list);
setProgress(42);
message="Start reading maul kills...";
publish(message);
readMaulKills(list);
setProgress(49);
message="Start reading crossbow kills...";
publish(message);
readCrossbowKills(list);
setProgress(56);
message="Start reading bow kills...";
publish(message);
readBowKills(list);
setProgress(63);
message="Start reading couched lance kills...";
publish(message);
readCouchedLanceKills(list);
setProgress(70);
message="Start reading spear kills...";
publish(message);
readSpearKills(list);
setProgress(77);
message="Start reading blunt kills...";
publish(message);
readBluntKills(list);
setProgress(84);
message="Start reading deaths...";
publish(message);
setProgress(91);
readDeaths(list);
PlayerContainer.getInstance().updatePlayerList();
message="Done reading log...";
publish(message);
setProgress(100);
return null;
}
@Override
protected void process(List<String> chunks){
if(chunks == null || chunks.isEmpty())
return;
firePropertyChange("message",null,chunks.get(0));
}
}
答案 0 :(得分:2)
如果我是你,我会使用PropertyChangeListener
(Oberserver)和PropertyChangeSupport
(Observable)。如果readLog(File f)
这是一个繁重的操作,请不要阻止你的gui。我会使用SwingWorker
。以下是progressBar的完整示例,我非常喜欢SwingWorker example。
一个简单的例子:
public class Worker extends SwingWorker<Void, String> {
@Override
protected Void doInBackground() throws Exception {
//here you make heavy task this is running in another thread not in EDT
setProgress(0);
setChanged();
publish("Start reading log...");
setProgress(43);
//another operation
publish("Start reading log...");
setProgress(89);
.
.
return null; // you have to add this, Void is wrapper class of native void
}
@Override
protected void process(List<String> chunks){
// here is called when you call publish in doInBackground, this is executed in EDT
if(chunks == null || chunks.isEmpty())
return;
firePropertyChange("message",null,chunks.get(0));
}
}
在您拥有progressBar的客户端代码中:
SwingWorker myWorker = new Worker();
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(final PropertyChangeEvent event) {
switch (event.getPropertyName()) {
case "progress":
myProgressBar.setIndeterminate(false);
myProgressBar.setValue((Integer) event.getNewValue());
break;
case "message":
myProgressBar.setString((String)event.getNewValue());
break;
}
}
});
myWorker.execute(); // you use swing worker in this way, you can only execute it once!
<强>更新强>
不要让你的SwingWorker
单身,你只能执行一次实例,而且你的“单身”不是单身,因为你的构造函数是公开的。
你必须为你的工人做这样的事情
public class MainFrame extends JFrame {
private JProgressBar progressBar;
private PropertyChangeListener listener = new MyPropertyChangeListener();
//in some place you have something like
readLogButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent evt){
if(jb.getText().equals("Read Log")) { // you compare objects with equals not with ==
File selectedFile = FileSelector.getInstance().selectFile();
Reader myWorker = new Reader();
myWorker.addPropertyChangeListener(listener);
myWorker.readLog(selectedFile);
}
}
});
//And the private inner class (you can use anonymous class if you want it)
private class MyPropertyChangeListener implements PropertyChangeListener{
@Override
public void propertyChange(final PropertyChangeEvent event) {
switch (event.getPropertyName()) {
case "progress":
progressBar.setIndeterminate(false);
progressBar.setValue((Integer) event.getNewValue());
break;
case "message":
progressBar.setString((String)event.getNewValue());
break;
}
}
}
}