Печать веб-карты с помощью arcpy.mp

Типичный рабочий процесс arcpy.mp в Portal for ArcGIS - это печать веб-карты, когда Python, ArcGIS API for JavaScript, ArcGIS Web AppBuilder и ArcGIS Experience Builder вместе создают веб-приложения, которые произведут картографические данные высокого качества.

Функция ConvertWebMapToArcGISProject

Функция ConvertWebMapToArcGISProject конвертирует веб-карту, которую вы хотите напечатать или экспортировать, в проект ArcGIS Pro. После преобразования веб-карты в проект переходят все элементы веб-карты. Затем можно изменить проект перед печатью или экспортом в стандартные форматы, такие как PDF. Функция ConvertWebMapToArcGISProject обычно используется при печати карты из приложения веб-ГИС с помощью ArcGIS API for JavaScript, ArcGIS Web AppBuilder или ArcGIS Experience Builder.

Преимущества arcpy.mp для печати веб-карт

Функция ConvertWebMapToArcGISProject предназначена для рабочих процессов, в которых необходимо изменить или экспортировать веб-карту с помощью функций arcpy.mp. Несколько примеров использования функции ConvertWebMapToArcGISProject в рабочих процессах:

  • Экспорт с помощью расширенных опций – все функции экспорта в arcpy.mp имеют множество расширенных опций. Например, метод exportToPDF, доступный в классах Layout и MapView, имеет параметры для управления сжатием растровых и векторных данных, задания цветового пространства, внедрения шрифтов и т.д. Образец кода см. в примере 2 в разделе ConvertWebMapToArcGISProject.
  • Создание атласов – если функция Серии карт в промежуточном шаблоне компоновки активирована, можно создавать атлас карт. Выходная компоновка может быть экспортирована в файл PDF, а затем вставлена в другие файлы PDF (например, на титульную страницу или в отчет), используя класс PDFDocument для создания полного атласа. Образцы кодов см. в примерах 5 и 6 в разделе ConvertWebMapToArcGISProject.
  • Создание отчетов – Отчет может генерироваться для слоев в веб-карте или промежуточных шаблонах компоновки. Один из способов выполнить этот рабочий процесс — импортировать файл отчета (.rptx) в проект ArcGIS Pro, возвращенный ConvertWebMapToArcGISProject. Для импорта файла отчета используйте функцию importDocument класса ArcGISProject. Этот отчет можно добавить в другие файлы PDF (например, в компоновку), используя класс PDFDocument. Пример кода см. в примере 7 в разделе ConvertWebMapToArcGISProject.
  • Отображение выбранных объектов во фрейме таблицы или в динамическом тексте атрибута таблицы. Доступ Python CIM можно использовать для доступа к функциям, недоступным в arcpy.mp, таким как фреймы таблиц. Образец кода см. в примере 8 в разделе ConvertWebMapToArcGISProject.
Примечание:

ArcGIS Server также содержит сервис геообработки, который называется PrintingTools. Сервис PrintingTools может использоваться в веб-приложении для создания изображения для печати высокого картографического качества. Дополнительные сведения о сервисе PrintingTools см. в разделе Печать в веб-приложениях.

Выходной файл (например, .pdf, .png и другие) скрипта Python может быть скомпонован из дополнительного параметра template_pagx и может включать различные элементы страницы компоновки (заголовок, легенды, масштабную линейку, обзорные карты, фреймы, сетки, градусные сетки, таблицы, диаграммы и т.д.) Выходные данные могут быть также элементом MapView, который не включает никаких элементов страницы компоновки.

Публикация вашего скрипта как веб-инструмента

Если у вас есть скрипт Python, который готовит карту для печати, можно включить его в инструмент-скрипт. Затем можно опубликовать инструмент-скрипт в качестве веб-инструмента. ArcGIS API for JavaScript, ArcGIS Web AppBuilder и ArcGIS Experience Builder имеют задачу печати или виджет Печать, который вы можете использовать в своем веб-приложении ГИС. И задача печати, и виджет Печать имеют свойство URL, указывающее на URL-адрес REST созданного вами веб-инструмента.

Параметры инструмента-скрипта

При использовании ConvertWebMapToArcGISProject в веб-инструменте в ArcGIS API for JavaScript, ArcGIS Web AppBuilder или ArcGIS Experience Builder, имена параметров инструмента-скрипта должны соответствовать параметрам Задачи печати или Виджета печати, описанным в следующей таблице:

Имя параметра инструмента-скриптаТип данныхТипОписание
Web_Map_as_JSON

String

Обязательный

Представление JavaScript Object Notation (JSON) о состоянии карты для экспорта из веб-приложения. JSON — это формат веб-карты. Он содержит полное состояние веб-карты (например, слои, система координат, экстент, масштаб и тому подобное). ArcGIS API for JavaScript, ArcGIS Web AppBuilder и ArcGIS Experience Builder позволяют получить эту строку JSON из веб-приложения.

Output_File

Файл

Производные

Имя выходного файла. Расширение файла зависит от параметра Format.

Format

String

Дополнительный

Формат, в котором будет предоставлено изображение карты для печати. Допускаются следующие строки: PDF, PNG, PNG8, PNG32, JPG, GIF, EPS, SVG и SVGZ.

Layout_Template

String

Дополнительный

Имя шаблона из списка или ключевое слово MAP_ONLY. Когда выбрано MAP_ONLY или передается пустая строка, выходная карта не содержит никаких окружающих объектов компоновки страницы (например, название, легенды, масштабную линейку и т. д.)

Следующий снимок экрана показывает пример параметров инструмента-скрипта:

Пример параметров инструмента-скрипта

Подсказка:

При работе с ArcGIS API for JavaScript, также можно добавить любое количество дополнительных пользовательских параметров. Возможность передачи дополнительных параметров в пользовательскую задачу Печать позволяет собрать любое количество дополнительных параметров из веб-приложения и передать их в скрипт Python. Например, ваше веб-приложение может иметь элемент управления, которые позволяют выбирать, внедрять ли информацию о геопривязке в выходной PDF. Пример сбора дополнительных параметров из веб-приложения см. в примере 3 в разделе ConvertWebMapToArcGISProject.

Подробную информацию о настройке параметров инструмента-скрипта см. в Настройка параметров инструмента-скрипта.

Понимание веб-карты JSON

Если вы используете задачу или виджет Печать в ArcGIS API for JavaScript, ArcGIS Web AppBuilder или ArcGIS Experience Builder, создавать веб-карту JSON не нужно; это сделают интерфейсы API. Однако прежде чем скрипт будет опубликован и использован в веб-API, его необходимо запустить локально в ArcGIS Pro. При локальном запуске скрипта можно использовать любую допустимую строку JSON. Строка JSON, похожая на то, что возвращает веб-приложение, может потребоваться для успешного выполнения скрипта. См. спецификацию ExportWebMap, чтобы узнать, как должен быть отформатирован этот текст. Ниже приведен пример строки:

{
    "layoutOptions": {
        "titleText": "Simple WebMap JSON example"
    },
    "operationalLayers": [
        {
            "url": "https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Federal_Lands/FeatureServer/0",
            "visibility": true,
            "title": "USA_Federal_Lands"
        }
    ],
    "exportOptions": {
        "outputSize": [
            1500,
            1500
        ]
    },
    "mapOptions": {
        "extent": {
            "xmin": -13077000,
            "ymin": 4031000,
            "xmax": -13023000,
            "ymax": 4053000
        }
    },
    "version": "1.4"
}
Подсказка:

При запуске инструмента-скрипта строку JSON можно скопировать и вставить во входной параметр Web_Map_as_JSON. Однако переносы строк необходимо удалить. Ниже представлен пример строки JSON, где удалены разделы на строки:

{"layoutOptions": {"titleText": "Simple WebMap JSON example"},"operationalLayers": [{"url": "https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Federal_Lands/FeatureServer/0","visibility": true, "title": "USA_Federal_Lands"}],"exportOptions": {"outputSize": [1500,1500]},"mapOptions": {"extent": {"xmin": -13077000,"ymin": 4031000,"xmax": -13023000,"ymax": 4053000}},"version": "1.4"}
Подсказка:

Дополнительно можно создать скрипт Python, чтобы он разрешал пустые входные данные Web_Map_as_JSON при запуске из ArcGIS Pro до публикации. Есть несколько способов выполнить это. Пример кода ниже показывает способ сделать это. После публикации скрипта как веб-инструмента, его можно опробовать с действующим JSON из веб-приложения.

# If script is executed from within ArcGIS Pro, and WebMap_as_JSON is blank, then don't fail
prodName = arcpy.GetInstallInfo()['ProductName']
if (WebMap_as_JSON == '#'):
	if (prodName == 'ArcGISPro'):
		exit()
Подсказка:

Как упоминалось раньше, JSON веб-карты, возвращенный интерфейсами Web API, содержит полное состояние веб-карты. Объект layoutOptions в веб-карте JSON требует дополнительного обсуждения, поскольку он автоматически обновляет элементы компоновки, чтобы они могли быть размещены в template_pagx. Например, если JSON имеет настройку titleText, а template_pagx содержит элемент Заголовка Компоновки или Метаданных в виде динамического текста с атрибутом заголовка, динамический текст в компоновке страницы шаблона будет обновлен с помощью значения titleText. Дополнительные сведения см. в разделе layoutOptions в спецификации ExportWebMap.

Шаблоны компоновки

ArcGIS Pro позволяет создавать мощные картографические компоновки, которые можно сохранить, как файл компоновки (.pagx) для его использования в качестве дополнительного параметра template_pagx в ConvertWebMapToArcGISProject. Компоновка страницы может содержать зарамочное оформление карты (например, текст заголовка, легенды, масштабную линейку, фреймы обзорной карты, сетки, таблицы, диаграммы и т.д.). Элементы зарамочного оформления карты могут быть статическими и динамическими. Это означает, что они могут реагировать на изменения в карте. К примеру, сетки могут автоматически изменяться при изменении масштаба, а элементы легенды - отображать только объекты, содержащиеся в текущем экстенте. Подробнее см. разделы Компоновки в ArcGIS Pro и Руководство по созданию компоновки.

Когда скрипт Python, который использует ConvertWebMapToArcGISProject, встраивается в веб-инструмент, необходимо убедиться, что ArcGIS Server может получить доступ к шаблонам компоновок и данным, используемым в веб-приложении. Рекомендуется использовать папку, которая зарегистрирована в ArcGIS Server. Дополнительную информацию о регистрации данных см. в разделе Регистрация данных на ArcGIS Server.

В дополнение к созданию ваших собственных шаблонов компоновки можно использовать шаблоны, которые поставляются вместе с программным обеспечением. Они находятся в папке <installation_directory>\Templates\ExportWebMapTemplates. Эти шаблоны содержат элементы карты, такие как легенда, динамический текст текущей даты, шкалу масштаба и текст масштаба. С этих шаблонов удобны для начала работы. Но помните, что они расположены в папке установки и могут быть удалены при удалении или переустановке программного обеспечения. Эти шаблоны могут быть скопированы вручную в местоположение, к которому у ArcGIS Server есть допуск, и далее они могут редактироваться, если требуется.

В определенных случаях бывает выгодно использовать отдельную задачу в веб-приложении, чтобы получать информацию о доступных шаблонах компоновки. Например, вы можете захотеть узнать, выбирает ли конечный пользователь веб-приложения шаблон компоновки с элементом Метаданные компоновки в виде динамического текста вместе с атрибутом заголовка, и вы можете запросить, чтобы пользователь ввел свой собственный заголовок. Для выполнения этого сервис PrintingTools содержит задачу с названием Получить информацию о шаблонах компоновки, которая возвращает содержимое шаблонов компоновки в формате JSON. Для большей информации о задаче Получить информацию о шаблонах компоновки см. в разделе Печать в веб-приложениях.

Поддержка графики клиента

По умолчанию, наложение заметок или графика со стороны клиента для веб-приложения сохраняется в рабочей области во внутренней памяти. Рабочая область в памяти является временной и удаляется при закрытии приложения. Чтобы сделать постоянную копию выходного проекта, содержащего наложение заметок, задайте notes_gdb; затем используйте метод saveACopy из класса ArcGISProject.

Использование функции updateLayerFromJSON

Если ваше веб-приложение использует динамические слои, функция updateLayerFromJSON из класса Layer может использоваться для обновления свойств (например, символов) промежуточных векторных слоев в шаблоне компоновки с определением динамических слоев из JSON веб-карты. Это удобно, если веб-приложение позволяет менять символы динамических слоев, и вы хотите заменить слои сервиса на промежуточные векторные данные, но все еще видите обновленные символы из веб-приложения. Пример кода, который использует updateLayerFromJSON, см. в примере 4 в разделе ConvertWebMapToArcGISProject.

Печать карт из ArcGIS Server, содержащих защищенные сервисы, в которых не используются токены

Функции ImportCredentials могут использоваться для доступа к не защищенных токенами сервисам ArcGIS Server через файлы подключения к ГИС-серверу. Учетные данные могут храниться в файлах соединений, созданных в ArcGIS Pro. См. Подключение к ГИС-серверу для получения подробной информации о создании файлов подключений. В скриптах для печати веб-карт используйте сначала ImportCredentials, а затем ConvertWebMapToArcGISProject. Поддерживаются следующие типы файлов подключения:

  • Файл подключения ArcGIS Server (.ags)
  • Файл подключения WMS Server (.wms)
  • Файл подключения WMTS Server (.wmts)

По окончании учетные данные можно очистить с помощью arcpy.ClearCredentials.

Образец кода см. в примере 9 в разделе ConvertWebMapToArcGISProject.

Дополнительные сведения см. в разделе Печать карт, содержащих защищенные сервисы.

Внимание:

Не рекомендуется внедрять учетные данные в пользовательский сервис печати, если у вас нет полного представления о системе безопасности. После публикации собственного сервиса печати с внедренными учетными данными, рекомендуется применить правила безопасности ArcGIS Server, чтобы ограничить доступ пользователей к сервису. Таким образом, можно запретить анонимным пользователям создавать изображения карты для печати, на которых отображаются ваши закрытые сервисы. Дополнительные сведения о настройке безопасности см. в разделе Изменение разрешений для сервисов и папок.

Примеры использования пользовательских скриптов Python в веб-приложениях

В следующих разделах показаны примеры использования пользовательских скриптов Python в веб-приложениях.

Пример 1: Используйте пользовательский скрипт Python в ArcGIS Web AppBuilder

Этот пример показывает, как можно использовать вместе Python и ArcGIS Web AppBuilder для создания веб-ГИС приложения для печати веб-карты. Пользователь сможет перейти к области интереса, выбрать шаблоны компоновки из списка (например, для различных размеров станицы) и нажать кнопку Печать. В результате он получит документ PDF или .png для печати. Если пользователь выбирает выходной файл PDF, этот файл будет содержать векторные данные для слоёв сервисов.

В этом скрипте Python используются промежуточные шаблоны компоновки (файлы .pagx), которые содержат векторные эквиваленты всех возможных сервисных слоев. После запуска функции ConvertWebMapToArcGISProject скрипт просматривает все слои выходного документа карты и удаляет все слои, кроме промежуточных векторных, которые соответствуют сервисным слоям в веб-карте JSON. Затем компоновка экспортируется в файлы PDF или .png.

import arcpy
import os
import uuid

# The template location in the server data store
templatePath = '//MyServer/MyDataStore/Templates'

# Input WebMap JSON
Web_Map_as_JSON = arcpy.GetParameterAsText(0)

# Format for output
Format = arcpy.GetParameterAsText(1)

# Input layout template
Layout_Template = arcpy.GetParameterAsText(2)

# Get the requested layout template pagx file
templatePagx = os.path.join(templatePath, Layout_Template + '.pagx')
   
# Convert the WebMap to an ArcGISProject
result = arcpy.mp.ConvertWebMapToArcGISProject(Web_Map_as_JSON, templatePagx, "Layers Map Frame")
aprx = result.ArcGISProject
layout = aprx.listLayouts()[0]

# Reference the map that contains the webmap
m = aprx.listMaps('Web Map')[0]

# Remove the service layer
# This will just leave the vector layers from the template
for lyr in m.listLayers():
    if lyr.isWebLayer:
        m.removeLayer(lyr)
        
# Use the uuid module to generate a GUID as part of the output name
# This will ensure a unique output name
output = 'WebMap_{}.{}'.format(str(uuid.uuid1()), Format)
Output_File = os.path.join(arcpy.env.scratchFolder, output)

# Export the WebMap
if Format.lower() == 'pdf':
    layout.exportToPDF(Output_File) 
elif Format.lower() == 'png':
    layout.exportToPNG(Output_File)

# Set the output parameter to be the output file of the server job
arcpy.SetParameterAsText(3, Output_File) 

# Clean up
del layout, aprx, result

После публикации инструмента-скрипта Python в качестве веб-инструмента виджет Печать ArcGIS Web AppBuilder будет настроен на работу с REST URL веб-инструмента. Следующий снимок экрана показывает диалоговое окно настройки для виджета Печать:

Диалоговое окно настройки для виджета Печать.
Подсказка:

В скриншоте, представленном выше, значения для Формата по умолчанию и Компоновки по умолчанию заполняются автоматически из параметров Format и Layout_Template веб-инструмента.

Пример 2: Используйте пользовательский скрипт Python в ArcGIS API for JavaScript

Этот пример показывает, как можно использовать вместе Python и ArcGIS API for JavaScript для создания веб-ГИС приложения для печати веб-карты. Пользователь сможет выполнять следующее в веб-приложении:

  • Перейти к области интереса.
  • Выбирать промежуточный шаблон компоновки.
  • Выбирать выходной формат.
  • Выбирать, нужно ли экспортировать информацию о географической привязке в выходной файл PDF, передав дополнительный параметр из веб-приложения в задачу Печать.
  • Экспортировать карту в дружественном к принтеру формате, содержащем выходные векторные данные для слоев сервиса.

В этом скрипте Python используются промежуточные шаблоны компоновки (файлы .pagx), которые содержат векторные эквиваленты всех возможных сервисных слоев. После запуска функции ConvertWebMapToArcGISProject скрипт просматривает все слои выходного документа карты и удаляет все слои, кроме промежуточных векторных, которые соответствуют сервисным слоям в веб-карте JSON. Затем выходная компоновка экспортируется в файлы PDF или .png. В этом примере также показано, как добавить дополнительные параметры (Georef_info) из веб-приложения в скрипт Python к стандартным параметрам, поддерживаемым задачей Печать.

import arcpy
import os
import uuid

# The template location in the server data store
templatePath = '//MyServer/MyDataStore/Templates'

# Input WebMap JSON
Web_Map_as_JSON = arcpy.GetParameterAsText(0)

# Format for output
Format = arcpy.GetParameterAsText(1)

# Input layout template
Layout_Template = arcpy.GetParameterAsText(2)
    
# Extra parameter - georef_info
Georef_info = arcpy.GetParameterAsText(3)

# Convert Georef_info string to boolean
if Georef_info.lower() == 'false': 
    Georef_info_bol = False
elif Georef_info.lower() == 'true': 
    Georef_info_bol = True
else: Georef_info_bol = True

# Get the requested layout template pagx file
templatePagx = os.path.join(templatePath, Layout_Template + '.pagx')
   
# Convert the WebMap to an ArcGISProject
result = arcpy.mp.ConvertWebMapToArcGISProject(Web_Map_as_JSON, templatePagx, "Layers Map Frame")
aprx = result.ArcGISProject
layout = aprx.listLayouts()[0]

# Reference the map that contains the webmap
m = aprx.listMaps('Web Map')[0]

# Remove the service layer
# This will just leave the vector layers from the template
for lyr in m.listLayers():
    if lyr.isWebLayer:
        m.removeLayer(lyr)
        
# Use the uuid module to generate a GUID as part of the output name
# This will ensure a unique output name
output = 'WebMap_{}.{}'.format(str(uuid.uuid1()), Format)
Output_File = os.path.join(arcpy.env.scratchFolder, output)

# Export the WebMap - use Georef_info_bol to control georeferencing
if Format.lower() == 'pdf':
    layout.exportToPDF(Output_File, georef_info=Georef_info_bol) 
elif Format.lower() == 'png':
    layout.exportToPNG(Output_File, world_file=Georef_info_bol)

# Set the output parameter to be the output file of the server job
arcpy.SetParameterAsText(4, Output_File) 

# Clean up
del layout, aprx, result

Инструмент-скрипт Python публикуется как веб-инструмент. В следующем скрипте задача Печать в ArcGIS API for JavaScript настроена для использования REST URL веб-инструмента:

Подсказка:

Ссылка на REST URL веб-инструмента размещается в этой строке:

var printServiceUrl = "https://MyServer:6443/arcgis/rest/services/MyPrintService/GPServer/MyPrintService";

Весь скрипт выглядит следующим образом:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
  <title>Austin Print WebApp</title>

  <link rel="stylesheet" href="https://js.arcgis.com/4.3/esri/css/main.css">
  <script src="https://js.arcgis.com/4.3/"></script>

  <style>
    html,
    body,
    #viewDiv {
      padding: 0;
      margin: 0;
      height: 100%;
      width: 100%;
    }
    
    #layerToggle {
      top: 20px;
      right: 20px;
      position: absolute;
      z-index: 99;
      background-color: white;
      border-radius: 8px;
      padding: 10px;
      opacity: 1;
    }
  </style>

  <script>
    require([
        "esri/Map",
        "esri/views/MapView",
        "esri/layers/TileLayer",
        "esri/tasks/PrintTask",
        "esri/tasks/support/PrintParameters",
        "esri/tasks/support/PrintTemplate",
        "dojo/dom",
        "dojo/on",
        "dojo/domReady!"
      ],
      function(
        Map, MapView, TileLayer, PrintTask, PrintParameters, PrintTemplate, dom, on
      ) {

        /*****************************************************************
         * Create a TileLayer instance. 
         *****************************************************************/
        var austinLyr = new TileLayer({
          url: "http://MyServer:6080/arcgis/rest/services/MyMapService/MapServer",
          id: "austin",
          opacity: 0.9
        });

        /*****************************************************************
         * Layers may be added to the map in the map's constructor
         *****************************************************************/
        var map = new Map({
          basemap: "oceans",
          layers: [austinLyr]
        });

        var view = new MapView({
          container: "viewDiv",
          map: map
        });
        
        /*****************************************************************
         * Go to extent of Austin Layer
         *****************************************************************/
        view.then(function() {
          austinLyr.then(function() {
            view.goTo(austinLyr.fullExtent);
          });
        });

        var printServiceUrl = "https://MyServer:6443/arcgis/rest/services/MyPrintService/GPServer/MyPrintService";
        
        var printMode = "async";
        
        var printTask = new PrintTask({
   			url: printServiceUrl,
   			mode: printMode
			});
		
	function myPrint() {
		// input layout template
		var layout = dom.byId("layout");
	        var index = layout.selectedIndex;
	        var selectedValue_layout = layout.options[index].value;
	        
	        // format for output
	        var format = dom.byId("format");
	        var index = format.selectedIndex;
	        var selectedValue_format = format.options[index].value;
	        
	        // Extra parameter: Georeferencing info boolean
	        var georef_info = dom.byId("georef_info");
	        var index = georef_info.selectedIndex;
	        var selectedValue_georef_info = georef_info.options[index].value;
	        
	        var template = new PrintTemplate({
			 format: selectedValue_format,
			 layout: selectedValue_layout, 
			});
	
		var params = new PrintParameters({
			 view: view,
			 template: template
			});
			
		params.extraParameters = {
          		Georef_info : selectedValue_georef_info
        		};
	        
		printTask.execute(params).then(printResult, printError);
			}
		
		function printResult(result) {
        	window.open(result.url);
     		}	
     		
     	function printError(result) {
        	alert('Error printing.')
     		}
     		
     	// Call myPrint() each time the button is clicked    
      	on(dom.byId("doBtn"), "click", myPrint);

      });
  </script>
</head>

<body>
  <div id="viewDiv"></div>
  <span id="layerToggle">
    Layout Template:
    <select id="layout" >
      <OPTION value="Austin26x28">Austin26x28</OPTION>
      <OPTION value="Austin24x36">Austin24x36</OPTION>
    </select>
    &nbsp;&nbsp;Format:
    <select id="format">
      <OPTION value="PDF">PDF</OPTION>
      <OPTION value="PNG">PNG</OPTION>
    </select>
	
    &nbsp;&nbsp;Include Georef info?
    <select id="georef_info">
      <OPTION value="True">True</OPTION>
      <OPTION value="False">False</OPTION>
    </select>
    <button id="doBtn">Print Map</button>
  </span>
</body>

</html>