OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 174 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.erp.core.sales.pos.ui;
15
 
16
import org.openconcerto.erp.core.sales.pos.model.Article;
17
import org.openconcerto.erp.core.sales.pos.model.Paiement;
174 ilm 18
import org.openconcerto.erp.core.sales.pos.model.TicketItem;
18 ilm 19
 
20
import java.awt.Color;
21
import java.awt.Dimension;
22
import java.awt.Font;
23
import java.awt.Graphics;
24
import java.awt.Graphics2D;
25
import java.awt.RenderingHints;
26
import java.awt.event.KeyEvent;
27
import java.awt.event.MouseEvent;
28
import java.awt.event.MouseListener;
29
import java.awt.geom.Rectangle2D;
174 ilm 30
import java.math.BigDecimal;
142 ilm 31
import java.util.List;
18 ilm 32
 
83 ilm 33
import javax.swing.JOptionPane;
18 ilm 34
import javax.swing.JPanel;
35
 
36
public class PaiementPanel extends JPanel implements CaisseListener, MouseListener, BarcodeListener {
142 ilm 37
    private static final int PAYMENT_POS_Y = 50;
38
    private static final int PAYMENT_LINE_HEIGHT = 60;
39
 
18 ilm 40
    private CaisseControler controller;
41
    private String calculatorValue = "";
142 ilm 42
    int calcHeight = 5 * 68;
43
    int calcWidth = 4 * 69;
44
    int BUTTON_SIZE = 64;
18 ilm 45
    /**
46
     * Mode '+' ajout d'une quantité '*' multiplication '-' soustraction ' ' remplacement
132 ilm 47
     */
18 ilm 48
    private char mode = ' ';
49
    private boolean init = true;
177 ilm 50
    private CaissePanel caissePanel;
18 ilm 51
 
177 ilm 52
    public PaiementPanel(CaissePanel caissePanel) {
53
        this.controller = caissePanel.getControler();
18 ilm 54
        this.controller.addCaisseListener(this);
55
        this.controller.addBarcodeListener(this);
177 ilm 56
        this.caissePanel = caissePanel;
18 ilm 57
        this.setOpaque(false);
142 ilm 58
 
18 ilm 59
        this.addMouseListener(this);
60
 
61
        this.setLayout(null);
62
        StatusBar st = new StatusBar();
63
        st.setTitle("Règlement");
64
        st.setLocation(0, 0);
65
        st.setSize(320, (int) st.getPreferredSize().getHeight());
66
 
67
        this.add(st);
68
 
69
    }
70
 
71
    @Override
72
    public void paint(Graphics g) {
174 ilm 73
 
142 ilm 74
        Graphics2D g2 = (Graphics2D) g;
75
        g.setColor(new Color(250, 250, 250));
67 ilm 76
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
77
 
142 ilm 78
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
174 ilm 79
        g.setColor(Color.LIGHT_GRAY);
18 ilm 80
        g.drawLine(0, 0, 0, this.getHeight());
142 ilm 81
        int y = PAYMENT_POS_Y;
174 ilm 82
        for (Paiement p : this.controller.getPaiements()) {
18 ilm 83
            if (p.getType() == Paiement.CB) {
142 ilm 84
                drawMontant(g, "CB", p, 242 - 15, y, true);
18 ilm 85
            } else if (p.getType() == Paiement.CHEQUE) {
142 ilm 86
                drawMontant(g, "Chèque", p, 242 - 15, y, true);
18 ilm 87
            } else if (p.getType() == Paiement.ESPECES) {
142 ilm 88
                drawMontant(g, "Espèces", p, 300 - 45, y, false);
89
            } else if (p.getType() == Paiement.SOLDE) {
90
                drawMontant(g, "Solde", p, 300 - 45, y, false);
18 ilm 91
            }
142 ilm 92
            y += PAYMENT_LINE_HEIGHT;
18 ilm 93
        }
142 ilm 94
 
95
        drawKey(g2, "0", 0, 0, 2, 1, CaissePanel.DARK_BLUE);
96
        drawKey(g2, ".", 2, 0, 1, 1, CaissePanel.DARK_BLUE);
97
 
98
        drawKey(g2, "1", 0, 1, 1, 1, CaissePanel.DARK_BLUE);
99
        drawKey(g2, "2", 1, 1, 1, 1, CaissePanel.DARK_BLUE);
100
        drawKey(g2, "3", 2, 1, 1, 1, CaissePanel.DARK_BLUE);
101
        drawKey(g2, "=", 3, 1, 1, 2, CaissePanel.DARK_BLUE);
102
 
103
        drawKey(g2, "4", 0, 2, 1, 1, CaissePanel.DARK_BLUE);
104
        drawKey(g2, "5", 1, 2, 1, 1, CaissePanel.DARK_BLUE);
105
        drawKey(g2, "6", 2, 2, 1, 1, CaissePanel.DARK_BLUE);
106
 
107
        drawKey(g2, "7", 0, 3, 1, 1, CaissePanel.DARK_BLUE);
108
        drawKey(g2, "8", 1, 3, 1, 1, CaissePanel.DARK_BLUE);
109
        drawKey(g2, "9", 2, 3, 1, 1, CaissePanel.DARK_BLUE);
110
        drawKey(g2, "+", 3, 3, 1, 2, CaissePanel.DARK_BLUE);
111
 
112
        drawKey(g2, "C", 0, 4, 2, 1, CaissePanel.LIGHT_BLUE);
113
        drawKey(g2, "x", 2, 4, 1, 1, CaissePanel.DARK_BLUE);
114
        drawKey(g2, "-", 3, 4, 1, 1, CaissePanel.DARK_BLUE);
115
 
18 ilm 116
        drawCalculator(g);
117
        super.paint(g);
174 ilm 118
 
18 ilm 119
    }
120
 
142 ilm 121
    private void drawKey(Graphics2D g2, String string, int col, int row, int w, int h, Color color) {
122
        // background
123
        g2.setColor(color);
124
        g2.fillRect(3 + col * 69, this.getHeight() - (68 * (row + 1)) + 2, 69 * w - 5, 68 * h - 4);
125
        // label
126
        g2.setColor(Color.WHITE);
127
        g2.setFont(g2.getFont().deriveFont(32f));
128
        final int width2 = (int) g2.getFontMetrics().getStringBounds(string, g2).getWidth();
129
        int x = -width2 / 2 + (69) / 2 + col * 69;
130
        int y = this.getHeight() - (row * 68 + 20);
18 ilm 131
 
142 ilm 132
        g2.drawString(string, x, y);
18 ilm 133
    }
134
 
142 ilm 135
    public int getLCDY() {
136
        return this.getHeight() - this.calcHeight - 66;
137
    }
138
 
139
    public int getLCDHeight() {
140
        return 64;
141
    }
142
 
18 ilm 143
    private void drawCalculator(Graphics g) {
144
        Graphics2D g2 = (Graphics2D) g;
67 ilm 145
 
142 ilm 146
        // LCD
174 ilm 147
        if (this.controller.getArticleSelected() != null || this.controller.getPaiementSelected() != null) {
142 ilm 148
            g.setColor(new Color(232, 242, 254));
149
        } else {
150
            g.setColor(new Color(240, 240, 240));
151
        }
152
        g.fillRect(3, getLCDY(), this.getWidth() - 5, getLCDHeight());
153
        //
154
        int y = this.getHeight() - this.calcHeight - 10;
18 ilm 155
        g.setFont(new Font("Arial", Font.PLAIN, 32));
156
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
174 ilm 157
        final Article article = this.controller.getArticleSelected();
18 ilm 158
        g.setColor(Color.DARK_GRAY);
159
        if (article != null) {
174 ilm 160
            String string = this.calculatorValue;
18 ilm 161
            g.setFont(g.getFont().deriveFont(52f));
162
            Rectangle2D r1 = g.getFontMetrics().getStringBounds(string, g2);
142 ilm 163
            g.drawString(string, (int) (260 - r1.getWidth()), y);
18 ilm 164
            g.setFont(g.getFont().deriveFont(14f));
67 ilm 165
            g.drawString("Quantité", 10, 460 + y);
18 ilm 166
 
167
        } else {
174 ilm 168
            final Paiement paiement = this.controller.getPaiementSelected();
18 ilm 169
            if (paiement != null) {
174 ilm 170
                String string = this.calculatorValue;
18 ilm 171
                g.setFont(g.getFont().deriveFont(52f));
172
                Rectangle2D r1 = g.getFontMetrics().getStringBounds(string, g2);
142 ilm 173
                g.drawString(string, (int) (260 - r1.getWidth()), y);
18 ilm 174
                g.setFont(g.getFont().deriveFont(14f));
175
                String str = "Paiement ";
176
                if (paiement.getType() == Paiement.CB) {
177
                    str += " CB";
178
                } else if (paiement.getType() == Paiement.ESPECES) {
179
                    str += " en espèces";
180
                } else if (paiement.getType() == Paiement.CHEQUE) {
181
                    str += " par chèque";
142 ilm 182
                } else if (paiement.getType() == Paiement.SOLDE) {
183
                    str += " depuis solde";
18 ilm 184
                }
142 ilm 185
                g.drawString(str, 10, y - 40);
18 ilm 186
            }
187
        }
188
        g.setFont(g.getFont().deriveFont(14f));
174 ilm 189
        g.drawString("" + this.mode, 10, y - 20);
18 ilm 190
    }
191
 
192
    private char getToucheFrom(int x, int y) {
142 ilm 193
        int yy = (this.getHeight() - y) / 68;
194
        int xx = x / 69;
18 ilm 195
        switch (yy) {
196
        case 0:
197
            if (xx == 0) {
198
                return '0';
199
            } else if (xx == 1) {
200
                return '0';
201
            } else if (xx == 2) {
202
                return '.';
203
            } else if (xx == 3) {
204
                return '=';
205
            } else {
206
                break;
207
            }
208
        case 1:
209
            if (xx == 0) {
210
                return '1';
211
            } else if (xx == 1) {
212
                return '2';
213
            } else if (xx == 2) {
214
                return '3';
215
            } else if (xx == 3) {
216
                return '=';
217
            } else {
218
                break;
219
            }
220
        case 2:
221
            if (xx == 0) {
222
                return '4';
223
            } else if (xx == 1) {
224
                return '5';
225
            } else if (xx == 2) {
226
                return '6';
227
            } else if (xx == 3) {
228
                return '+';
229
            } else {
230
                break;
231
            }
232
        case 3:
233
            if (xx == 0) {
234
                return '7';
235
            } else if (xx == 1) {
236
                return '8';
237
            } else if (xx == 2) {
238
                return '9';
239
            } else if (xx == 3) {
240
                return '+';
241
            } else {
242
                break;
243
            }
244
        case 4:
245
            if (xx == 0) {
246
                return 'c';
247
            } else if (xx == 1) {
248
                return 'c';
249
            } else if (xx == 2) {
250
                return '*';
251
            } else if (xx == 3) {
252
                return '-';
253
            } else {
254
                break;
255
            }
256
 
257
        }
258
        return '?';
259
    }
260
 
142 ilm 261
    private void drawMontant(Graphics g, String label, Paiement p, int x, int y, boolean showAdd) {
18 ilm 262
        y = y + 36;
263
        Graphics2D g2 = (Graphics2D) g;
142 ilm 264
 
18 ilm 265
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
151 ilm 266
        int cents = p.getCents();
267
        int euros = p.getEuros();
142 ilm 268
        // Background
269
        g.setColor(new Color(240, 240, 240));
270
        g.fillRect(3, y - 36, this.getWidth() - 5, 44);
271
 
272
        g.setColor(CaissePanel.DARK_BLUE);
273
 
274
        g.fillRect(3, y - 36, 95, 44);
275
 
276
        if (showAdd) {
277
            g.setColor(CaissePanel.DARK_BLUE);
278
            g.fillRect(this.getWidth() - 46, y - 36, 44, 44);
279
        }
280
        // Label
281
        g.setFont(g.getFont().deriveFont(20f));
282
        g.setFont(g.getFont().deriveFont(Font.BOLD));
283
 
284
        g.setColor(Color.WHITE);
285
        g.drawString(label, 10, y - 8);
286
        if (showAdd) {
287
            g.drawString("+", this.getWidth() - 32, y - 8);
288
        }
289
        // Cents
290
        g.setColor(Color.GRAY);
18 ilm 291
        String sCents = String.valueOf(cents);
292
        if (sCents.length() < 2) {
293
            sCents = "0" + sCents;
294
        }
295
        g.setFont(getFont().deriveFont(18f));
296
        Rectangle2D r1 = g.getFontMetrics().getStringBounds(sCents, g2);
297
        g.drawString(sCents, (int) (x - r1.getWidth()), y);
142 ilm 298
        // Euros
18 ilm 299
        g.setFont(g.getFont().deriveFont(36f));
300
        g.setFont(g.getFont().deriveFont(Font.BOLD));
142 ilm 301
        g.setColor(Color.BLACK);
18 ilm 302
        String sEuros = String.valueOf(euros) + ".";
303
        Rectangle2D r2 = g.getFontMetrics().getStringBounds(sEuros, g2);
304
        g.drawString(sEuros, (int) (x - r1.getWidth() - r2.getWidth()), y);
305
    }
306
 
307
    @Override
308
    public Dimension getPreferredSize() {
174 ilm 309
        return new Dimension(this.calcWidth, 768);
18 ilm 310
    }
311
 
312
    public Dimension getMinimumSize() {
174 ilm 313
        return new Dimension(this.calcWidth, 768);
18 ilm 314
    }
315
 
316
    @Override
317
    public void caisseStateChanged() {
174 ilm 318
        if (this.controller.getArticleSelected() != null) {
18 ilm 319
            initCaisseArticle();
174 ilm 320
        } else if (this.controller.getPaiementSelected() != null) {
18 ilm 321
            initCaissePaiement();
322
        }
142 ilm 323
        // Add / Remove solde if needed
324
        boolean soldeIsShown = false;
174 ilm 325
        for (Paiement p : this.controller.getPaiements()) {
142 ilm 326
            if (p.getType() == Paiement.SOLDE) {
327
                soldeIsShown = true;
328
                break;
329
            }
330
        }
18 ilm 331
 
174 ilm 332
        if (this.controller.isClientDefined()) {
333
            if (!soldeIsShown && this.controller.getClient().getSolde().signum() == 1) {
142 ilm 334
                // add
174 ilm 335
                this.controller.addPaiement(new Paiement(Paiement.SOLDE));
142 ilm 336
            }
337
        } else {
338
            if (soldeIsShown) {
339
                // remove
174 ilm 340
                final List<Paiement> paiements = this.controller.getPaiements();
142 ilm 341
                for (int i = 0; i < paiements.size(); i++) {
342
                    final Paiement p = paiements.get(i);
343
                    if (p.getType() == Paiement.SOLDE) {
174 ilm 344
                        this.controller.getPaiements().remove(i);
142 ilm 345
                        break;
346
                    }
347
                }
348
            }
349
        }
18 ilm 350
        repaint();
351
 
352
    }
353
 
354
    private void initCaisseArticle() {
174 ilm 355
        if (this.controller.getTicketItemSelected() != null) {
356
            this.calculatorValue = this.controller.getTicketItemSelected().getQty().toPlainString();
357
        } else {
358
            this.calculatorValue = "";
359
        }
360
        this.init = true;
361
        this.mode = ' ';
18 ilm 362
    }
363
 
364
    private void initCaissePaiement() {
174 ilm 365
        this.calculatorValue = TicketCellRenderer.centsToString(this.controller.getPaiementSelected().getMontantInCents());
366
        this.init = true;
367
        this.mode = ' ';
18 ilm 368
    }
369
 
370
    @Override
371
    public void mouseClicked(MouseEvent e) {
142 ilm 372
        // Nothing to do here
18 ilm 373
    }
374
 
375
    @Override
376
    public void mouseEntered(MouseEvent e) {
142 ilm 377
        // Nothing to do here
18 ilm 378
    }
379
 
380
    @Override
381
    public void mouseExited(MouseEvent e) {
142 ilm 382
        // Nothing to do here
18 ilm 383
    }
384
 
385
    @Override
386
    public void mousePressed(MouseEvent e) {
142 ilm 387
        if (e.getY() > getLCDY() && e.getY() < (getLCDY() + getLCDHeight())) {
388
            lcdPressed();
389
            return;
390
        }
391
 
18 ilm 392
        char c = getToucheFrom(e.getX(), e.getY());
393
        if (c != '?') {
394
            handleCharacter(c);
395
        } else {
396
            Paiement p = getPaiementFrom(e.getY());
397
            if (p != null) {
174 ilm 398
                if (e.getX() > this.getWidth() - 68 && p.getType() != Paiement.ESPECES && this.controller.canAddPaiement(p.getType())) {
18 ilm 399
                    p = new Paiement(p.getType());
174 ilm 400
                    this.controller.addPaiement(p);
18 ilm 401
                }
174 ilm 402
                this.controller.autoFillPaiement(p);
18 ilm 403
                this.calculatorValue = TicketCellRenderer.centsToString(p.getMontantInCents());
149 ilm 404
                if (p.getType() == Paiement.ESPECES) {
405
                    try {
174 ilm 406
                        this.controller.openDrawer();
149 ilm 407
                    } catch (Throwable ex) {
408
                        JOptionPane.showMessageDialog(PaiementPanel.this, "Ouverture du tiroir caisse impossible");
409
                    }
410
                } else if (p.getType() == Paiement.CB) {
174 ilm 411
                    this.controller.sendCBRequest(p);
18 ilm 412
                }
132 ilm 413
 
18 ilm 414
            }
174 ilm 415
            this.controller.setPaiementSelected(p);
18 ilm 416
        }
417
    }
418
 
142 ilm 419
    public void lcdPressed() {
420
        System.err.println("PaiementPanel.lcdPressed()");
174 ilm 421
        final TicketItem articleSelected = this.controller.getTicketItemSelected();
142 ilm 422
        if (articleSelected != null) {
174 ilm 423
            this.controller.openPriceEditor(articleSelected);
142 ilm 424
        }
425
        repaint();
426
 
427
    }
428
 
18 ilm 429
    private void handleCharacter(char c) {
430
        System.out.println("Handle: " + c);
431
        if (c == '?')
432
            return;
174 ilm 433
        final TicketItem article = this.controller.getTicketItemSelected();
18 ilm 434
 
435
        if (c == '+' || c == '-' || c == '*') {
174 ilm 436
            this.mode = c;
18 ilm 437
 
438
            repaint();
439
            return;
440
        }
441
 
442
        if (article != null) {
443
            // Changement de quantité
444
            if (c == 'c' || c == '/') {
445
                System.out.println("Clear quantité");
174 ilm 446
                this.mode = ' ';
447
                this.controller.removeTicketItem(article);
18 ilm 448
            } else if (c == '=' || c == '\n') {
174 ilm 449
                if (!this.init) {
450
                    BigDecimal v = new BigDecimal(this.calculatorValue);
451
                    if (this.mode == ' ') {
452
                        article.setQty(v);
453
                    } else if (this.mode == '+') {
454
                        article.setQty(article.getQty().add(v));
455
                    } else if (this.mode == '-') {
456
                        article.setQty(article.getQty().subtract(v));
457
                    } else if (this.mode == '*') {
458
                        article.setQty(article.getQty().multiply(v));
18 ilm 459
                    }
174 ilm 460
                    // Reselect to fire a refresh
461
                    this.controller.setTicketItemSelected(article);
18 ilm 462
                }
463
                initCaisseArticle();
464
            } else if (Character.isDigit(c)) {
174 ilm 465
                if (this.init) {
466
                    this.calculatorValue = "";
467
                    this.init = false;
18 ilm 468
                }
174 ilm 469
                if (this.calculatorValue.length() < 8) {
470
                    this.calculatorValue += c;
18 ilm 471
                }
472
            }
174 ilm 473
            if (article.getArticle().getSalesUnit() != null && c == '.' && (this.calculatorValue.indexOf('.') < 0)) {
474
                this.calculatorValue += ".";
475
            }
18 ilm 476
 
477
        } else {
174 ilm 478
            final Paiement paiement = this.controller.getPaiementSelected();
18 ilm 479
            if (paiement != null) {
480
                // Changement de paiement
481
                if (c == 'c' || c == '/') {
482
                    System.out.println("Clear paiement");
174 ilm 483
                    this.mode = ' ';
484
                    this.controller.clearPaiement(paiement);
485
                } else if (c == '.' && (this.calculatorValue.indexOf('.') < 0)) {
486
                    this.calculatorValue += ".";
18 ilm 487
                } else if (c == '=' || c == '\n') {
174 ilm 488
                    if (!this.init) {
18 ilm 489
                        int v = getCentsFrom(this.calculatorValue);
174 ilm 490
                        if (this.mode == ' ') {
491
                            this.controller.setPaiementValue(paiement, v);
492
                        } else if (this.mode == '+') {
493
                            this.controller.setPaiementValue(paiement, paiement.getMontantInCents() + v);
494
                        } else if (this.mode == '-') {
495
                            this.controller.setPaiementValue(paiement, paiement.getMontantInCents() - v);
496
                        } else if (this.mode == '*') {
497
                            this.controller.setPaiementValue(paiement, paiement.getMontantInCents() * v);
18 ilm 498
                        }
499
                    }
500
                    initCaissePaiement();
174 ilm 501
                    this.controller.setPaiementSelected(null);
18 ilm 502
                } else if (Character.isDigit(c)) {
174 ilm 503
                    if (this.init) {
504
                        this.calculatorValue = "";
505
                        this.init = false;
18 ilm 506
                    }
174 ilm 507
                    if (this.calculatorValue.length() < 9) {
508
                        int i = this.calculatorValue.indexOf('.');
509
                        if (i < 0 || (this.calculatorValue.length() - i < 3)) {
510
                            this.calculatorValue += c;
142 ilm 511
                        }
18 ilm 512
                    }
513
                }
514
            }
515
        }
516
        repaint();
517
    }
518
 
519
    private int getCentsFrom(String str) {
520
        int i = str.indexOf('.');
521
        if (i >= 0) {
522
            String euros = str.substring(0, i);
523
            String cents = str.substring(i + 1);
524
            if (cents.length() == 1) {
525
                cents += "0";
526
            }
527
            int e = 0;
528
            if (euros.length() > 0) {
529
                e = Integer.parseInt(euros);
530
            }
531
            int c = 0;
532
            if (cents.length() > 0) {
533
                c = Integer.parseInt(cents);
534
            }
535
            return e * 100 + c;
536
        }
537
        return Integer.parseInt(str) * 100;
538
 
539
    }
540
 
541
    @Override
542
    public void mouseReleased(MouseEvent e) {
142 ilm 543
        // Nothing to do here
18 ilm 544
    }
545
 
546
    @Override
547
    public void barcodeRead(String code) {
142 ilm 548
        // Nothing to do here
18 ilm 549
    }
550
 
551
    private Paiement getPaiementFrom(int y) {
142 ilm 552
        int index = (y - PAYMENT_POS_Y) / PAYMENT_LINE_HEIGHT;
174 ilm 553
        if (index < this.controller.getPaiements().size() && index >= 0) {
554
            return this.controller.getPaiements().get(index);
18 ilm 555
        }
556
        return null;
557
    }
558
 
559
    @Override
560
    public void keyReceived(KeyEvent e) {
177 ilm 561
        if (!this.caissePanel.isModeSearch() && e.getID() == KeyEvent.KEY_TYPED) {
18 ilm 562
            System.out.println("PaiementPanel.keyPressed()" + e.getKeyChar());
563
            handleCharacter(e.getKeyChar());
564
        }
565
 
566
    }
567
 
568
}