From f710cc4300d4ecf43f9f1f80f847ebbb01dcea6d Mon Sep 17 00:00:00 2001 From: Safgerd Date: Mon, 21 Nov 2022 21:34:45 +0400 Subject: [PATCH] =?UTF-8?q?LabWork03:=20=D0=94=D0=BE=20=D1=83=D0=B4=D0=B0?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20FormMap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DrawningTrackedVehicle.java | 4 + DrawningTracktor.java | 5 + EntityWithRollers.java | 45 +++++++++ FormGallery.form | 41 +++++++++ FormGallery.java | 66 +++++++++++++ FormMapWithSetTracktor.form | 146 +++++++++++++++++++++++++++++ FormMapWithSetTracktor.java | 152 ++++++++++++++++++++++++++++++ FormTracktor.form | 20 ++-- FormTracktor.java | 36 ++++++-- MapWithSetTracktorGeneric.java | 164 +++++++++++++++++++++++++++++++++ Program.java | 7 +- SetTracktorGeneric.java | 64 +++++++++++++ 12 files changed, 732 insertions(+), 18 deletions(-) create mode 100644 EntityWithRollers.java create mode 100644 FormGallery.form create mode 100644 FormGallery.java create mode 100644 FormMapWithSetTracktor.form create mode 100644 FormMapWithSetTracktor.java create mode 100644 MapWithSetTracktorGeneric.java create mode 100644 SetTracktorGeneric.java diff --git a/DrawningTrackedVehicle.java b/DrawningTrackedVehicle.java index 29d692b..085c5e5 100644 --- a/DrawningTrackedVehicle.java +++ b/DrawningTrackedVehicle.java @@ -6,6 +6,10 @@ public class DrawningTrackedVehicle extends DrawningTracktor { Tracktor = new EntityTrackedVehicle(speed, weight, bodyColor, dopColor, bucket, supports); } + public DrawningTrackedVehicle(EntityTrackedVehicle entity, IDrawningRollers rollers) { + super(entity, rollers); + } + @Override public void DrawTransport(Graphics2D g){ if (!(Tracktor instanceof EntityTrackedVehicle trackedVehicle)) diff --git a/DrawningTracktor.java b/DrawningTracktor.java index bc268bd..8354d8f 100644 --- a/DrawningTracktor.java +++ b/DrawningTracktor.java @@ -22,6 +22,11 @@ public class DrawningTracktor { drawningRollers = RollersType.random(countRollers, bodyColor); } + public DrawningTracktor(EntityTracktor entity, IDrawningRollers rollers) { + Tracktor = entity; + drawningRollers = rollers; + } + protected DrawningTracktor(int speed, float weight, Color bodyColor, int countRollers, int tracktorWidth, int tracktorHeight){ this(speed, weight, bodyColor, countRollers); _tracktorWidth = tracktorWidth; diff --git a/EntityWithRollers.java b/EntityWithRollers.java new file mode 100644 index 0000000..0539c01 --- /dev/null +++ b/EntityWithRollers.java @@ -0,0 +1,45 @@ +import java.util.Random; + +public class EntityWithRollers { + static Random rnd = new Random(); + private Object[] entities; + public int entitiesCount = 0; + private Object[] rollers; + public int rollersCount = 0; + + public EntityWithRollers(int count) { + //new T[count] не работает "Type parameter 'T' cannot be instantiated directly" + entities = new Object[count]; + //new U[count] не работает "Type parameter 'U' cannot be instantiated directly" + rollers = new Object[count]; + } + + public boolean add(T entity) { + if (entitiesCount >= entities.length) { + return false; + } + entities[entitiesCount++] = entity; + return true; + } + + public boolean add(U roller) { + if (rollersCount >= rollers.length) { + return false; + } + rollers[rollersCount++] = roller; + return true; + } + + public IDrawningObject constructArtillery() { + if (entitiesCount == 0 || rollersCount == 0) { + return null; + } + EntityTracktor entity = (EntityTracktor) entities[rnd.nextInt(0, entitiesCount)]; + IDrawningRollers roller = (IDrawningRollers) rollers[rnd.nextInt(0, rollersCount)]; + + if (entity instanceof EntityTrackedVehicle advancedEntity) { + return new DrawningObjectExcavator(new DrawningTrackedVehicle(advancedEntity, roller)); + } + return new DrawningObjectExcavator(new DrawningTracktor(entity, roller)); + } +} diff --git a/FormGallery.form b/FormGallery.form new file mode 100644 index 0000000..bc541db --- /dev/null +++ b/FormGallery.form @@ -0,0 +1,41 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/FormGallery.java b/FormGallery.java new file mode 100644 index 0000000..f59dd45 --- /dev/null +++ b/FormGallery.java @@ -0,0 +1,66 @@ +import javax.swing.*; +import java.awt.*; +import java.util.Random; + +public class FormGallery extends JFrame { + private static final Random rnd = new Random(); + private JPanel contentPanel; + private JButton buttonRefresh; + private JPanel pictureBox; + private IDrawningObject first; + private IDrawningObject second; + private IDrawningObject third; + + private final EntityWithRollers storage; + + public FormGallery() { + setTitle("Галлерея"); + setContentPane(contentPanel); + + storage = new EntityWithRollers<>(20); + + for(int i = 0; i < 20; i++) { + if (rnd.nextBoolean()) { + storage.add(new EntityTrackedVehicle( + rnd.nextInt(100, 300), + rnd.nextInt(1000, 2000), + new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), + new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), + rnd.nextBoolean(), + rnd.nextBoolean() + )); + } else { + storage.add(new EntityTracktor( + rnd.nextInt(100, 300), + rnd.nextInt(1000, 2000), + new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)) + )); + } + storage.add(RollersType.random(rnd.nextInt(4, 7), new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)))); + } + + buttonRefresh.addActionListener(e -> { + first = storage.constructArtillery(); + second = storage.constructArtillery(); + third = storage.constructArtillery(); + + first.setObject(0, 10, pictureBox.getWidth(), pictureBox.getHeight()); + second.setObject(150, 10, pictureBox.getWidth(), pictureBox.getHeight()); + third.setObject(300, 10, pictureBox.getWidth(), pictureBox.getHeight()); + + repaint(); + }); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + Graphics2D g2g = (Graphics2D) pictureBox.getGraphics(); + + if (first != null && second != null && third != null) { + first.drawningObject(g2g); + second.drawningObject(g2g); + third.drawningObject(g2g); + } + } +} diff --git a/FormMapWithSetTracktor.form b/FormMapWithSetTracktor.form new file mode 100644 index 0000000..f1cf28e --- /dev/null +++ b/FormMapWithSetTracktor.form @@ -0,0 +1,146 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/FormMapWithSetTracktor.java b/FormMapWithSetTracktor.java new file mode 100644 index 0000000..c99edc4 --- /dev/null +++ b/FormMapWithSetTracktor.java @@ -0,0 +1,152 @@ +import javax.swing.*; +import javax.swing.text.DefaultFormatterFactory; +import javax.swing.text.MaskFormatter; +import java.awt.*; +import java.text.ParseException; + +public class FormMapWithSetTracktor extends JFrame { + private JPanel ContentPanel; + private JPanel pictureBox; + private JPanel toolsGroup; + private JLabel toolsLabel; + private JComboBox comboBoxMapSelector; + private JButton buttonAddTracktor; + private JFormattedTextField textBoxPosition; + private JButton buttonRemoveTracktor; + private JButton buttonShowStorage; + private JButton buttonShowOnMap; + private JButton buttonUp; + private JButton buttonLeft; + private JButton buttonRight; + private JButton buttonDown; + + private Image bufferedImage; + private MapWithSetTracktorGeneric _mapTracktorCollectionGeneric; + + public FormMapWithSetTracktor() { + this.setTitle("Трактор"); + this.setContentPane(ContentPanel); + this.setSize(800,500); + + try { + textBoxPosition.setFormatterFactory(new DefaultFormatterFactory(new MaskFormatter("##"))); + } catch (ParseException e) { + e.printStackTrace(); + } + + comboBoxMapSelector.addActionListener(e -> { + AbstractMap map = switch (((JComboBox) e.getSource()).getSelectedItem().toString()) { + case "Простая карта" -> new SimpleMap(); + case "Свалка карта" -> new DumpMap(); + default -> null; + }; + + if (map != null) { + _mapTracktorCollectionGeneric = new MapWithSetTracktorGeneric<>(pictureBox.getWidth(), pictureBox.getHeight(), map); + } else { + _mapTracktorCollectionGeneric = null; + } + }); + + buttonAddTracktor.addActionListener(e -> { + if (_mapTracktorCollectionGeneric == null) { + return; + } + + FormTracktor dialog = new FormTracktor(); + dialog.setSize(800, 500); + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + + if (dialog.getSelectedTracktor() != null) { + DrawningObjectExcavator tracktor = new DrawningObjectExcavator(dialog.getSelectedTracktor()); + if (_mapTracktorCollectionGeneric.addTracktor(tracktor) != -1) + { + JOptionPane.showMessageDialog(this, "Объект добавлен", "Успех", JOptionPane.INFORMATION_MESSAGE); + bufferedImage = _mapTracktorCollectionGeneric.showSet(); + repaint(); + } + else + { + JOptionPane.showMessageDialog(this, "Не удалось добавить объект", "Провал", JOptionPane.INFORMATION_MESSAGE); + } + } + }); + + buttonRemoveTracktor.addActionListener(e -> { + String text = textBoxPosition.getText(); + if (text == null || text.isEmpty()) { + return; + } + + if (JOptionPane.showConfirmDialog(this, "Удалить объект?", "Удаление", JOptionPane.YES_NO_OPTION) == JOptionPane.NO_OPTION) { + return; + } + + int position = Integer.parseInt(text); + + if (_mapTracktorCollectionGeneric.removeTracktorAt(position) != null) { + JOptionPane.showMessageDialog(this, "Объект удалён", "Успех", JOptionPane.INFORMATION_MESSAGE); + bufferedImage = _mapTracktorCollectionGeneric.showSet(); + repaint(); + } else { + JOptionPane.showMessageDialog(this, "Не удалось удалить объект", "Провал", JOptionPane.INFORMATION_MESSAGE); + } + }); + + buttonShowStorage.addActionListener(e -> { + if (_mapTracktorCollectionGeneric == null) { + return; + } + bufferedImage = _mapTracktorCollectionGeneric.showSet(); + repaint(); + }); + + buttonShowOnMap.addActionListener(e -> { + if (_mapTracktorCollectionGeneric == null) { + return; + } + bufferedImage = _mapTracktorCollectionGeneric.showOnMap(); + repaint(); + }); + + buttonLeft.addActionListener(e -> { + if (_mapTracktorCollectionGeneric != null) { + bufferedImage = _mapTracktorCollectionGeneric.moveObject(Direction.Left); + repaint(); + } + }); + + buttonRight.addActionListener(e -> { + if (_mapTracktorCollectionGeneric != null) { + bufferedImage = _mapTracktorCollectionGeneric.moveObject(Direction.Right); + repaint(); + } + }); + + buttonUp.addActionListener(e -> { + if (_mapTracktorCollectionGeneric != null) { + bufferedImage = _mapTracktorCollectionGeneric.moveObject(Direction.Up); + repaint(); + } + }); + + buttonDown.addActionListener(e -> { + if (_mapTracktorCollectionGeneric != null) { + bufferedImage = _mapTracktorCollectionGeneric.moveObject(Direction.Down); + repaint(); + } + }); + } + + @Override + public void paint(Graphics g) { + super.paint(g); + + if (bufferedImage != null) { + pictureBox.paintComponents(bufferedImage.getGraphics()); + pictureBox.getGraphics().drawImage(bufferedImage, 0, 0, null); + } + } +} diff --git a/FormTracktor.form b/FormTracktor.form index 8a2e7dd..b83cb39 100644 --- a/FormTracktor.form +++ b/FormTracktor.form @@ -1,6 +1,6 @@
- + @@ -48,7 +48,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -68,7 +68,7 @@ - + @@ -80,7 +80,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -110,6 +110,14 @@ + + + + + + + + diff --git a/FormTracktor.java b/FormTracktor.java index 126ac7d..ad16359 100644 --- a/FormTracktor.java +++ b/FormTracktor.java @@ -4,7 +4,7 @@ import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.Random; -public class FormTracktor extends JFrame { +public class FormTracktor extends JDialog { private JPanel ContentPanel; private JButton buttonCreate; private JLabel speedLabel; @@ -16,8 +16,10 @@ public class FormTracktor extends JFrame { private JButton buttonUp; private JPanel pictureBox; private JButton buttonCreateModif; + private JButton buttonSelect; private DrawningTracktor _tracktor; + private DrawningTracktor selectedTracktor; public FormTracktor(){ setTitle("Трактор"); @@ -27,24 +29,31 @@ public class FormTracktor extends JFrame { // Обработка нажатия кнопки "Создать" buttonCreate.addActionListener(e->{ Random rnd = new Random(); - _tracktor = new DrawningTracktor( - rnd.nextInt(100, 300), - rnd.nextInt(1000, 2000), - new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), - rnd.nextInt(3,8) - ); + Color color = JColorChooser.showDialog(this, "Цвет", new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256))); + if (color == null) { + color = new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)); + } + _tracktor = new DrawningTracktor(rnd.nextInt(100, 300), rnd.nextInt(1000, 2000), color, rnd.nextInt(3,8)); setData(); }); // Обработка нажатия кнопки "Модификация" buttonCreateModif.addActionListener(e->{ Random rnd = new Random(); + Color color = JColorChooser.showDialog(this, "Основной цвет", Color.white); + if (color == null) { + color = new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)); + } + Color dopColor = JColorChooser.showDialog(this, "Дополнительный цвет", Color.white); + if (dopColor == null) { + dopColor = new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)); + } _tracktor = new DrawningTrackedVehicle( rnd.nextInt(100, 300), rnd.nextInt(1000, 2000), - new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), + color, rnd.nextInt(3,8), - new Color(rnd.nextInt(0, 256), rnd.nextInt(0, 256), rnd.nextInt(0, 256)), + dopColor, rnd.nextBoolean(), rnd.nextBoolean() ); @@ -79,6 +88,11 @@ public class FormTracktor extends JFrame { } }); + buttonSelect.addActionListener(e->{ + selectedTracktor = _tracktor; + dispose(); + }); + pictureBox.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { @@ -100,6 +114,10 @@ public class FormTracktor extends JFrame { repaint(); } + public DrawningTracktor getSelectedTracktor() { + return selectedTracktor; + } + @Override public void paint(Graphics g){ super.paint(g); diff --git a/MapWithSetTracktorGeneric.java b/MapWithSetTracktorGeneric.java new file mode 100644 index 0000000..44fb57c --- /dev/null +++ b/MapWithSetTracktorGeneric.java @@ -0,0 +1,164 @@ +import java.awt.*; +import java.awt.image.BufferedImage; + +public class MapWithSetTracktorGeneric { + public final int _pictureWidth; + public final int _pictureHeight; + public final int _placeSizeWidth = 150; + public final int _placeSizeHeight = 100; + private final SetTracktorGeneric _setTracktor; + private final U _map; + + public MapWithSetTracktorGeneric(int picWidth, int picHeight, U map) { + int width = picWidth / _placeSizeWidth; + int height = picHeight / _placeSizeHeight; + _setTracktor = new SetTracktorGeneric(width * height); + _pictureWidth = picWidth; + _pictureHeight = picHeight; + _map = map; + } + + public int addTracktor(T tracktor) { + return _setTracktor.insert(tracktor); + } + + public T removeTracktorAt(int position) { + return _setTracktor.remove(position); + } + + public Image showSet() { + BufferedImage img = new BufferedImage(_pictureWidth, _pictureHeight, BufferedImage.TYPE_INT_ARGB); + Graphics2D gr = (Graphics2D)img.getGraphics(); + drawBackground(gr); + drawTracktor(gr); + return img; + } + + public Image showOnMap() { + shaking(); + for (int i = 0; i < _setTracktor.getCount(); i++) + { + var tracktor = _setTracktor.get(i); + if (tracktor != null) + { + return _map.CreateMap(_pictureWidth, _pictureHeight, tracktor); + } + } + return new BufferedImage(_pictureWidth, _pictureHeight, BufferedImage.TYPE_INT_ARGB); + } + + public Image moveObject(Direction direction) { + if (_map != null) { + return _map.MoveObject(direction); + } + return new BufferedImage(_pictureWidth, _pictureHeight, BufferedImage.TYPE_INT_ARGB); + } + + private void shaking() { + int j = _setTracktor.getCount() - 1; + for (int i = 0; i < _setTracktor.getCount(); i++) + { + if (_setTracktor.get(i) == null) + { + for (; j > i; j--) + { + var tracktor = _setTracktor.get(j); + if (tracktor != null) + { + _setTracktor.insert(tracktor , i); + _setTracktor.remove(j); + break; + } + } + if (j <= i) + { + return; + } + } + } + } + + private void drawBackground(Graphics2D g) { + Color pen = Color.WHITE; + Stroke penStroke = new BasicStroke(3); + Color brush = Color.LIGHT_GRAY; + Color disabledPersonBadgeBrush = Color.WHITE; + for (int i = 0; i < _pictureWidth / _placeSizeWidth; i++) + { + for (int j = 0; j < _pictureHeight / _placeSizeHeight; j++) + { + // Асфальт + g.setColor(brush); + g.fillRect( i * _placeSizeWidth, j * _placeSizeHeight, _placeSizeWidth, _placeSizeHeight); + // Разметка + g.setColor(pen); + g.setStroke(penStroke); + g.drawLine(i * _placeSizeWidth, j * _placeSizeHeight, (i * _placeSizeWidth) + (_placeSizeWidth / 2), j * _placeSizeHeight); + g.drawLine(i * _placeSizeWidth, j * _placeSizeHeight, i * _placeSizeWidth, (j * _placeSizeHeight) + _placeSizeHeight); + g.drawLine(i * _placeSizeWidth, (j + 1) * _placeSizeHeight, (i * _placeSizeWidth) + (_placeSizeWidth / 2), (j + 1) * _placeSizeHeight); + if (j%2==0) + { + // Знак паркинга + g.setColor(pen); + g.setStroke(penStroke); + g.drawLine(i * _placeSizeWidth + 20, j * _placeSizeHeight + 60, i * _placeSizeWidth + 60, j * _placeSizeHeight + 60); + g.drawLine(i * _placeSizeWidth + 20, j * _placeSizeHeight + 60, i * _placeSizeWidth + 20, j * _placeSizeHeight + 40); + g.drawLine(i * _placeSizeWidth + 20, j * _placeSizeHeight + 40, i * _placeSizeWidth + 40, j * _placeSizeHeight + 40); + g.drawLine(i * _placeSizeWidth + 40, j * _placeSizeHeight + 40, i * _placeSizeWidth + 40, j * _placeSizeHeight + 60); + } + else + { + // Инвалид + // Колесо + g.setColor(pen); + g.setStroke(penStroke); + g.drawOval(i * _placeSizeWidth + 40, j * _placeSizeHeight + 50, 30, 30); + // Голова + g.setColor(disabledPersonBadgeBrush); + g.setStroke(new BasicStroke(1)); + g.fillOval(i * _placeSizeWidth + 20, j * _placeSizeHeight + 60, 10, 10); + // Туловище + g.setColor(pen); + g.setStroke(penStroke); + g.drawLine(i * _placeSizeWidth + 25, j * _placeSizeHeight + 65, i * _placeSizeWidth + 55, j * _placeSizeHeight + 60); + // Рука + g.drawLine(i * _placeSizeWidth + 32, j * _placeSizeHeight + 65, i * _placeSizeWidth + 38, j * _placeSizeHeight + 55); + // Нога + g.drawLine(i * _placeSizeWidth + 55, j * _placeSizeHeight + 60, i * _placeSizeWidth + 60, j * _placeSizeHeight + 40); + // Голеностоп + g.drawLine(i * _placeSizeWidth + 60, j * _placeSizeHeight + 40, i * _placeSizeWidth + 65, j * _placeSizeHeight + 38); + } + } + } + g.setStroke(new BasicStroke(1)); + } + + private void drawTracktor(Graphics2D g) { + int width = _pictureWidth / _placeSizeWidth; + int curWidth = width-1; + int curHeight = 0; + for (int i = 0; i < _setTracktor.getCount(); i++) + { + // установка позиции + // Влево - вниз + if (_setTracktor.get(i) != null){ + _setTracktor.get(i).setObject( + curWidth * _placeSizeWidth, + curHeight * _placeSizeHeight, + _pictureWidth, + _pictureHeight); + + _setTracktor.get(i).drawningObject(g); + if (curWidth > 0) + { + curWidth--; + } + else + { + curWidth = width-1; + curHeight++; + } + } + } + } +} diff --git a/Program.java b/Program.java index 339ae6b..786e3d7 100644 --- a/Program.java +++ b/Program.java @@ -2,8 +2,9 @@ import javax.swing.*; public class Program { public static void main(String[] args){ - FormMap formMap = new FormMap(); - formMap.setVisible(true); - formMap.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + FormGallery form = new FormGallery(); + form.setSize(500, 300); + form.setVisible(true); + form.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } } diff --git a/SetTracktorGeneric.java b/SetTracktorGeneric.java new file mode 100644 index 0000000..633a23a --- /dev/null +++ b/SetTracktorGeneric.java @@ -0,0 +1,64 @@ +public class SetTracktorGeneric { + private final Object[] _places; + + public int getCount() { + return _places.length; + } + + public SetTracktorGeneric(int count) { + _places = new Object[count]; + } + + public int insert(T tracktor) { + return insert(tracktor, 0); + } + + public int insert(T tracktor, int position) { + if (position < 0 || position >= getCount()) { + return -1; + } + + if (_places[position] == null) { + _places[position] = tracktor; + return position; + } + + int tmp = -1; + + for(int i = position; i < getCount(); i++) + { + if (_places[i] == null) + { + tmp = i; + break; + } + } + if (tmp != -1) + { + System.arraycopy(_places, position, _places, position + 1, tmp - position); + _places[position] = tracktor; + return position; + } + return -1; + } + + @SuppressWarnings("unchecked") + public T remove(int position) { + if (position < getCount() && position >= 0) + { + T temp = (T) _places[position]; + _places[position] = null; + return temp; + } + return null; + } + + @SuppressWarnings("unchecked") + public T get(int position) { + if (position < 0 || position >= getCount()) { + return null; + } + + return (T) _places[position]; + } +}