Example #1
0
class SuggestionsDelegate(QStyledItemDelegate):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._doc = QTextDocument()
        self._translation_char_format = QTextCharFormat()
        self._strokes_char_format = QTextCharFormat()
        self._strokes_char_format.font().setStyleHint(QFont.Monospace)

    @property
    def text_font(self):
        return self._translation_char_format.font()

    @text_font.setter
    def text_font(self, font):
        self._translation_char_format.setFont(font)

    @property
    def strokes_font(self):
        return self._strokes_char_format.font()

    @strokes_font.setter
    def strokes_font(self, font):
        self._strokes_char_format.setFont(font)

    def _format_suggestion(self, index):
        suggestion = index.data(Qt.DisplayRole)
        self._doc.clear()
        cursor = QTextCursor(self._doc)
        cursor.setCharFormat(self._translation_char_format)
        cursor.insertText(escape_translation(suggestion.text) + ':')
        if not suggestion.steno_list:
            cursor.insertText(' ' + NO_SUGGESTIONS_STRING)
            return
        for strokes_list in suggestion.steno_list[:MAX_SUGGESTIONS_COUNT]:
            cursor.insertBlock()
            cursor.setCharFormat(self._strokes_char_format)
            cursor.insertText('   ' + '/'.join(strokes_list))

    def paint(self, painter, option, index):
        painter.save()
        if option.state & QStyle.State_Selected:
            painter.fillRect(option.rect, option.palette.highlight())
            text_color = option.palette.highlightedText()
        else:
            text_color = option.palette.text()
        self._translation_char_format.setForeground(text_color)
        self._strokes_char_format.setForeground(text_color)
        painter.translate(option.rect.topLeft())
        self._format_suggestion(index)
        self._doc.drawContents(painter)
        painter.restore()

    def sizeHint(self, option, index):
        self._format_suggestion(index)
        return self._doc.size().toSize()
Example #2
0
class widget1(QWidget):
#widget

    def __init__(self,  parent=None):
        super(widget1, self).__init__(parent)

        self.initUI()

    def initUI(self):
    #----------------------Widgets-----------------------------
        
        #Objeto document
        self.document=QTextDocument()

        #Qpusbutton
        button_data=QPushButton("Mostrar datos", self)
        button1=QPushButton("Vista Previa", self)
        button2=QPushButton("Imprimir", self)
        button3=QPushButton("Exportar", self)
        button4=QPushButton("Limpiar", self)

        #-------Objeto: QTreWidget-------------------
        self.table_user=QTreeWidget()
        self.table_user.setHeaderLabels(("Id_Usuario", "Mes", "Nombre", "Estatus", "Fecha de alta"))
        
        #Formato
        self.model=self.table_user.model()

        for indice, ancho in enumerate((110, 150, 150, 160), start=0):
                self.model.setHeaderData(indice, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
                self.table_user.setColumnWidth(indice, ancho)

        self.table_user.setAlternatingRowColors(True)


        #----------Objeto Layout vertical para QPushButton--------
        horizontal_layout=QHBoxLayout()
        horizontal_layout.addWidget(button_data)
        horizontal_layout.addWidget(button1)
        horizontal_layout.addWidget(button2)
        horizontal_layout.addWidget(button3)
        horizontal_layout.addWidget(button4)
        horizontal_layout.addStretch()

        #---------Objeto - Layout-----------------
        gridLayout1=QGridLayout()
        #Agregar al gridlayout1
        gridLayout1.addLayout(horizontal_layout, 0, 1, 1, 1)
        gridLayout1.addWidget(self.table_user,   1, 1, 1, 1)#widget 

        #Asignar al layout clase widget
        self.setLayout(gridLayout1)

        #--------------Eventos qpushbutton----------------------------------------
        button_data.clicked.connect(self.data)          #data
        button1.clicked.connect(self.view)              #var_view previa
        button2.clicked.connect(self.print_document)    #imprimir
        button3.clicked.connect(self.pdf_export)        #exportar
        button4.clicked.connect(self.clear)             #limpiar
        

    def clear(self):
    #Limpiar tabla/documento
        
        self.table_user.clear()
        self.document.clear()


    def data (self):
    #Mostrar datos y objeto document

        data = [("1", "March", "Arnt", "Disabled", "10/23/2010"),
            ("2", "April", "Louis", "Enabled", "09/05/2020"),
            ("3", "June", "Steve", "Disabled", "02/15/2001"),
            ("4", "October", "Marcus", "Enabled", "01/13/2002"),
            ("5", "December", "John", "Enabled", "12/28/2018"),
        
                ]

        #Limpiar tabla/documento
        self.table_user.clear()
        self.document.clear()


        html_dato =''
        item_widget=[]

        for d in data:
        #Imprimir datos en la tabla
            
            self.table_user.insertTopLevelItems(0,[QTreeWidgetItem(self.table_user, d)])    

            html_dato += "<tr> <td>%s</td> <td>%s</td> <td>%s</td> <td>%s</td>  <td>%s</td> </tr>" %d
            item_widget.append(QTreeWidgetItem((str(d[0]), d[1], d[2], d[3], d[3])))

        

        html="""
        <!DOCTYPE html>
        <html>
        <head>
        <meta charset="UTF-8">
        <style>
        h3 {
            font-family: Helvetica-Bold;
            text-align: center;
        }
        table {
            font-family: arial, sans-serif;
            border-collapse: collapse;
            width: 100%;
            }
        td {
            text-align: left;
            padding-top: 4px;
            padding-right: 6px;
            padding-bottom: 2px;
            padding-left: 6px;
        }
        th {
            text-align: left;
            padding: 4px;
            background-color: black;
            color: white;
        }
        tr:nth-child(even) {
                            background-color: #dddddd;
                        }
        </style>
        </head>
        <body>
        <h3>LISTADO DE USUARIOS<br/></h3>
        <table align="left" width="100%" cellspacing="0">
        <tr>
            <th>Id_Usuario</th>
            <th>Mes</th>
            <th>Nombre</th>
            <th>Estatus</th>
            <th>Fecha de alta</th>
        </tr>
        [DATA]
        </table>
        </body>
        </html>
        """.replace("[DATA]", html_dato)


        qbyte = QByteArray()
        qbyte.append(str(html))
        #Ajuste
        codec = QTextCodec.codecForHtml(qbyte)
        unistr = codec.toUnicode(qbyte)

        if Qt.mightBeRichText(unistr):
            self.document.setHtml(unistr)
        else:
            self.document.setPlainText(unistr)

    def view(self):
    #Vista previa

        if not self.document.isEmpty():

            impres = QPrinter(QPrinter.HighResolution)
                
            var_view = QPrintPreviewDialog(impres, self)
            var_view.setWindowTitle("Vista previa")
            var_view.setWindowFlags(Qt.Window)
            var_view.resize(800, 600)

            exportarPDF = var_view.findChildren(QToolBar)
            exportarPDF[0].addAction(QIcon("logo.png"), "Exportar a PDF", self.pdf_export)
                
            var_view.paintRequested.connect(self.visualizar) 
            var_view.exec_()
        
        else:
            QMessageBox.critical(self, "Atención", "No hay datos en la tabla ",
                                 QMessageBox.Ok)

    def visualizar(self, imp):

        self.document.print_(imp)

    
    def pdf_export(self):

        if not self.document.isEmpty():
            file1, _ = QFileDialog.getSaveFileName(self, "Exportar a PDF", "file",
                                                           "Archivos PDF (*.pdf);;All Files (*)",
                                                           options=QFileDialog.Options())

            if file1:
                
                impres = QPrinter(QPrinter.HighResolution)
                impres.setOutputFormat(QPrinter.PdfFormat)
                impres.setOutputFileName(file1)
                
                self.document.print_(impres)

                QMessageBox.information(self, "Finalizado", "Se exportó correctamente el archivo",
                                        QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Atención", "No hay datos en la tabla",
                                 QMessageBox.Ok)

    def print_document(self):

        if not self.document.isEmpty():
            impres = QPrinter(QPrinter.HighResolution)
            
            dlg = QPrintDialog(impres, self)
            dlg.setWindowTitle("Imprimir documento")

            if dlg.exec_() == QPrintDialog.Accepted:
                self.document.print_(impres)

            del dlg
        else:
            QMessageBox.critical(self, "Atención", "No hay datos en la tabla",
                                 QMessageBox.Ok)
Example #3
0
class visualizarImprimirExportar(QDialog):
    def __init__(self, parent=None):
        super(visualizarImprimirExportar, self).__init__()

        self.setWindowTitle(
            "Visualizar, imprimir y exportar datos a PDF con PyQt5")
        self.setWindowIcon(QIcon("Qt.png"))
        self.setWindowFlags(Qt.WindowCloseButtonHint
                            | Qt.MSWindowsFixedSizeDialogHint)
        self.setFixedSize(612, 408)

        self.initUI()

    def initUI(self):
        self.documento = QTextDocument()

        # =================== WIDGETS QPUSHBUTTON ==================

        buttonBuscar = QPushButton("Buscar usuarios", self)
        buttonBuscar.setFixedSize(426, 26)
        buttonBuscar.move(20, 20)

        buttonLimpiar = QPushButton("Limpiar tabla", self)
        buttonLimpiar.setFixedSize(140, 26)
        buttonLimpiar.move(452, 20)

        # =================== WIDGET QTREEWIDGET ===================

        self.treeWidgetUsuarios = QTreeWidget(self)

        self.treeWidgetUsuarios.setFont(
            QFont(self.treeWidgetUsuarios.font().family(), 10, False))
        self.treeWidgetUsuarios.setRootIsDecorated(False)
        self.treeWidgetUsuarios.setHeaderLabels(
            ("D.N.I", "NOMBRE", "APELLIDO", "CORREO"))

        self.model = self.treeWidgetUsuarios.model()

        for indice, ancho in enumerate((110, 150, 150, 160), start=0):
            self.model.setHeaderData(indice, Qt.Horizontal, Qt.AlignCenter,
                                     Qt.TextAlignmentRole)
            self.treeWidgetUsuarios.setColumnWidth(indice, ancho)

        self.treeWidgetUsuarios.setAlternatingRowColors(True)

        self.treeWidgetUsuarios.setFixedSize(572, 300)
        self.treeWidgetUsuarios.move(20, 56)

        # =================== WIDGETS QPUSHBUTTON ==================

        buttonVistaPrevia = QPushButton("Vista previa", self)
        buttonVistaPrevia.setFixedSize(140, 26)
        buttonVistaPrevia.move(156, 364)

        buttonImprimir = QPushButton("Imprimir", self)
        buttonImprimir.setFixedSize(140, 26)
        buttonImprimir.move(304, 364)

        buttonExportarPDF = QPushButton("Exportar a PDF", self)
        buttonExportarPDF.setFixedSize(140, 26)
        buttonExportarPDF.move(452, 364)

        # =================== EVENTOS QPUSHBUTTON ==================

        buttonBuscar.clicked.connect(self.Buscar)
        buttonLimpiar.clicked.connect(self.limpiarTabla)

        buttonVistaPrevia.clicked.connect(self.vistaPrevia)
        buttonImprimir.clicked.connect(self.Imprimir)
        buttonExportarPDF.clicked.connect(self.exportarPDF)

# ======================= FUNCIONES ============================

    def Buscar(self):
        conexionDB = connect("Data/db_favan.db")
        cursor = conexionDB.cursor()

        cursor.execute(
            "SELECT ID_CLIENTE, NOM_CLIENTE, APE_CLIENTE, COR_CLIENTE FROM CLIENTE"
        )
        datosDB = cursor.fetchall()

        conexionDB.close()

        if datosDB:
            self.documento.clear()
            self.treeWidgetUsuarios.clear()

            datos = ""
            item_widget = []
            for dato in datosDB:
                datos += "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>" % dato
                item_widget.append(
                    QTreeWidgetItem((str(dato[0]), dato[1], dato[2], dato[3])))

            reporteHtml = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
h3 {
    font-family: Helvetica-Bold;
    text-align: center;
   }
table {
       font-family: arial, sans-serif;
       border-collapse: collapse;
       width: 100%;
      }
td {
    text-align: left;
    padding-top: 4px;
    padding-right: 6px;
    padding-bottom: 2px;
    padding-left: 6px;
   }
th {
    text-align: left;
    padding: 4px;
    background-color: purple;
    color: white;
   }
tr:nth-child(even) {
                    background-color: #dddddd;
                   }
</style>
</head>
<body>
<h3>LISTADO DE USUARIOS<br/></h3>
<table align="left" width="100%" cellspacing="0">
  <tr>
    <th>D.N.I</th>
    <th>NOMBRE</th>
    <th>APELLIDO</th>
    <th>FECHA DE NACIMIENTO</th>
  </tr>
  [DATOS]
</table>
</body>
</html>
""".replace("[DATOS]", datos)

            datos = QByteArray()
            datos.append(str(reporteHtml))
            codec = QTextCodec.codecForHtml(datos)
            unistr = codec.toUnicode(datos)

            if Qt.mightBeRichText(unistr):
                self.documento.setHtml(unistr)
            else:
                self.documento.setPlainText(unistr)

            self.treeWidgetUsuarios.addTopLevelItems(item_widget)
        else:
            QMessageBox.information(self, "Buscar usuarios",
                                    "No se encontraron resultados.      ",
                                    QMessageBox.Ok)

    def limpiarTabla(self):
        self.documento.clear()
        self.treeWidgetUsuarios.clear()

    def vistaPrevia(self):
        if not self.documento.isEmpty():
            impresion = QPrinter(QPrinter.HighResolution)

            vista = QPrintPreviewDialog(impresion, self)
            vista.setWindowTitle("Vista previa")
            vista.setWindowFlags(Qt.Window)
            vista.resize(800, 600)

            exportarPDF = vista.findChildren(QToolBar)
            exportarPDF[0].addAction(QIcon("exportarPDF.png"),
                                     "Exportar a PDF", self.exportarPDF)

            vista.paintRequested.connect(self.vistaPreviaImpresion)
            vista.exec_()
        else:
            QMessageBox.critical(self, "Vista previa",
                                 "No hay datos para visualizar.   ",
                                 QMessageBox.Ok)

    def vistaPreviaImpresion(self, impresion):
        self.documento.print_(impresion)

    def Imprimir(self):
        if not self.documento.isEmpty():
            impresion = QPrinter(QPrinter.HighResolution)

            dlg = QPrintDialog(impresion, self)
            dlg.setWindowTitle("Imprimir documento")

            if dlg.exec_() == QPrintDialog.Accepted:
                self.documento.print_(impresion)

            del dlg
        else:
            QMessageBox.critical(self, "Imprimir",
                                 "No hay datos para imprimir.   ",
                                 QMessageBox.Ok)

    def exportarPDF(self):
        if not self.documento.isEmpty():
            nombreArchivo, _ = QFileDialog.getSaveFileName(
                self,
                "Exportar a PDF",
                "Listado de usuarios",
                "Archivos PDF (*.pdf);;All Files (*)",
                options=QFileDialog.Options())

            if nombreArchivo:
                # if QFileInfo(nombreArchivo).suffix():
                #     nombreArchivo += ".pdf"

                impresion = QPrinter(QPrinter.HighResolution)
                impresion.setOutputFormat(QPrinter.PdfFormat)
                impresion.setOutputFileName(nombreArchivo)
                self.documento.print_(impresion)

                QMessageBox.information(self, "Exportar a PDF",
                                        "Datos exportados con éxito.   ",
                                        QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Exportar a PDF",
                                 "No hay datos para exportar.   ",
                                 QMessageBox.Ok)
Example #4
0
class visualizarImprimirExportar(QDialog):
    def __init__(self, parent=None):
        super(visualizarImprimirExportar, self).__init__()

        self.setWindowTitle("Просмотр, печать и экспорт данных в PDF")
        self.setWindowIcon(QIcon("Qt.png"))
        self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.MSWindowsFixedSizeDialogHint)
        self.setFixedSize(612, 408)

        self.initUI()

    def initUI(self):
        self.documento = QTextDocument()

        buttonBuscar = QPushButton("Найти пользователей", self)
        buttonBuscar.setFixedSize(426, 26)
        buttonBuscar.move(20, 20)

        buttonLimpiar = QPushButton("Очистить", self)
        buttonLimpiar.setFixedSize(140, 26)
        buttonLimpiar.move(452, 20)

        self.treeWidgetUsuarios = QTreeWidget(self)

        self.treeWidgetUsuarios.setFont(QFont(self.treeWidgetUsuarios.font().family(), 10, False))
        self.treeWidgetUsuarios.setRootIsDecorated(False)
        self.treeWidgetUsuarios.setHeaderLabels(("Id", "Имя", "Фамилия", "Пол", "Дата рождения", "Страна",
                                                 "Телефон"))

        self.model = self.treeWidgetUsuarios.model()

        for indice, ancho in enumerate((110, 150, 150, 160), start=0):
            self.model.setHeaderData(indice, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
            self.treeWidgetUsuarios.setColumnWidth(indice, ancho)

        self.treeWidgetUsuarios.setAlternatingRowColors(True)

        self.treeWidgetUsuarios.setFixedSize(572, 300)
        self.treeWidgetUsuarios.move(20, 56)

        buttonVistaPrevia = QPushButton("предварительный просмотр", self)
        buttonVistaPrevia.setFixedSize(180, 26)
        buttonVistaPrevia.move(116, 364)

        buttonImprimir = QPushButton("печать", self)
        buttonImprimir.setFixedSize(140, 26)
        buttonImprimir.move(304, 364)

        buttonExportarPDF = QPushButton("Экспорт в PDF", self)
        buttonExportarPDF.setFixedSize(140, 26)
        buttonExportarPDF.move(452, 364)

        buttonBuscar.clicked.connect(self.Buscar)
        buttonLimpiar.clicked.connect(self.limpiarTabla)

        buttonVistaPrevia.clicked.connect(self.vistaPrevia)
        buttonImprimir.clicked.connect(self.Imprimir)
        buttonExportarPDF.clicked.connect(self.exportarPDF)

    def Buscar(self):
        conexionDB = connect("DB_SIACLE/DB_SIACLE.db")
        cursor = conexionDB.cursor()

        cursor.execute("SELECT NOMBRE, APELLIDO, SEXO, FECHA_NACIMIENTO, PAIS, TELEFONO_CELULAR FROM CLIENTES ")
        datosDB = cursor.fetchall()

        conexionDB.close()

        if datosDB:
            self.documento.clear()
            self.treeWidgetUsuarios.clear()

            datos = ""
            item_widget = []
            for dato in datosDB:
                datos += "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>" % dato
                item_widget.append(QTreeWidgetItem((str(dato[0]), dato[1], dato[2], dato[3], dato[4], dato[5])))

            reporteHtml = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
h3 {
    font-family: Helvetica-Bold;
    text-align: center;
   }

table {
       font-family: arial, sans-serif;
       border-collapse: collapse;
       width: 100%;
      }

td {
    text-align: left;
    padding-top: 4px;
    padding-right: 6px;
    padding-bottom: 2px;
    padding-left: 6px;
   }

th {
    text-align: left;
    padding: 4px;
    background-color: black;
    color: white;
   }

tr:nth-child(even) {
                    background-color: #dddddd;
                   }
</style>
</head>
<body>

<h3>Клиенты<br/></h3>

<table align="left" width="100%" cellspacing="0">
  <tr>
    <th>Имя</th>
    <th>Фамилия</th>
    <th>Пол</th>
    <th>Дата рождения</th>
    <th>Страна</th>
    <th>Телефон</th>
  </tr>
  [DATOS]
</table>

</body>
</html>
""".replace("[DATOS]", datos)

            datos = QByteArray()
            datos.append(str(reporteHtml))
            codec = QTextCodec.codecForHtml(datos)
            unistr = codec.toUnicode(datos)

            if Qt.mightBeRichText(unistr):
                self.documento.setHtml(unistr)
            else:
                self.documento.setPlainText(unistr)

            self.treeWidgetUsuarios.addTopLevelItems(item_widget)
        else:
            QMessageBox.information(self, "Найти пользователей", "Результатов не найдено.      ",
                                    QMessageBox.Ok)

    def limpiarTabla(self):
        self.documento.clear()
        self.treeWidgetUsuarios.clear()

    def vistaPrevia(self):
        if not self.documento.isEmpty():
            impresion = QPrinter(QPrinter.HighResolution)

            vista = QPrintPreviewDialog(impresion, self)
            vista.setWindowTitle("предварительный просмотр")
            vista.setWindowFlags(Qt.Window)
            vista.resize(800, 600)

            exportarPDF = vista.findChildren(QToolBar)
            exportarPDF[0].addAction(QIcon("exportarPDF.png"), "Экспорт в PDF", self.exportarPDF)

            vista.paintRequested.connect(self.vistaPreviaImpresion)
            vista.exec_()
        else:
            QMessageBox.critical(self, "предварительный просмотр", "Нет данных для отображения.   ",
                                 QMessageBox.Ok)

    def vistaPreviaImpresion(self, impresion):
        self.documento.print_(impresion)

    def Imprimir(self):
        if not self.documento.isEmpty():
            impresion = QPrinter(QPrinter.HighResolution)

            dlg = QPrintDialog(impresion, self)
            dlg.setWindowTitle("Распечатать документ")

            if dlg.exec_() == QPrintDialog.Accepted:
                self.documento.print_(impresion)

            del dlg
        else:
            QMessageBox.critical(self, "печать", "Нет данных для печати.   ",
                                 QMessageBox.Ok)

    def exportarPDF(self):
        if not self.documento.isEmpty():
            nombreArchivo, _ = QFileDialog.getSaveFileName(self, "Экспорт в PDF", "Список пользователей ",
                                                           "PDF файлы  (*.doc);;All Files (*)",
                                                           options=QFileDialog.Options())

            if nombreArchivo:
                impresion = QPrinter(QPrinter.HighResolution)
                impresion.setOutputFormat(QPrinter.PdfFormat)
                impresion.setOutputFileName(nombreArchivo)
                self.documento.print_(impresion)

                QMessageBox.information(self, "Экспорт в PDF", "Данные успешно экспортированы.   ",
                                        QMessageBox.Ok)
        else:
            QMessageBox.critical(self, "Экспорт в PDF", "Нет данных для экспорта.   ",
                                 QMessageBox.Ok)
Example #5
0
class TextDocument(DocumentInterface):
    def __init__(self, *args, **kwargs):
        super(TextDocument, self).__init__(*args, **kwargs)

        self._raw_type = 'text'
        self._qtextdoc = QTextDocument(None)

    @property
    def contents(self):
        return self._qtextdoc

    @property
    def raw_type(self):
        return self._raw_type

    @raw_type.setter
    def raw_type(self, value):
        new_value = str(value)
        if new_value not in ('text', 'html'):
            raise ValueError('raw_type must equal \'text\' or \'html\'!')
        self._raw_type = value

    @property
    def raw(self):
        raw_contents = RawContents(text=self._qtextdoc.toPlainText(),
                                   html=self._qtextdoc.toHtml())
        return raw_contents(self._raw_type)

    @staticmethod
    def get_raw_text(text_document):
        def do_get(text_doc, old_rt):
            text_doc.raw_type = 'text'
            rv = text_doc.raw
            text_doc.raw_type = old_rt
            return rv

        # # #
        if text_document is not None and isinstance(text_document,
                                                    TextDocument):
            return do_get(text_document, text_document.raw_type)

        return ''

    @staticmethod
    def get_raw_html(text_document):
        def do_get(text_doc, old_rt):
            text_doc.raw_type = 'html'
            rv = text_doc.raw
            text_doc.raw_type = old_rt
            return rv

        # # #
        if text_document is not None and isinstance(text_document,
                                                    TextDocument):
            return do_get(text_document, text_document.raw_type)

        return ''

    def load_document(self, load_callback):
        return

    def reset_document(self):
        self._qtextdoc.clear()

    def save_document(self, file_obj, format):
        fmt_method = {
            'text': TextDocument.get_raw_text,
            'html': TextDocument.get_raw_html
        }

        try:
            content_method = lambda m=fmt_method[format]: m(self)
            file_obj.write(content_method())
        except KeyError:
            print('Unable to save document. Invalid format.')