Пример #1
0
class TrackWidget(QWidget, Ui_Track):

    def __init__(self, parent=None):
        super(TrackWidget, self).__init__(parent)
        self.setupUi(self)
        self.title = "Display track"
        self.canvas = None
        self.band = None
        self.color_btn = None
        self.center = False
        self.position = None
        self.geom_type = None
        self.marker = None
        self.hidden = False
        self.centerButton.setEnabled(False)
        icon = QIcon(":/resources/mActionSave.svg")
        self.save_track_pushButton.setIcon(icon)
        self.save_track_pushButton.setToolTip("Save Track")
        self.save_track_pushButton.clicked.connect(self.save_track)

    def init(self, title, canvas, default_color, geom_type, marker):
        self.canvas = canvas
        self.geom_type = geom_type
        self.track_groupBox.setTitle(title)
        if marker:
            # Add marker
            self.marker = marker
            self.with_marker = True
        else:
            self.with_marker = False
        # Add rubber band
        self.band = QgsRubberBand(self.canvas, self.geom_type)
        if self.geom_type == QgsWkbTypes.PointGeometry:
            self.band.setIcon(QgsRubberBand.ICON_CIRCLE)
            self.band.setIconSize(12)
        else:
            self.band.setWidth(3)
        # Add color button widget for picking color
        self.color_btn = QgsColorButton()
        self.horizontal_layout_color.insertWidget(1, self.color_btn, 0, Qt.AlignLeft)
        self.color_btn.colorChanged.connect(self.color_changed)
        self.color_btn.setDefaultColor(default_color)
        self.color_btn.setColor(default_color)
        # Set signals
        self.centerButton.clicked.connect(self.center_to_location)
        self.clearTrackButton.clicked.connect(self.clear_track)

    def color_changed(self):
        transparent_color = QColor(self.color_btn.color())
        transparent_color.setAlpha(80)
        self.band.setColor(transparent_color)
        if self.with_marker:
            self.marker.set_color(QColor(self.color_btn.color()))

    def add_position(self, position):
        self.band.addPoint(position)

    def track_update_canvas(self, position, heading):
        self.centerButton.setEnabled(True)
        self.position = position
        self.add_position(position)
        if self.with_marker:
            self.marker.set_center(position, heading)
        if self.isHidden():
            if self.with_marker:
                self.marker.hide()
            self.band.hide()
        else:
            if self.with_marker:
                self.marker.show()
            self.band.show()

    def center_to_location(self):
        """
        Center to last received position on the map.
        """
        rect = QgsRectangle(self.position, self.position)
        self.canvas.setExtent(rect)
        self.canvas.zoomScale(400)
        self.canvas.refresh()

    def hide_band(self):
        self.band.hide()

    def hide_marker(self):
        if self.with_marker:
            self.marker.hide()

    def clear_track(self):
        self.band.reset(self.geom_type)

    def save_track(self):
        """
        Save the track to disk
        """
        layer_name, selected_filter = QFileDialog.getSaveFileName(None, 'Save Track', "",
                                                                  'Shapefile (*.shp);;KML (*.kml);;GPX (*.gpx)')

        if layer_name != '':

            if self.geom_type == QgsWkbTypes.PointGeometry:
                geometric_object = "MultiPoint?crs=epsg:4326"
            else:
                geometric_object = "LineString?crs=epsg:4326"

            layer = QgsVectorLayer(
                geometric_object,
                layer_name,
                "memory")
            feature = QgsFeature()
            feature.setGeometry(self.band.asGeometry())
            layer.dataProvider().addFeatures([feature])

            if selected_filter == "Shapefile (*.shp)":

                if not layer_name.endswith('.shp'):
                    layer_name = layer_name + '.shp'
                ret = QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8",
                                                              QgsCoordinateReferenceSystem(4326,
                                                                                           QgsCoordinateReferenceSystem.EpsgCrsId),
                                                              "ESRI Shapefile")
                if ret == QgsVectorFileWriter.NoError:
                    logger.info(layer.name() + " saved to " + layer_name)

            elif selected_filter == "KML (*.kml)":

                if not layer_name.endswith('.kml'):
                    layer_name = layer_name + '.kml'

                QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8",
                                                        QgsCoordinateReferenceSystem(4326,
                                                                                     QgsCoordinateReferenceSystem.EpsgCrsId),
                                                        "KML")
            elif selected_filter == "GPX (*.gpx)":

                if not layer_name.endswith('.gpx'):
                    layer_name = layer_name + '.gpx'
                ds_options = list()
                ds_options.append("GPX_USE_EXTENSIONS=TRUE")
                QgsVectorFileWriter.writeAsVectorFormat(layer, layer_name, "utf-8",
                                                        QgsCoordinateReferenceSystem(4326,
                                                                                     QgsCoordinateReferenceSystem.EpsgCrsId),
                                                        "GPX",
                                                        datasourceOptions=ds_options)

    def close(self):
        self.hide_band()
        self.hide_marker()
class Ui_Mapmashup(object):
    def setupUi(self, Mapmashup):
        Mapmashup.setObjectName("Mapmashup")
        Mapmashup.resize(327, 427)
        self.verticalLayout = QtWidgets.QVBoxLayout(Mapmashup)
        self.verticalLayout.setObjectName("verticalLayout")
        self.hlImageFolder = QtWidgets.QHBoxLayout()
        self.hlImageFolder.setObjectName("hlImageFolder")
        self.leImageFolder = QtWidgets.QLineEdit(Mapmashup)
        self.leImageFolder.setObjectName("leImageFolder")
        self.hlImageFolder.addWidget(self.leImageFolder)
        self.butBrowseImg = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butBrowseImg.sizePolicy().hasHeightForWidth())
        self.butBrowseImg.setSizePolicy(sizePolicy)
        self.butBrowseImg.setMinimumSize(QtCore.QSize(100, 0))
        self.butBrowseImg.setMaximumSize(QtCore.QSize(100, 16777215))
        self.butBrowseImg.setObjectName("butBrowseImg")
        self.hlImageFolder.addWidget(self.butBrowseImg)
        self.verticalLayout.addLayout(self.hlImageFolder)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        self.leRegistrationFolder = QtWidgets.QLineEdit(Mapmashup)
        self.leRegistrationFolder.setObjectName("leRegistrationFolder")
        self.horizontalLayout_2.addWidget(self.leRegistrationFolder)
        self.butBrowseReg = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.MinimumExpanding,
            QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butBrowseReg.sizePolicy().hasHeightForWidth())
        self.butBrowseReg.setSizePolicy(sizePolicy)
        self.butBrowseReg.setMinimumSize(QtCore.QSize(100, 0))
        self.butBrowseReg.setMaximumSize(QtCore.QSize(100, 16777215))
        self.butBrowseReg.setObjectName("butBrowseReg")
        self.horizontalLayout_2.addWidget(self.butBrowseReg)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.cboRegistrations = QtWidgets.QComboBox(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.cboRegistrations.sizePolicy().hasHeightForWidth())
        self.cboRegistrations.setSizePolicy(sizePolicy)
        self.cboRegistrations.setObjectName("cboRegistrations")
        self.horizontalLayout_5.addWidget(self.cboRegistrations)
        self.butRefresh = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.MinimumExpanding,
            QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butRefresh.sizePolicy().hasHeightForWidth())
        self.butRefresh.setSizePolicy(sizePolicy)
        self.butRefresh.setMinimumSize(QtCore.QSize(100, 0))
        self.butRefresh.setMaximumSize(QtCore.QSize(100, 16777215))
        self.butRefresh.setObjectName("butRefresh")
        self.horizontalLayout_5.addWidget(self.butRefresh)
        self.verticalLayout.addLayout(self.horizontalLayout_5)
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label_2 = QtWidgets.QLabel(Mapmashup)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout.addWidget(self.label_2)
        self.leName = QtWidgets.QLineEdit(Mapmashup)
        self.leName.setObjectName("leName")
        self.horizontalLayout.addWidget(self.leName)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.label = QtWidgets.QLabel(Mapmashup)
        self.label.setObjectName("label")
        self.horizontalLayout_3.addWidget(self.label)
        self.hsTransparency = QtWidgets.QSlider(Mapmashup)
        self.hsTransparency.setOrientation(QtCore.Qt.Horizontal)
        self.hsTransparency.setTickPosition(QtWidgets.QSlider.TicksBelow)
        self.hsTransparency.setTickInterval(10)
        self.hsTransparency.setObjectName("hsTransparency")
        self.horizontalLayout_3.addWidget(self.hsTransparency)
        self.verticalLayout.addLayout(self.horizontalLayout_3)
        self.groupBox = QtWidgets.QGroupBox(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.groupBox.sizePolicy().hasHeightForWidth())
        self.groupBox.setSizePolicy(sizePolicy)
        self.groupBox.setMinimumSize(QtCore.QSize(0, 61))
        self.groupBox.setMaximumSize(QtCore.QSize(3000, 61))
        self.groupBox.setObjectName("groupBox")
        self.cbTransparentColour = QtWidgets.QCheckBox(self.groupBox)
        self.cbTransparentColour.setGeometry(QtCore.QRect(10, 15, 211, 17))
        self.cbTransparentColour.setObjectName("cbTransparentColour")
        self.label_3 = QtWidgets.QLabel(self.groupBox)
        self.label_3.setGeometry(QtCore.QRect(10, 35, 56, 20))
        self.label_3.setObjectName("label_3")
        self.mcbTransparentColour = QgsColorButton(self.groupBox)
        self.mcbTransparentColour.setGeometry(QtCore.QRect(43, 33, 61, 25))
        self.mcbTransparentColour.setColor(QtGui.QColor(255, 255, 255))
        self.mcbTransparentColour.setDefaultColor(QtGui.QColor(255, 255, 255))
        self.mcbTransparentColour.setObjectName("mcbTransparentColour")
        self.verticalLayout.addWidget(self.groupBox)
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.leStyleFile = QtWidgets.QLineEdit(Mapmashup)
        self.leStyleFile.setObjectName("leStyleFile")
        self.horizontalLayout_6.addWidget(self.leStyleFile)
        self.pbBrowseStyleFile = QtWidgets.QPushButton(Mapmashup)
        self.pbBrowseStyleFile.setMinimumSize(QtCore.QSize(100, 0))
        self.pbBrowseStyleFile.setObjectName("pbBrowseStyleFile")
        self.horizontalLayout_6.addWidget(self.pbBrowseStyleFile)
        self.verticalLayout.addLayout(self.horizontalLayout_6)
        self.cbApplyStyle = QtWidgets.QCheckBox(Mapmashup)
        self.cbApplyStyle.setObjectName("cbApplyStyle")
        self.verticalLayout.addWidget(self.cbApplyStyle)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.butLoadImage = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butLoadImage.sizePolicy().hasHeightForWidth())
        self.butLoadImage.setSizePolicy(sizePolicy)
        self.butLoadImage.setMinimumSize(QtCore.QSize(30, 30))
        self.butLoadImage.setMaximumSize(QtCore.QSize(30, 30))
        self.butLoadImage.setText("")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("images/mashup.png"), QtGui.QIcon.Normal,
                       QtGui.QIcon.Off)
        self.butLoadImage.setIcon(icon)
        self.butLoadImage.setIconSize(QtCore.QSize(26, 26))
        self.butLoadImage.setObjectName("butLoadImage")
        self.horizontalLayout_4.addWidget(self.butLoadImage)
        self.butLoadImageFile = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butLoadImageFile.sizePolicy().hasHeightForWidth())
        self.butLoadImageFile.setSizePolicy(sizePolicy)
        self.butLoadImageFile.setMinimumSize(QtCore.QSize(30, 30))
        self.butLoadImageFile.setMaximumSize(QtCore.QSize(30, 30))
        self.butLoadImageFile.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("images/mashup2.png"),
                        QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.butLoadImageFile.setIcon(icon1)
        self.butLoadImageFile.setIconSize(QtCore.QSize(26, 26))
        self.butLoadImageFile.setObjectName("butLoadImageFile")
        self.horizontalLayout_4.addWidget(self.butLoadImageFile)
        self.butLoadImageBrowse = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butLoadImageBrowse.sizePolicy().hasHeightForWidth())
        self.butLoadImageBrowse.setSizePolicy(sizePolicy)
        self.butLoadImageBrowse.setMinimumSize(QtCore.QSize(30, 30))
        self.butLoadImageBrowse.setMaximumSize(QtCore.QSize(30, 30))
        self.butLoadImageBrowse.setText("")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("images/mashup3.png"),
                        QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.butLoadImageBrowse.setIcon(icon2)
        self.butLoadImageBrowse.setIconSize(QtCore.QSize(26, 26))
        self.butLoadImageBrowse.setObjectName("butLoadImageBrowse")
        self.horizontalLayout_4.addWidget(self.butLoadImageBrowse)
        self.butClearLast = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butClearLast.sizePolicy().hasHeightForWidth())
        self.butClearLast.setSizePolicy(sizePolicy)
        self.butClearLast.setMinimumSize(QtCore.QSize(30, 30))
        self.butClearLast.setMaximumSize(QtCore.QSize(30, 30))
        self.butClearLast.setText("")
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap("images/removelayer.png"),
                        QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.butClearLast.setIcon(icon3)
        self.butClearLast.setIconSize(QtCore.QSize(26, 26))
        self.butClearLast.setObjectName("butClearLast")
        self.horizontalLayout_4.addWidget(self.butClearLast)
        self.butClear = QtWidgets.QPushButton(Mapmashup)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed,
                                           QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.butClear.sizePolicy().hasHeightForWidth())
        self.butClear.setSizePolicy(sizePolicy)
        self.butClear.setMinimumSize(QtCore.QSize(30, 30))
        self.butClear.setMaximumSize(QtCore.QSize(30, 30))
        self.butClear.setText("")
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("images/removelayers.png"),
                        QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.butClear.setIcon(icon4)
        self.butClear.setIconSize(QtCore.QSize(26, 26))
        self.butClear.setObjectName("butClear")
        self.horizontalLayout_4.addWidget(self.butClear)
        spacerItem = QtWidgets.QSpacerItem(40, 20,
                                           QtWidgets.QSizePolicy.Expanding,
                                           QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem)
        self.butHelp = QtWidgets.QPushButton(Mapmashup)
        self.butHelp.setMinimumSize(QtCore.QSize(30, 30))
        self.butHelp.setMaximumSize(QtCore.QSize(30, 30))
        self.butHelp.setText("")
        icon5 = QtGui.QIcon()
        icon5.addPixmap(QtGui.QPixmap("images/info.png"), QtGui.QIcon.Normal,
                        QtGui.QIcon.Off)
        self.butHelp.setIcon(icon5)
        self.butHelp.setIconSize(QtCore.QSize(24, 24))
        self.butHelp.setObjectName("butHelp")
        self.horizontalLayout_4.addWidget(self.butHelp)
        self.butGithub = QtWidgets.QPushButton(Mapmashup)
        self.butGithub.setMinimumSize(QtCore.QSize(30, 30))
        self.butGithub.setMaximumSize(QtCore.QSize(30, 30))
        self.butGithub.setText("")
        icon6 = QtGui.QIcon()
        icon6.addPixmap(QtGui.QPixmap("images/github.png"), QtGui.QIcon.Normal,
                        QtGui.QIcon.Off)
        self.butGithub.setIcon(icon6)
        self.butGithub.setIconSize(QtCore.QSize(24, 24))
        self.butGithub.setObjectName("butGithub")
        self.horizontalLayout_4.addWidget(self.butGithub)
        self.verticalLayout.addLayout(self.horizontalLayout_4)
        spacerItem1 = QtWidgets.QSpacerItem(20, 150,
                                            QtWidgets.QSizePolicy.Minimum,
                                            QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout.addItem(spacerItem1)
        self.groupBox.raise_()
        self.cbApplyStyle.raise_()

        self.retranslateUi(Mapmashup)
        QtCore.QMetaObject.connectSlotsByName(Mapmashup)

    def retranslateUi(self, Mapmashup):
        _translate = QtCore.QCoreApplication.translate
        Mapmashup.setWindowTitle(_translate("Mapmashup", "FSC QGIS plugin"))
        self.leImageFolder.setToolTip(
            _translate("Mapmashup", "Path of folder for temp image files"))
        self.butBrowseImg.setToolTip(
            _translate("Mapmashup", "Browse for image folder"))
        self.butBrowseImg.setText(_translate("Mapmashup", "Image folder"))
        self.leRegistrationFolder.setToolTip(
            _translate("Mapmashup", "Folder where WLD files are kept"))
        self.butBrowseReg.setToolTip(
            _translate("Mapmashup", "Browse for folder containing WLD files"))
        self.butBrowseReg.setText(
            _translate("Mapmashup", "Registration folder"))
        self.cboRegistrations.setToolTip(
            _translate("Mapmashup", "Select WLD registration info"))
        self.butRefresh.setToolTip(
            _translate("Mapmashup", "Refresh the list of WLD files"))
        self.butRefresh.setText(_translate("Mapmashup", "Refresh"))
        self.label_2.setText(_translate("Mapmashup", "Layer name"))
        self.leName.setToolTip(
            _translate("Mapmashup", "Text to be used in layer name"))
        self.label.setText(_translate("Mapmashup", "Global transparency"))
        self.hsTransparency.setToolTip(
            _translate("Mapmashup", "Set the layer\'s global transparency"))
        self.groupBox.setTitle(_translate("Mapmashup", "Transparent colour"))
        self.cbTransparentColour.setText(
            _translate("Mapmashup", "Set transparent background colour"))
        self.label_3.setText(_translate("Mapmashup", "Colour"))
        self.mcbTransparentColour.setToolTip(
            _translate("Mapmashup",
                       "Use this button to select transparent colour"))
        self.mcbTransparentColour.setColorDialogTitle(
            _translate("Mapmashup", "Select transparent colour"))
        self.leStyleFile.setToolTip(
            _translate("Mapmashup",
                       "Path of style file to apply to created maps"))
        self.pbBrowseStyleFile.setText(
            _translate("Mapmashup", "Browse style file"))
        self.cbApplyStyle.setText(_translate("Mapmashup", "Apply style"))
        self.butLoadImage.setToolTip(
            _translate(
                "Mapmashup",
                "Paste image from clipboard to map with specified registration"
            ))
        self.butLoadImageFile.setToolTip(
            _translate(
                "Mapmashup",
                "Paste most recent  image from image folder to map with specified registration"
            ))
        self.butLoadImageBrowse.setToolTip(
            _translate(
                "Mapmashup",
                "Browse for image to paste into map with specified registration"
            ))
        self.butClearLast.setToolTip(
            _translate("Mapmashup", "Remove last mashed map"))
        self.butClear.setToolTip(
            _translate("Mapmashup", "Remove all mashed maps"))
        self.butHelp.setToolTip(
            _translate(
                "Mapmashup",
                "<html><head/><body><p><span style=\" font-size:12pt;\">Get more information about this tool and help on using it. This links to a webpage with up-to-date information about the tool. </span></p></body></html>"
            ))
        self.butGithub.setToolTip(
            _translate(
                "Mapmashup",
                "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600;\">Report an issue with this tool.</span><span style=\" font-size:12pt;\"> Using this channel is the best way to get attention quickly. Issues can be bug reports, enhancement requests or just questions. Anyone can view current issues, but to add a new issue you will need to sign up for a free Github account (very easy).</span></p></body></html>"
            ))