diff --git a/tableauserverclient/server/endpoint/custom_views_endpoint.py b/tableauserverclient/server/endpoint/custom_views_endpoint.py index d1446b1f..57a5b010 100644 --- a/tableauserverclient/server/endpoint/custom_views_endpoint.py +++ b/tableauserverclient/server/endpoint/custom_views_endpoint.py @@ -1,8 +1,13 @@ +import io import logging -from typing import List, Optional, Tuple - -from .endpoint import QuerysetEndpoint, api -from .exceptions import MissingRequiredFieldError +import os +from pathlib import Path +from typing import List, Optional, Tuple, Union + +from tableauserverclient.config import BYTES_PER_MB, FILESIZE_LIMIT_MB +from tableauserverclient.filesys_helpers import get_file_object_size +from tableauserverclient.server.endpoint.endpoint import QuerysetEndpoint, api +from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError from tableauserverclient.models import CustomViewItem, PaginationItem from tableauserverclient.server import RequestFactory, RequestOptions, ImageRequestOptions @@ -16,6 +21,15 @@ update the name or owner of a custom view. """ +FilePath = Union[str, os.PathLike] +FileObject = Union[io.BufferedReader, io.BytesIO] +FileObjectR = Union[io.BufferedReader, io.BytesIO] +FileObjectW = Union[io.BufferedWriter, io.BytesIO] +PathOrFileR = Union[FilePath, FileObjectR] +PathOrFileW = Union[FilePath, FileObjectW] +io_types_r = (io.BufferedReader, io.BytesIO) +io_types_w = (io.BufferedWriter, io.BytesIO) + class CustomViews(QuerysetEndpoint[CustomViewItem]): def __init__(self, parent_srv): @@ -25,6 +39,10 @@ def __init__(self, parent_srv): def baseurl(self) -> str: return "{0}/sites/{1}/customviews".format(self.parent_srv.baseurl, self.parent_srv.site_id) + @property + def expurl(self) -> str: + return f"{self.parent_srv._server_address}/api/exp/sites/{self.parent_srv.site_id}/customviews" + """ If the request has no filter parameters: Administrators will see all custom views. Other users will see only custom views that they own. @@ -102,3 +120,46 @@ def delete(self, view_id: str) -> None: url = "{0}/{1}".format(self.baseurl, view_id) self.delete_request(url) logger.info("Deleted single custom view (ID: {0})".format(view_id)) + + @api(version="3.21") + def download(self, view_item: CustomViewItem, file: PathOrFileW) -> PathOrFileW: + url = f"{self.expurl}/{view_item.id}/content" + server_response = self.get_request(url) + if isinstance(file, io_types_w): + file.write(server_response.content) + return file + + with open(file, "wb") as f: + f.write(server_response.content) + + return file + + @api(version="3.21") + def publish(self, view_item: CustomViewItem, file: PathOrFileR) -> Optional[CustomViewItem]: + url = self.expurl + if isinstance(file, io_types_r): + size = get_file_object_size(file) + elif isinstance(file, (str, Path)) and (p := Path(file)).is_file(): + size = p.stat().st_size + else: + raise ValueError("File path or file object required for publishing custom view.") + + if size >= FILESIZE_LIMIT_MB * BYTES_PER_MB: + upload_session_id = self.parent_srv.fileuploads.upload(file) + url = f"{url}?uploadSessionId={upload_session_id}" + xml_request, content_type = RequestFactory.CustomView.publish_req_chunked(view_item) + else: + if isinstance(file, io_types_r): + file.seek(0) + contents = file.read() + if view_item.name is None: + raise MissingRequiredFieldError("Custom view item missing name.") + filename = view_item.name + elif isinstance(file, (str, Path)): + filename = Path(file).name + contents = Path(file).read_bytes() + + xml_request, content_type = RequestFactory.CustomView.publish_req(view_item, filename, contents) + + server_response = self.post_request(url, xml_request, content_type) + return CustomViewItem.from_response(server_response.content, self.parent_srv.namespace) diff --git a/tableauserverclient/server/request_factory.py b/tableauserverclient/server/request_factory.py index e965411c..b0c8b37b 100644 --- a/tableauserverclient/server/request_factory.py +++ b/tableauserverclient/server/request_factory.py @@ -1,4 +1,5 @@ import xml.etree.ElementTree as ET + from typing import Any, Dict, Iterable, List, Optional, Tuple, TYPE_CHECKING, Union from requests.packages.urllib3.fields import RequestField @@ -1267,6 +1268,49 @@ def update_req(self, xml_request: ET.Element, custom_view_item: CustomViewItem): if custom_view_item.name is not None: updating_element.attrib["name"] = custom_view_item.name + @_tsrequest_wrapped + def _publish_xml(self, xml_request: ET.Element, custom_view_item: CustomViewItem) -> bytes: + custom_view_element = ET.SubElement(xml_request, "customView") + if (name := custom_view_item.name) is not None: + custom_view_element.attrib["name"] = name + else: + raise ValueError(f"Custom View Item missing name: {custom_view_item}") + if (shared := custom_view_item.shared) is not None: + custom_view_element.attrib["shared"] = str(shared).lower() + else: + raise ValueError(f"Custom View Item missing shared: {custom_view_item}") + if (owner := custom_view_item.owner) is not None: + owner_element = ET.SubElement(custom_view_element, "owner") + if (owner_id := owner.id) is not None: + owner_element.attrib["id"] = owner_id + else: + raise ValueError(f"Custom View Item owner missing id: {owner}") + else: + raise ValueError(f"Custom View Item missing owner: {custom_view_item}") + if (workbook := custom_view_item.workbook) is not None: + workbook_element = ET.SubElement(custom_view_element, "workbook") + if (workbook_id := workbook.id) is not None: + workbook_element.attrib["id"] = workbook_id + else: + raise ValueError(f"Custom View Item workbook missing id: {workbook}") + else: + raise ValueError(f"Custom View Item missing workbook: {custom_view_item}") + + return ET.tostring(xml_request) + + def publish_req_chunked(self, custom_view_item: CustomViewItem): + xml_request = self._publish_xml(custom_view_item) + parts = {"request_payload": ("", xml_request, "text/xml")} + return _add_multipart(parts) + + def publish_req(self, custom_view_item: CustomViewItem, filename: str, file_contents: bytes): + xml_request = self._publish_xml(custom_view_item) + parts = { + "request_payload": ("", xml_request, "text/xml"), + "tableau_customview": (filename, file_contents, "application/octet-stream"), + } + return _add_multipart(parts) + class GroupSetRequest: @_tsrequest_wrapped diff --git a/test/assets/custom_view_download.json b/test/assets/custom_view_download.json new file mode 100644 index 00000000..1ba2d74b --- /dev/null +++ b/test/assets/custom_view_download.json @@ -0,0 +1,47 @@ +[ + { + "isSourceView": true, + "viewName": "Overview", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IGRhc2hib2FyZD0nT3ZlcnZpZXcnIHNvdXJjZS1idWlsZD0nMjAyNC4yLjAgKDIwMjQyLjI0LjA3MTYuMTk0NCknIHZlcnNpb249JzE4LjEnIHhtbG5zOnVzZXI9J2h0dHA6Ly93d3cudGFibGVhdXNvZnR3YXJlLmNvbS94bWwvdXNlcic-CiAgPGFjdGl2ZSBpZD0nMScgLz4KICA8ZGF0YXNvdXJjZXM-CiAgICA8ZGF0YXNvdXJjZSBuYW1lPSdmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjaic-CiAgICAgIDxjb2x1bW4gZGF0YXR5cGU9J3N0cmluZycgbmFtZT0nWzpNZWFzdXJlIE5hbWVzXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJz4KICAgICAgICA8YWxpYXNlcz4KICAgICAgICAgIDxhbGlhcyBrZXk9JyZxdW90O1tmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjal0uW2N0ZDpDdXN0b21lciBOYW1lOnFrXSZxdW90OycgdmFsdWU9J0NvdW50IG9mIEN1c3RvbWVycycgLz4KICAgICAgICA8L2FsaWFzZXM-CiAgICAgIDwvY29sdW1uPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChNT05USChPcmRlciBEYXRlKSxQcm9kdWN0IENhdGVnb3J5KScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChNT05USChPcmRlciBEYXRlKSxQcm9kdWN0IENhdGVnb3J5KV0nIG5hbWUtc3R5bGU9J3VucXVhbGlmaWVkJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJz4KICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2Nyb3Nzam9pbic-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbdG1uOk9yZGVyIERhdGU6b2tdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW25vbmU6Q2F0ZWdvcnk6bmtdJyAvPgogICAgICAgIDwvZ3JvdXBmaWx0ZXI-CiAgICAgIDwvZ3JvdXA-CiAgICAgIDxjb2x1bW4gY2FwdGlvbj0nQWN0aW9uIChNT05USChPcmRlciBEYXRlKSxQcm9kdWN0IENhdGVnb3J5KScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKE1PTlRIKE9yZGVyIERhdGUpLFByb2R1Y3QgQ2F0ZWdvcnkpXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJyAvPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChNT05USChPcmRlciBEYXRlKSxTZWdtZW50KScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChNT05USChPcmRlciBEYXRlKSxTZWdtZW50KV0nIG5hbWUtc3R5bGU9J3VucXVhbGlmaWVkJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJz4KICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2Nyb3Nzam9pbic-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbdG1uOk9yZGVyIERhdGU6b2tdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW1NlZ21lbnRdJyAvPgogICAgICAgIDwvZ3JvdXBmaWx0ZXI-CiAgICAgIDwvZ3JvdXA-CiAgICAgIDxjb2x1bW4gY2FwdGlvbj0nQWN0aW9uIChNT05USChPcmRlciBEYXRlKSxTZWdtZW50KScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKE1PTlRIKE9yZGVyIERhdGUpLFNlZ21lbnQpXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJyAvPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChPcmRlciBQcm9maXRhYmxlPyxDYXRlZ29yeSxNT05USChPcmRlciBEYXRlKSknIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoT3JkZXIgUHJvZml0YWJsZT8sQ2F0ZWdvcnksTU9OVEgoT3JkZXIgRGF0ZSkpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tDYWxjdWxhdGlvbl85MDYwMTIyMTA0OTQ3NDcxXScgLz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tDYXRlZ29yeV0nIC8-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbdG1uOk9yZGVyIERhdGU6b2tdJyAvPgogICAgICAgIDwvZ3JvdXBmaWx0ZXI-CiAgICAgIDwvZ3JvdXA-CiAgICAgIDxjb2x1bW4gY2FwdGlvbj0nQWN0aW9uIChPcmRlciBQcm9maXRhYmxlPyxDYXRlZ29yeSxNT05USChPcmRlciBEYXRlKSknIGRhdGF0eXBlPSd0dXBsZScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChPcmRlciBQcm9maXRhYmxlPyxDYXRlZ29yeSxNT05USChPcmRlciBEYXRlKSldJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnIC8-CiAgICAgIDxncm91cCBjYXB0aW9uPSdBY3Rpb24gKE9yZGVyIFByb2ZpdGFibGU_LE1PTlRIKE9yZGVyIERhdGUpLFNlZ21lbnQpJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKE9yZGVyIFByb2ZpdGFibGU_LE1PTlRIKE9yZGVyIERhdGUpLFNlZ21lbnQpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tDYWxjdWxhdGlvbl85MDYwMTIyMTA0OTQ3NDcxXScgLz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1t0bW46T3JkZXIgRGF0ZTpva10nIC8-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbU2VnbWVudF0nIC8-CiAgICAgICAgPC9ncm91cGZpbHRlcj4KICAgICAgPC9ncm91cD4KICAgICAgPGNvbHVtbiBjYXB0aW9uPSdBY3Rpb24gKE9yZGVyIFByb2ZpdGFibGU_LE1PTlRIKE9yZGVyIERhdGUpLFNlZ21lbnQpJyBkYXRhdHlwZT0ndHVwbGUnIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoT3JkZXIgUHJvZml0YWJsZT8sTU9OVEgoT3JkZXIgRGF0ZSksU2VnbWVudCldJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnIC8-CiAgICAgIDxncm91cCBjYXB0aW9uPSdBY3Rpb24gKFBvc3RhbCBDb2RlLFN0YXRlL1Byb3ZpbmNlKScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChQb3N0YWwgQ29kZSxTdGF0ZS9Qcm92aW5jZSldJyBuYW1lLXN0eWxlPSd1bnF1YWxpZmllZCcgdXNlcjphdXRvLWNvbHVtbj0nc2hlZXRfbGluayc-CiAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdjcm9zc2pvaW4nPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW25vbmU6UG9zdGFsIENvZGU6bmtdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW1N0YXRlL1Byb3ZpbmNlXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoUG9zdGFsIENvZGUsU3RhdGUvUHJvdmluY2UpJyBkYXRhdHlwZT0ndHVwbGUnIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoUG9zdGFsIENvZGUsU3RhdGUvUHJvdmluY2UpXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJyAvPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChTdGF0ZS9Qcm92aW5jZSknIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoU3RhdGUvUHJvdmluY2UpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tTdGF0ZS9Qcm92aW5jZV0nIC8-CiAgICAgICAgPC9ncm91cGZpbHRlcj4KICAgICAgPC9ncm91cD4KICAgICAgPGNvbHVtbiBjYXB0aW9uPSdBY3Rpb24gKFN0YXRlL1Byb3ZpbmNlKScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKFN0YXRlL1Byb3ZpbmNlKV0nIHJvbGU9J2RpbWVuc2lvbicgdHlwZT0nbm9taW5hbCcgdXNlcjphdXRvLWNvbHVtbj0nc2hlZXRfbGluaycgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tDYWxjdWxhdGlvbl85MDYwMTIyMTA0OTQ3NDcxXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6Q2FsY3VsYXRpb25fOTA2MDEyMjEwNDk0NzQ3MTpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOk9yZGVyIERhdGU6cWtdJyBwaXZvdD0na2V5JyB0eXBlPSdxdWFudGl0YXRpdmUnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbUmVnaW9uXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6UmVnaW9uOm5rXScgcGl2b3Q9J2tleScgdHlwZT0nbm9taW5hbCcgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tDYWxjdWxhdGlvbl85OTIxMTAzMTQ0MTAzNzQzXScgZGVyaXZhdGlvbj0nVXNlcicgbmFtZT0nW3VzcjpDYWxjdWxhdGlvbl85OTIxMTAzMTQ0MTAzNzQzOnFrXScgcGl2b3Q9J2tleScgdHlwZT0ncXVhbnRpdGF0aXZlJyAvPgogICAgPC9kYXRhc291cmNlPgogIDwvZGF0YXNvdXJjZXM-CiAgPHdvcmtzaGVldCBuYW1lPSdUb3RhbCBTYWxlcyc-CiAgICA8ZmlsdGVyIGNsYXNzPSdjYXRlZ29yaWNhbCcgY29sdW1uPSdbZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltBY3Rpb24gKFN0YXRlL1Byb3ZpbmNlKV0nPgogICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J21lbWJlcicgbGV2ZWw9J1tTdGF0ZS9Qcm92aW5jZV0nIG1lbWJlcj0nJnF1b3Q7VGV4YXMmcXVvdDsnIHVzZXI6dWktYWN0aW9uLWZpbHRlcj0nW0FjdGlvbjFdJyB1c2VyOnVpLWRvbWFpbj0nZGF0YWJhc2UnIHVzZXI6dWktZW51bWVyYXRpb249J2luY2x1c2l2ZScgdXNlcjp1aS1tYXJrZXI9J2VudW1lcmF0ZScgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlciBjbGFzcz0nY2F0ZWdvcmljYWwnIGNvbHVtbj0nW2ZlZGVyYXRlZC4xMG5uazhkMXZnbXc4cTE3eXU3NnUwNnBuYmNqXS5bbm9uZTpSZWdpb246bmtdJyBmaWx0ZXItZ3JvdXA9JzE0Jz4KICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdtZW1iZXInIGxldmVsPSdbbm9uZTpSZWdpb246bmtdJyBtZW1iZXI9JyZxdW90O0NlbnRyYWwmcXVvdDsnIHVzZXI6dWktZG9tYWluPSdkYXRhYmFzZScgdXNlcjp1aS1lbnVtZXJhdGlvbj0naW5jbHVzaXZlJyB1c2VyOnVpLW1hcmtlcj0nZW51bWVyYXRlJyAvPgogICAgPC9maWx0ZXI-CiAgICA8dGFibGUgLz4KICA8L3dvcmtzaGVldD4KICA8d29ya3NoZWV0IG5hbWU9J1NhbGUgTWFwJz4KICAgIDxmaWx0ZXIgY2xhc3M9J2NhdGVnb3JpY2FsJyBjb2x1bW49J1tmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjal0uW25vbmU6UmVnaW9uOm5rXScgZmlsdGVyLWdyb3VwPScxNCc-CiAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbWVtYmVyJyBsZXZlbD0nW25vbmU6UmVnaW9uOm5rXScgbWVtYmVyPScmcXVvdDtDZW50cmFsJnF1b3Q7JyB1c2VyOnVpLWRvbWFpbj0nZGF0YWJhc2UnIHVzZXI6dWktZW51bWVyYXRpb249J2luY2x1c2l2ZScgdXNlcjp1aS1tYXJrZXI9J2VudW1lcmF0ZScgLz4KICAgIDwvZmlsdGVyPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CiAgPHdvcmtzaGVldCBuYW1lPSdTYWxlcyBieSBTZWdtZW50Jz4KICAgIDxmaWx0ZXIgY2xhc3M9J2NhdGVnb3JpY2FsJyBjb2x1bW49J1tmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjal0uW0FjdGlvbiAoU3RhdGUvUHJvdmluY2UpXSc-CiAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbWVtYmVyJyBsZXZlbD0nW1N0YXRlL1Byb3ZpbmNlXScgbWVtYmVyPScmcXVvdDtUZXhhcyZxdW90OycgdXNlcjp1aS1hY3Rpb24tZmlsdGVyPSdbQWN0aW9uMV0nIHVzZXI6dWktZG9tYWluPSdkYXRhYmFzZScgdXNlcjp1aS1lbnVtZXJhdGlvbj0naW5jbHVzaXZlJyB1c2VyOnVpLW1hcmtlcj0nZW51bWVyYXRlJyAvPgogICAgPC9maWx0ZXI-CiAgICA8ZmlsdGVyIGNsYXNzPSdjYXRlZ29yaWNhbCcgY29sdW1uPSdbZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltub25lOlJlZ2lvbjpua10nIGZpbHRlci1ncm91cD0nMTQnPgogICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J21lbWJlcicgbGV2ZWw9J1tub25lOlJlZ2lvbjpua10nIG1lbWJlcj0nJnF1b3Q7Q2VudHJhbCZxdW90OycgdXNlcjp1aS1kb21haW49J2RhdGFiYXNlJyB1c2VyOnVpLWVudW1lcmF0aW9uPSdpbmNsdXNpdmUnIHVzZXI6dWktbWFya2VyPSdlbnVtZXJhdGUnIC8-CiAgICA8L2ZpbHRlcj4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0PgogIDx3b3Jrc2hlZXQgbmFtZT0nU2FsZXMgYnkgUHJvZHVjdCc-CiAgICA8ZmlsdGVyIGNsYXNzPSdjYXRlZ29yaWNhbCcgY29sdW1uPSdbZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltBY3Rpb24gKFN0YXRlL1Byb3ZpbmNlKV0nPgogICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J21lbWJlcicgbGV2ZWw9J1tTdGF0ZS9Qcm92aW5jZV0nIG1lbWJlcj0nJnF1b3Q7VGV4YXMmcXVvdDsnIHVzZXI6dWktYWN0aW9uLWZpbHRlcj0nW0FjdGlvbjFdJyB1c2VyOnVpLWRvbWFpbj0nZGF0YWJhc2UnIHVzZXI6dWktZW51bWVyYXRpb249J2luY2x1c2l2ZScgdXNlcjp1aS1tYXJrZXI9J2VudW1lcmF0ZScgLz4KICAgIDwvZmlsdGVyPgogICAgPGZpbHRlciBjbGFzcz0nY2F0ZWdvcmljYWwnIGNvbHVtbj0nW2ZlZGVyYXRlZC4xMG5uazhkMXZnbXc4cTE3eXU3NnUwNnBuYmNqXS5bbm9uZTpSZWdpb246bmtdJyBmaWx0ZXItZ3JvdXA9JzE0Jz4KICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdtZW1iZXInIGxldmVsPSdbbm9uZTpSZWdpb246bmtdJyBtZW1iZXI9JyZxdW90O0NlbnRyYWwmcXVvdDsnIHVzZXI6dWktZG9tYWluPSdkYXRhYmFzZScgdXNlcjp1aS1lbnVtZXJhdGlvbj0naW5jbHVzaXZlJyB1c2VyOnVpLW1hcmtlcj0nZW51bWVyYXRlJyAvPgogICAgPC9maWx0ZXI-CiAgICA8dGFibGUgLz4KICA8L3dvcmtzaGVldD4KICA8d2luZG93cz4KICAgIDx3aW5kb3cgY2xhc3M9J3dvcmtzaGVldCcgbmFtZT0nU2FsZSBNYXAnPgogICAgICA8c2VsZWN0aW9uLWNvbGxlY3Rpb24-CiAgICAgICAgPHR1cGxlLXNlbGVjdGlvbj4KICAgICAgICAgIDx0dXBsZS1yZWZlcmVuY2U-CiAgICAgICAgICAgIDx0dXBsZS1kZXNjcmlwdG9yPgogICAgICAgICAgICAgIDxwYW5lLWRlc2NyaXB0b3I-CiAgICAgICAgICAgICAgICA8eC1maWVsZHM-CiAgICAgICAgICAgICAgICAgIDxmaWVsZD5bZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltMb25naXR1ZGUgKGdlbmVyYXRlZCldPC9maWVsZD4KICAgICAgICAgICAgICAgIDwveC1maWVsZHM-CiAgICAgICAgICAgICAgICA8eS1maWVsZHM-CiAgICAgICAgICAgICAgICAgIDxmaWVsZD5bZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltMYXRpdHVkZSAoZ2VuZXJhdGVkKV08L2ZpZWxkPgogICAgICAgICAgICAgICAgPC95LWZpZWxkcz4KICAgICAgICAgICAgICA8L3BhbmUtZGVzY3JpcHRvcj4KICAgICAgICAgICAgICA8Y29sdW1ucz4KICAgICAgICAgICAgICAgIDxmaWVsZD5bZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltub25lOkNvdW50cnkvUmVnaW9uOm5rXTwvZmllbGQ-CiAgICAgICAgICAgICAgICA8ZmllbGQ-W2ZlZGVyYXRlZC4xMG5uazhkMXZnbXc4cTE3eXU3NnUwNnBuYmNqXS5bbm9uZTpTdGF0ZS9Qcm92aW5jZTpua108L2ZpZWxkPgogICAgICAgICAgICAgICAgPGZpZWxkPltmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjal0uW0dlb21ldHJ5IChnZW5lcmF0ZWQpXTwvZmllbGQ-CiAgICAgICAgICAgICAgICA8ZmllbGQ-W2ZlZGVyYXRlZC4xMG5uazhkMXZnbXc4cTE3eXU3NnUwNnBuYmNqXS5bTGF0aXR1ZGUgKGdlbmVyYXRlZCldPC9maWVsZD4KICAgICAgICAgICAgICAgIDxmaWVsZD5bZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltMb25naXR1ZGUgKGdlbmVyYXRlZCldPC9maWVsZD4KICAgICAgICAgICAgICAgIDxmaWVsZD5bZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLlt1c3I6Q2FsY3VsYXRpb25fOTkyMTEwMzE0NDEwMzc0Mzpxa108L2ZpZWxkPgogICAgICAgICAgICAgIDwvY29sdW1ucz4KICAgICAgICAgICAgPC90dXBsZS1kZXNjcmlwdG9yPgogICAgICAgICAgICA8dHVwbGU-CiAgICAgICAgICAgICAgPHZhbHVlPiZxdW90O1VuaXRlZCBTdGF0ZXMmcXVvdDs8L3ZhbHVlPgogICAgICAgICAgICAgIDx2YWx1ZT4mcXVvdDtUZXhhcyZxdW90OzwvdmFsdWU-CiAgICAgICAgICAgICAgPHZhbHVlPiZxdW90O01VTFRJUE9MWUdPTigoKC05Ny4xNDYzIDI1Ljk1NTYsLTk3LjIwOCAyNS45NjM2LC05Ny4yNzcyIDI1LjkzNTQsLTk3LjM0ODkgMjUuOTMwOCwtOTcuMzc0NCAyNS45MDc0LC05Ny4zNTc2IDI1Ljg4NjksLTk3LjM3MzcgMjUuODQsLTk3LjQ1MzkgMjUuODU0NCwtOTcuNDU2NCAyNS44ODM4LC05Ny41MjE4IDI1Ljg4NjUsLTk3LjU0ODIgMjUuOTM1NSwtOTcuNTgyNiAyNS45Mzc5LC05Ny42NDQ5IDI2LjAyNzUsLTk3LjcwNjcgMjYuMDM3NCwtOTcuNzY0MSAyNi4wMjg2LC05Ny44MDEzIDI2LjA2LC05Ny44MzU1IDI2LjA0NjksLTk3Ljg2MTkgMjYuMDY5OCwtOTcuOTA5OSAyNi4wNTY5LC05Ny45NjYxIDI2LjA1MTksLTk4LjAzMDggMjYuMDY1LC05OC4wNzAxIDI2LjAzNzksLTk4LjA3OTEgMjYuMDcwNSwtOTguMTM1NSAyNi4wNzIsLTk4LjE1NzUgMjYuMDU0NCwtOTguMTk3IDI2LjA1NjIsLTk4LjMwNjUgMjYuMTA0MywtOTguMzM1MiAyNi4xMzc2LC05OC4zODY3IDI2LjE1NzksLTk4LjQ0NDMgMjYuMjAxMiwtOTguNDQ1MiAyNi4yMjQ2LC05OC41MDYxIDI2LjIwOSwtOTguNTIyNCAyNi4yMjA5LC05OC41NjE1IDI2LjIyNDUsLTk4LjU4NjcgMjYuMjU3NSwtOTguNjU0MiAyNi4yMzYsLTk4LjY3OTQgMjYuMjQ5MiwtOTguNzUzOCAyNi4zMzE3LC05OC43ODk4IDI2LjMzMTYsLTk4LjgyNjkgMjYuMzY5NiwtOTguODk2MiAyNi4zNTMyLC05OC45MjkyIDI2LjM5MzIsLTk4Ljk0NjUgMjYuMzY5OSwtOTguOTc0MiAyNi40MDExLC05OS4wMTA2IDI2LjM5MjEsLTk5LjA0IDI2LjQxMjksLTk5LjA5NDggMjYuNDEwOSwtOTkuMTEwOSAyNi40MjYzLC05OS4wOTE2IDI2LjQ3NjQsLTk5LjEyODQgMjYuNTI1NSwtOTkuMTY2NyAyNi41MzYxLC05OS4xNjk0IDI2LjU3MTcsLTk5LjIwMDIgMjYuNjU1OCwtOTkuMjA4OSAyNi43MjQ4LC05OS4yNCAyNi43NDU5LC05OS4yNDI0IDI2Ljc4ODMsLTk5LjI2ODYgMjYuODQzMiwtOTkuMzI4OSAyNi44ODAyLC05OS4zMjE4IDI2LjkwNjgsLTk5LjM4ODMgMjYuOTQ0MiwtOTkuMzc3MyAyNi45NzM4LC05OS40MTU1IDI3LjAxNzIsLTk5LjQ0NjUgMjcuMDIzLC05OS40NTEgMjcuMDY2OCwtOTkuNDMwMyAyNy4wOTQ5LC05OS40Mzk2IDI3LjE1MjEsLTk5LjQyNjQgMjcuMTc4MywtOTkuNDUzOCAyNy4yNjUxLC05OS40OTY2IDI3LjI3MTcsLTk5LjQ5NSAyNy4zMDM5LC05OS41Mzc5IDI3LjMxNzUsLTk5LjUwNDQgMjcuMzM5OSwtOTkuNDgwNCAyNy40ODE2LC05OS41MjgzIDI3LjQ5ODksLTk5LjUxMTEgMjcuNTY0NSwtOTkuNTU2OCAyNy42MTQzLC05OS41OCAyNy42MDIzLC05OS41OTQgMjcuNjM4NiwtOTkuNjM4OSAyNy42MjY4LC05OS42OTEzIDI3LjY2ODcsLTk5LjcyODQgMjcuNjc5MywtOTkuNzcwNyAyNy43MzIxLC05OS44MzMxIDI3Ljc2MjksLTk5Ljg3MjMgMjcuNzk1MywtOTkuODgxMyAyNy44NDk2LC05OS45MDE1IDI3Ljg2NDIsLTk5LjkwMDEgMjcuOTEyMSwtOTkuOTM3MSAyNy45NDA1LC05OS45MzE4IDI3Ljk4MSwtOTkuOTg5OCAyNy45OTI5LC0xMDAuMDE5IDI4LjA2NjQsLTEwMC4wNTYxIDI4LjA5MTMsLTEwMC4wODY5IDI4LjE0NjgsLTEwMC4xNTkyIDI4LjE2NzYsLTEwMC4yMTIyIDI4LjE5NjgsLTEwMC4yMjM2IDI4LjIzNTIsLTEwMC4yNTc4IDI4LjI0MDMsLTEwMC4yOTM1IDI4LjI3ODUsLTEwMC4yODg2IDI4LjMxNywtMTAwLjM0OTMgMjguNDAxNCwtMTAwLjMzNjIgMjguNDMwMiwtMTAwLjM2ODIgMjguNDc4OSwtMTAwLjMzNDcgMjguNTAwMywtMTAwLjM4NyAyOC41MTQsLTEwMC40MTA0IDI4LjU1NDMsLTEwMC4zOTg1IDI4LjU4NTIsLTEwMC40NDc2IDI4LjYxMDEsLTEwMC40NDU3IDI4LjY0MDYsLTEwMC41MDA0IDI4LjY2MiwtMTAwLjUwNzYgMjguNzQwNiwtMTAwLjUzMzYgMjguNzYxMSwtMTAwLjU0NjYgMjguODI0OSwtMTAwLjU3MDUgMjguODI2MywtMTAwLjU5MTUgMjguODg5MywtMTAwLjY0ODggMjguOTQxLC0xMDAuNjQ1OSAyOC45ODY0LC0xMDAuNjY3NSAyOS4wODQzLC0xMDAuNzc1OSAyOS4xNzMzLC0xMDAuNzY1OSAyOS4xODc1LC0xMDAuNzk0OCAyOS4yNDE2LC0xMDAuODc2MSAyOS4yNzk2LC0xMDAuODg2OCAyOS4zMDc4LC0xMDAuOTUwNyAyOS4zNDc3LC0xMDEuMDA2NiAyOS4zNjYsLTEwMS4wNjAyIDI5LjQ1ODcsLTEwMS4xNTE5IDI5LjQ3NywtMTAxLjE3MzggMjkuNTE0NiwtMTAxLjI2MTIgMjkuNTM2OCwtMTAxLjI0MSAyOS41NjUsLTEwMS4yNjIyIDI5LjYzMDYsLTEwMS4yOTEgMjkuNTcxNSwtMTAxLjMxMTYgMjkuNTg1MSwtMTAxLjMgMjkuNjQwNywtMTAxLjMxNDEgMjkuNjU5MSwtMTAxLjM2MzIgMjkuNjUyNiwtMTAxLjM3NTQgMjkuNzAxOCwtMTAxLjQxNTYgMjkuNzQ2NSwtMTAxLjQ0ODkgMjkuNzUwNywtMTAxLjQ1NTggMjkuNzg4LC0xMDEuNTM5MiAyOS43NjE4LC0xMDEuNTQxOSAyOS44MTA4LC0xMDEuNTc1OCAyOS43NjkzLC0xMDEuNzEwNiAyOS43NjE3LC0xMDEuNzYwOSAyOS43ODIxLC0xMDEuODA2MiAyOS43ODA4LC0xMDEuODUzNCAyOS44MDc5LC0xMDEuOTMzNSAyOS43ODUxLC0xMDIuMDM4MyAyOS44MDMxLC0xMDIuMDQ5IDI5Ljc4NTYsLTEwMi4xMTYxIDI5Ljc5MjUsLTEwMi4xOTQ5IDI5LjgzNzEsLTEwMi4zMjA3IDI5Ljg3ODksLTEwMi4zNjQ4IDI5Ljg0NDMsLTEwMi4zODk3IDI5Ljc4MTksLTEwMi41MTc0IDI5Ljc4MzgsLTEwMi41NDggMjkuNzQ1LC0xMDIuNTcyNCAyOS43NTYxLC0xMDIuNjIzIDI5LjczNjQsLTEwMi42NzQ5IDI5Ljc0NDMsLTEwMi42OTM0IDI5LjY3NzIsLTEwMi43NDIyIDI5LjYzMDcsLTEwMi43NDUgMjkuNTkzMiwtMTAyLjc2ODMgMjkuNTk0NywtMTAyLjc3MTQgMjkuNTQ4OSwtMTAyLjgwODQgMjkuNTIyOSwtMTAyLjgzMSAyOS40NDQzLC0xMDIuODI0NyAyOS4zOTczLC0xMDIuODM5OSAyOS4zNjA2LC0xMDIuODc4NiAyOS4zNTM5LC0xMDIuOTAzMiAyOS4yNTQsLTEwMi44NzA2IDI5LjIzNjksLTEwMi44OTAxIDI5LjIwODgsLTEwMi45NTAyIDI5LjE3MzYsLTEwMi45NzM4IDI5LjE4NTUsLTEwMy4wMzI1IDI5LjEwNDcsLTEwMy4wNzUzIDI5LjA5MjMsLTEwMy4xMDA3IDI5LjA2MDIsLTEwMy4xMTUzIDI4Ljk4NTMsLTEwMy4xNTMzIDI4Ljk3MTgsLTEwMy4yMjc0IDI4Ljk5MTUsLTEwMy4yNzkyIDI4Ljk3NzcsLTEwMy4yOTg2IDI5LjAwNjgsLTEwMy40MzM3IDI5LjA0NSwtMTAzLjQ1MDYgMjkuMDcyOCwtMTAzLjU1NDUgMjkuMTU4NSwtMTAzLjcxOTIgMjkuMTgxNCwtMTAzLjc5MjcgMjkuMjYyMywtMTAzLjgxNDcgMjkuMjczOCwtMTAzLjk2OTYgMjkuMjk3OCwtMTA0LjAxOTkgMjkuMzEyMSwtMTA0LjEwNjUgMjkuMzczMSwtMTA0LjE2MyAyOS4zOTE5LC0xMDQuMjE3NSAyOS40NTU5LC0xMDQuMjA5IDI5LjQ4MSwtMTA0LjI2NDIgMjkuNTE0LC0xMDQuMzM4MSAyOS41MiwtMTA0LjQwMDYgMjkuNTczLC0xMDQuNDY2OSAyOS42MDk2LC0xMDQuNTQ0MiAyOS42ODE2LC0xMDQuNTY2MSAyOS43NzE0LC0xMDQuNjI5NSAyOS44NTIzLC0xMDQuNjgyNSAyOS45MzQ4LC0xMDQuNjc0IDI5Ljk1NjcsLTEwNC43MDYzIDMwLjA0OTcsLTEwNC42ODc5IDMwLjA3MzksLTEwNC42OTY2IDMwLjEzNDQsLTEwNC42ODcyIDMwLjE3OSwtMTA0LjcwNjggMzAuMjM1NCwtMTA0Ljc2MzIgMzAuMjc0NCwtMTA0Ljc3MzUgMzAuMzAyNywtMTA0LjgyMjYgMzAuMzUwMywtMTA0LjgxNjMgMzAuMzc0MywtMTA0Ljg1OTUgMzAuMzkxMSwtMTA0Ljg2OTQgMzAuNDc3MywtMTA0Ljg4MjQgMzAuNTMyMywtMTA0LjkxOSAzMC41OTc3LC0xMDQuOTcyMSAzMC42MTAzLC0xMDUuMDA2NSAzMC42ODU4LC0xMDUuMDYyNSAzMC42ODY2LC0xMDUuMTE4MSAzMC43NDk1LC0xMDUuMTYxNyAzMC43NTIxLC0xMDUuMjE3NyAzMC44MDYsLTEwNS4yNTYxIDMwLjc5NDUsLTEwNS4yOTE3IDMwLjgyNjEsLTEwNS4zNjE1IDMwLjg1MDMsLTEwNS4zOTU2IDMwLjg0OSwtMTA1LjQxMzUgMzAuODk5OCwtMTA1LjQ5ODggMzAuOTUwMywtMTA1LjU3ODYgMzEuMDIwNiwtMTA1LjU4NTEgMzEuMDU2OSwtMTA1LjY0NjcgMzEuMTEzOSwtMTA1Ljc3MzkgMzEuMTY4LC0xMDUuODE4OCAzMS4yMzA3LC0xMDUuODc0NyAzMS4yOTEzLC0xMDUuOTMxMiAzMS4zMTI3LC0xMDUuOTUzOSAzMS4zNjQ3LC0xMDYuMDE2MiAzMS4zOTM1LC0xMDYuMDc1MyAzMS4zOTc2LC0xMDYuMTkxMSAzMS40NTk5LC0xMDYuMjE5NiAzMS40ODE2LC0xMDYuMjQ1MiAzMS41MzkxLC0xMDYuMjgwMSAzMS41NjE1LC0xMDYuMzA3OSAzMS42Mjk1LC0xMDYuMzgxMSAzMS43MzIxLC0xMDYuNDUxNCAzMS43NjQ0LC0xMDYuNDkwNSAzMS43NDg5LC0xMDYuNTI4MiAzMS43ODMxLC0xMDYuNTQ3MSAzMS44MDczLC0xMDYuNjA1MyAzMS44Mjc3LC0xMDYuNjQ1NSAzMS44OTg3LC0xMDYuNjExOCAzMS45MiwtMTA2LjYxODUgMzIuMDAwNSwtMTA1Ljk5OCAzMi4wMDIzLC0xMDUuMjUwNSAzMi4wMDAzLC0xMDQuODQ3OCAzMi4wMDA1LC0xMDQuMDI0NSAzMiwtMTAzLjA2NDQgMzIuMDAwNSwtMTAzLjA2NDcgMzIuOTU5MSwtMTAzLjA1NjcgMzMuMzg4NCwtMTAzLjA0NCAzMy45NzQ2LC0xMDMuMDQyNCAzNS4xODMxLC0xMDMuMDQwOCAzNi4wNTUyLC0xMDMuMDQxOSAzNi41MDA0LC0xMDMuMDAyNCAzNi41MDA0LC0xMDIuMDMyMyAzNi41MDA2LC0xMDEuNjIzOSAzNi40OTk1LC0xMDEuMDg1MiAzNi40OTkyLC0xMDAuMDAwNCAzNi40OTk3LC0xMDAuMDAwNCAzNC43NDY1LC05OS45OTc1IDM0LjU2MDYsLTk5LjkyMzIgMzQuNTc0NiwtOTkuODQ0NiAzNC41MDY5LC05OS43NTM0IDM0LjQyMDksLTk5LjY5NDUgMzQuMzc4MiwtOTkuNiAzNC4zNzQ3LC05OS41Nzk4IDM0LjQxNjksLTk5LjUxNzYgMzQuNDE0NSwtOTkuNDMzNSAzNC4zNzAyLC05OS4zOTg3IDM0LjM3NTgsLTk5LjM5NTIgMzQuNDQyLC05OS4zNzU2IDM0LjQ1ODgsLTk5LjMyMDEgMzQuNDA5MywtOTkuMjYxMyAzNC40MDM1LC05OS4yMTA4IDM0LjMzNjgsLTk5LjE4OTggMzQuMjE0NCwtOTkuMDk1MyAzNC4yMTE4LC05OS4wNDM0IDM0LjE5ODIsLTk4Ljk5MTcgMzQuMjIxNCwtOTguOTUyNCAzNC4yMTI1LC05OC44NjAxIDM0LjE0OTksLTk4LjgzMTEgMzQuMTYyMiwtOTguNzY2NyAzNC4xMzY4LC05OC42OTAxIDM0LjEzMzIsLTk4LjY0ODEgMzQuMTY0NCwtOTguNjEwMiAzNC4xNTcxLC05OC41NjAyIDM0LjEzMzIsLTk4LjQ4NyAzNC4wNjI5LC05OC40MjM1IDM0LjA4MjgsLTk4LjM5ODQgMzQuMTI4NSwtOTguMzY0IDM0LjE1NzEsLTk4LjMwMDIgMzQuMTM0NiwtOTguMjMyNSAzNC4xMzQ2LC05OC4xNjg4IDM0LjExNDMsLTk4LjEzOTEgMzQuMTQxOSwtOTguMTAxOSAzNC4xNDY4LC05OC4wOTA1IDM0LjEyMjUsLTk4LjEyMDIgMzQuMDcyMSwtOTguMDgzOCAzNC4wNDE3LC05OC4wODQ0IDM0LjAwMjksLTk4LjAxNjMgMzMuOTk0MSwtOTcuOTc0MiAzNC4wMDY3LC05Ny45NDY4IDMzLjk5MDksLTk3Ljk3MTIgMzMuOTM3MiwtOTcuOTU3MiAzMy45MTQ1LC05Ny45Nzc5IDMzLjg4OTksLTk3Ljg3MTQgMzMuODQ5LC05Ny44MzQzIDMzLjg1NzcsLTk3Ljc2MyAzMy45MzQxLC05Ny43MzIzIDMzLjkzNjcsLTk3LjY4NzcgMzMuOTg3MiwtOTcuNjYxNSAzMy45OTA4LC05Ny41ODg4IDMzLjk1MTksLTk3LjU4OTMgMzMuOTAzOSwtOTcuNTYwOSAzMy44OTk2LC05Ny40ODQyIDMzLjkxNTQsLTk3LjQ1MTEgMzMuODkxNywtOTcuNDYyOSAzMy44NDI5LC05Ny40NDM5IDMzLjgyMzcsLTk3LjM3MjkgMzMuODE5NSwtOTcuMzMxOSAzMy44ODQ1LC05Ny4yNTU2IDMzLjg2MzcsLTk3LjI0NjIgMzMuOTAwMywtOTcuMjEwMyAzMy45MTU5LC05Ny4xODU1IDMzLjkwMDcsLTk3LjE2NjggMzMuODQwNCwtOTcuMTk3NCAzMy44Mjk4LC05Ny4xOTM0IDMzLjc2MDYsLTk3LjE1MTMgMzMuNzIyNiwtOTcuMTExMSAzMy43MTk0LC05Ny4wODg3IDMzLjczODcsLTk3LjA4OCAzMy44MDg3LC05Ny4wNDggMzMuODE3OSwtOTcuMDg3MyAzMy44Mzk4LC05Ny4wNTczIDMzLjg1NjksLTk3LjAyMzUgMzMuODQ0NSwtOTYuOTg1NiAzMy44ODY1LC05Ni45OTYzIDMzLjk0MjcsLTk2LjkzNDggMzMuOTU0NSwtOTYuODk5NCAzMy45MzM3LC05Ni44ODMgMzMuODY4LC05Ni44NTA2IDMzLjg0NzIsLTk2LjgzMjIgMzMuODc0OCwtOTYuNzc5NiAzMy44NTc5LC05Ni43Njk0IDMzLjgyNzUsLTk2LjcxMzcgMzMuODMxMywtOTYuNjkwNyAzMy44NSwtOTYuNjczNCAzMy45MTIzLC05Ni41ODg1IDMzLjg5NSwtOTYuNjI5IDMzLjg1MjQsLTk2LjU3MzIgMzMuODE5MiwtOTYuNTMyOSAzMy44MjMsLTk2LjUwMDcgMzMuNzcyNiwtOTYuNDIyNiAzMy43NzYsLTk2LjM3OTUgMzMuNzI1OCwtOTYuMzYyMiAzMy42OTE4LC05Ni4zMTg0IDMzLjY5NzEsLTk2LjMwMyAzMy43NTA5LC05Ni4yNzczIDMzLjc2OTcsLTk2LjIzMDQgMzMuNzQ4NSwtOTYuMTc4MSAzMy43NjA1LC05Ni4xNDkyIDMzLjgzNzEsLTk2LjEwMTUgMzMuODQ2NywtOTYuMDQ4OCAzMy44MzY1LC05NS45NDE5IDMzLjg2MSwtOTUuOTMyMSAzMy44ODY1LC05NS44NDMzIDMzLjgzODMsLTk1LjgwNDUgMzMuODYyMiwtOTUuNzY3OSAzMy44NDY4LC05NS43NTY2IDMzLjg5MiwtOTUuNjk0OSAzMy44ODY4LC05NS42Njg2IDMzLjkwNywtOTUuNjI3MyAzMy45MDc4LC05NS41OTc1IDMzLjk0MjMsLTk1LjU1NzcgMzMuOTMwNCwtOTUuNTQzNCAzMy44ODA1LC05NS40NTk4IDMzLjg4OCwtOTUuNDM4MiAzMy44NjcxLC05NS4zMTA1IDMzLjg3NzIsLTk1LjI4MjIgMzMuODc1OSwtOTUuMjcxNCAzMy45MTI2LC05NS4yMTk0IDMzLjk2MTYsLTk1LjE1NTkgMzMuOTM2OCwtOTUuMTI5NiAzMy45MzY3LC05NS4xMTc2IDMzLjkwNDYsLTk1LjA4MjQgMzMuODc5OSwtOTUuMDYwMSAzMy45MDE5LC05NS4wNDkgMzMuODY0MSwtOTQuOTY4OSAzMy44NjA5LC05NC45NTM1IDMzLjgxNjUsLTk0LjkyMzMgMzMuODA4NywtOTQuOTExNSAzMy43Nzg0LC05NC44NDkzIDMzLjczOTYsLTk0LjgyMzQgMzMuNzY5MiwtOTQuODAyMyAzMy43MzI4LC05NC43NzEzIDMzLjc2MDcsLTk0Ljc0NjEgMzMuNzAzLC05NC42ODQ4IDMzLjY4NDQsLTk0LjY2NzkgMzMuNjk0NiwtOTQuNjM5MiAzMy42NjM3LC05NC42MjE0IDMzLjY4MjYsLTk0LjU5MDggMzMuNjQ1NiwtOTQuNTQ2NCAzMy42NiwtOTQuNTIwNCAzMy42MTc1LC05NC40ODU5IDMzLjYzNzksLTk0LjM4OTUgMzMuNTQ2NywtOTQuMzUzNiAzMy41NDQsLTk0LjM0NTUgMzMuNTY3MywtOTQuMzA5NiAzMy41NTE3LC05NC4yNzU5IDMzLjU1OCwtOTQuMjE5MiAzMy41NTYxLC05NC4xODQzIDMzLjU5NDYsLTk0LjE0NzQgMzMuNTY1MiwtOTQuMDgyNCAzMy41NzU3LC05NC4wNDM0IDMzLjU1MjMsLTk0LjA0MyAzMy4wMTkyLC05NC4wNDI3IDMxLjk5OTMsLTk0LjAxNTYgMzEuOTc5OSwtOTMuOTcwOCAzMS45MiwtOTMuOTI5OSAzMS45MTI3LC05My44OTY3IDMxLjg4NTMsLTkzLjg3NDggMzEuODIyMywtOTMuODIyNiAzMS43NzM2LC05My44MzY5IDMxLjc1MDIsLTkzLjc5NDUgMzEuNzAyMSwtOTMuODIxNyAzMS42NzQsLTkzLjgxODcgMzEuNjE0NiwtOTMuODM0OSAzMS41ODYyLC05My43ODUgMzEuNTI2LC05My43MTI1IDMxLjUxMzQsLTkzLjc0OTUgMzEuNDY4NywtOTMuNjkyNiAzMS40MzcyLC05My43MDQ5IDMxLjQxMDksLTkzLjY3NDEgMzEuMzk3NywtOTMuNjY5MSAzMS4zNjU0LC05My42ODc1IDMxLjMxMDgsLTkzLjU5ODQgMzEuMjMxMSwtOTMuNjAwMyAzMS4xNzYyLC05My41NTI2IDMxLjE4NTYsLTkzLjUzOTQgMzEuMTE1MiwtOTMuNTYzMiAzMS4wOTcsLTkzLjUyNzYgMzEuMDc0NSwtOTMuNTA4OSAzMS4wMjkzLC05My41NTYzIDMxLjAwNDEsLTkzLjU2ODQgMzAuOTY5MSwtOTMuNTMyMSAzMC45NTc5LC05My41MjYzIDMwLjkyOTcsLTkzLjU1ODYgMzAuOTEzMiwtOTMuNTUzNiAzMC44MzUxLC05My42MTQ4IDMwLjc1NiwtOTMuNjA3NyAzMC43MTU2LC05My42MzE1IDMwLjY3OCwtOTMuNjgzMSAzMC42NDA4LC05My42Nzg4IDMwLjU5ODYsLTkzLjcyNzUgMzAuNTc0NywtOTMuNzMzOCAzMC41MzE3LC05My42OTc4IDMwLjQ0MzgsLTkzLjc0MTcgMzAuNDAyMywtOTMuNzYyMyAzMC4zNTM3LC05My43NDIxIDMwLjMwMSwtOTMuNzA0NyAzMC4yODk5LC05My43MDcgMzAuMjQzNywtOTMuNzIxIDMwLjIxMDQsLTkzLjY5MjggMzAuMTM1MiwtOTMuNzMyOCAzMC4wODI5LC05My43MjI1IDMwLjA1MDksLTkzLjc1NTEgMzAuMDE1MywtOTMuODcxNyAyOS45ODEsLTkzLjg2OTIgMjkuOTM4LC05My45NTA2IDI5Ljg0OTMsLTkzLjk0NjYgMjkuNzgwMSwtOTMuODM3NyAyOS42NzksLTk0LjAxNDMgMjkuNjc5OCwtOTQuMzU0MyAyOS41NjEsLTk0LjQ5OTEgMjkuNTA2OCwtOTQuNDcwMiAyOS41NTcxLC05NC41NDU5IDI5LjU3MjUsLTk0Ljc2MjUgMjkuNTI0MSwtOTQuNzAzOSAyOS42MzI1LC05NC42OTU3IDI5Ljc1NjUsLTk0LjczODkgMjkuNzkwNiwtOTQuODE0MSAyOS43NTksLTk0Ljg3MjggMjkuNjcxNCwtOTQuOTMwMyAyOS42NzM3LC05NS4wMTY2IDI5LjcyMDUsLTk1LjA3MjYgMjkuODI2MiwtOTUuMDk1NSAyOS43NTc2LC05NC45ODMzIDI5LjY4MjMsLTk0Ljk5ODUgMjkuNjE2NCwtOTUuMDc4OSAyOS41MzUzLC05NS4wMTcgMjkuNTQ4LC05NC45MDk2IDI5LjQ5NjEsLTk0Ljk1MDQgMjkuNDY2NywtOTQuODg1NCAyOS4zODk3LC05NS4wNTc0IDI5LjIwMTMsLTk1LjE0OTYgMjkuMTgwNSwtOTUuMjM0MiAyOC45OTI2LC05NS4zODU2IDI4Ljg2NDYsLTk1LjUwNzIgMjguODI1NCwtOTUuNjUzNyAyOC43NDk5LC05NS42NzI3IDI4Ljc0OTUsLTk1Ljc4NCAyOC42Nzk0LC05NS45MTQ5IDI4LjYzODgsLTk1LjY3NzYgMjguNzQ5NCwtOTUuNzg1MyAyOC43NDcxLC05NS45MjM2IDI4LjcwMTUsLTk1Ljk2MDggMjguNjE1MiwtOTYuMzM1NSAyOC40MzgxLC05Ni4xNDYzIDI4LjU0MjcsLTk1Ljk5MDYgMjguNjAxNiwtOTYuMDM4OCAyOC42NTI4LC05Ni4xNTI0IDI4LjYxMzUsLTk2LjIzNTQgMjguNjQyNywtOTYuMjA3OCAyOC42OTgxLC05Ni4zMjI5IDI4LjY0MTksLTk2LjM4NiAyOC42NzQ4LC05Ni40Mjg0IDI4LjcwNzEsLTk2LjQzNDggMjguNjAzLC05Ni41NjE1IDI4LjY0NTQsLTk2LjU3MzYgMjguNzA1NSwtOTYuNjU5NiAyOC43MjI2LC05Ni42NjE0IDI4LjcwMjYsLTk2LjYxMjEgMjguNjM5NCwtOTYuNjM4NSAyOC41NzE5LC05Ni41NjY3IDI4LjU4MjUsLTk2LjQxNTMgMjguNDYzNywtOTYuNDMyMiAyOC40MzI1LC05Ni42NTAzIDI4LjMzMjUsLTk2LjcwODQgMjguNDA3NSwtOTYuNzg1NyAyOC40NDc2LC05Ni43ODMyIDI4LjQwMDQsLTk2Ljg1ODkgMjguNDE3NiwtOTYuNzkwNSAyOC4zMTkyLC05Ni44MDk1IDI4LjIxOTksLTk2LjkxMTEgMjguMTM1NywtOTYuOTg2OCAyOC4xMjg3LC05Ny4wMzczIDI4LjIwMTMsLTk3LjI0MTUgMjguMDYyMywtOTcuMTUgMjguMDMzOCwtOTcuMTM1NCAyOC4wNDcyLC05Ny4wMjQ2IDI4LjExMzMsLTk3LjAzMSAyOC4wNDg2LC05Ny4xMzM4IDI3LjkwMDksLTk3LjE1NjkgMjcuODcyOCwtOTcuMjEzNCAyNy44MjEsLTk3LjI1MDEgMjcuODc2NCwtOTcuMzU0OCAyNy44NTAyLC05Ny4zMzEyIDI3Ljg3MzgsLTk3LjUyODEgMjcuODQ3NCwtOTcuMzgyOSAyNy44Mzg3LC05Ny4zNjE3IDI3LjczNTEsLTk3LjI0NSAyNy42OTMxLC05Ny4zMjQ4IDI3LjU2MSwtOTcuNDEyMyAyNy4zMjI0LC05Ny41MDExIDI3LjI5MTUsLTk3LjQ3MzcgMjcuNDAyOSwtOTcuNTMzOSAyNy4zMzk4LC05Ny42Mzc0IDI3LjMwMSwtOTcuNzM1MiAyNy40MTgyLC05Ny42NjE5IDI3LjI4NzUsLTk3Ljc5NjYgMjcuMjcyNiwtOTcuNjU3NCAyNy4yNzM3LC05Ny41MzQxIDI3LjIyNTMsLTk3LjQ0ODcgMjcuMjYzMSwtOTcuNDUxMSAyNy4xMjE2LC05Ny41MDUyIDI3LjA4NTYsLTk3LjQ3OSAyNi45OTkxLC05Ny41NjE0IDI2Ljk5OCwtOTcuNTYyOSAyNi44Mzg5LC05Ny40NzEgMjYuNzUwMSwtOTcuNDQ2NCAyNi41OTk5LC05Ny40MTc3IDI2LjM3MDIsLTk3LjM0MDYgMjYuMzMxOCwtOTcuMjk1NSAyNi4xOTA4LC05Ny4zMTIxIDI2LjEyMTYsLTk3LjIzNjUgMjYuMDY0NiwtOTcuMjUxNiAyNS45NjQzLC05Ny4xNTI3IDI2LjAyNzUsLTk3LjE0NjMgMjUuOTU1NikpLCgoLTk0LjUxMTcgMjkuNTE1OCwtOTQuNjU5MiAyOS40Mzc1LC05NC43MjgyIDI5LjM3MTYsLTk0Ljc3NzQgMjkuMzc1OSwtOTQuNjg1MiAyOS40NTEzLC05NC41MTE3IDI5LjUxNTgpKSwoKC05NC43NTE4IDI5LjMzMjksLTk0LjgwNDkgMjkuMjc4NywtOTUuMDU2MiAyOS4xMjk5LC05NC44NjEzIDI5LjI5NTMsLTk0Ljc1MTggMjkuMzMyOSkpLCgoLTk2LjgyMDEgMjguMTY0NSwtOTYuNzAzNyAyOC4xOTgsLTk2LjM4NzUgMjguMzc2MiwtOTYuNDQwMyAyOC4zMTg4LC05Ni42ODc4IDI4LjE4NTksLTk2Ljg0NzkgMjguMDY1MSwtOTYuODIwMSAyOC4xNjQ1KSksKCgtOTYuODcyMiAyOC4xMzE1LC05Ni44NSAyOC4wNjM4LC05Ny4wNTU0IDI3Ljg0NzIsLTk2Ljk2MzIgMjguMDIyOSwtOTYuODcyMiAyOC4xMzE1KSksKCgtOTcuMjk0MyAyNi42MDAzLC05Ny4zMjU0IDI2LjYwMDMsLTk3LjMwOTQgMjYuNjI5OCwtOTcuMzkyMSAyNi45MzY3LC05Ny4zOTE2IDI3LjEyNTgsLTk3LjM2NjEgMjcuMjc4MSwtOTcuMzcxMiAyNy4yNzgxLC05Ny4zMzAyIDI3LjQzNTIsLTk3LjI0NzIgMjcuNTgxNSwtOTcuMTk2NCAyNy42ODM3LC05Ny4wOTI1IDI3LjgxMTQsLTk3LjA0NDYgMjcuODM0NCwtOTcuMTUwNCAyNy43MDI3LC05Ny4yMjI3IDI3LjU3NjUsLTk3LjM0NzIgMjcuMjc4LC05Ny4zNzkzIDI3LjA0MDIsLTk3LjM3MDUgMjYuOTA4MSwtOTcuMjkwMSAyNi42MDAzLC05Ny4yOTQzIDI2LjYwMDMpKSkmcXVvdDs8L3ZhbHVlPgogICAgICAgICAgICAgIDx2YWx1ZT4zMS4yNTwvdmFsdWU-CiAgICAgICAgICAgICAgPHZhbHVlPi05OS4yNTwvdmFsdWU-CiAgICAgICAgICAgICAgPHZhbHVlPi0wLjE1MTE4MTkyNDU1MzI0NTk0PC92YWx1ZT4KICAgICAgICAgICAgPC90dXBsZT4KICAgICAgICAgIDwvdHVwbGUtcmVmZXJlbmNlPgogICAgICAgIDwvdHVwbGUtc2VsZWN0aW9uPgogICAgICA8L3NlbGVjdGlvbi1jb2xsZWN0aW9uPgogICAgPC93aW5kb3c-CiAgPC93aW5kb3dzPgo8L2N1c3RvbWl6ZWQtdmlldz4K" + }, + { + "isSourceView": false, + "viewName": "Product", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IGRhc2hib2FyZD0nUHJvZHVjdCcgc291cmNlLWJ1aWxkPScyMDI0LjIuMCAoMjAyNDIuMjQuMDcxNi4xOTQ0KScgdmVyc2lvbj0nMTguMScgeG1sbnM6dXNlcj0naHR0cDovL3d3dy50YWJsZWF1c29mdHdhcmUuY29tL3htbC91c2VyJz4KICA8YWN0aXZlIGlkPSctMScgLz4KICA8ZGF0YXNvdXJjZXM-CiAgICA8ZGF0YXNvdXJjZSBuYW1lPSdmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjaic-CiAgICAgIDxncm91cCBjYXB0aW9uPSdBY3Rpb24gKENhdGVnb3J5LFlFQVIoT3JkZXIgRGF0ZSksTU9OVEgoT3JkZXIgRGF0ZSkpJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKENhdGVnb3J5LFlFQVIoT3JkZXIgRGF0ZSksTU9OVEgoT3JkZXIgRGF0ZSkpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tDYXRlZ29yeV0nIC8-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbeXI6T3JkZXIgRGF0ZTpva10nIC8-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbbW46T3JkZXIgRGF0ZTpva10nIC8-CiAgICAgICAgPC9ncm91cGZpbHRlcj4KICAgICAgPC9ncm91cD4KICAgICAgPGNvbHVtbiBjYXB0aW9uPSdBY3Rpb24gKENhdGVnb3J5LFlFQVIoT3JkZXIgRGF0ZSksTU9OVEgoT3JkZXIgRGF0ZSkpJyBkYXRhdHlwZT0ndHVwbGUnIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoQ2F0ZWdvcnksWUVBUihPcmRlciBEYXRlKSxNT05USChPcmRlciBEYXRlKSldJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnIC8-CiAgICAgIDxncm91cCBjYXB0aW9uPSdBY3Rpb24gKFlFQVIoT3JkZXIgRGF0ZSksTU9OVEgoT3JkZXIgRGF0ZSkpJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKFlFQVIoT3JkZXIgRGF0ZSksTU9OVEgoT3JkZXIgRGF0ZSkpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1t5cjpPcmRlciBEYXRlOm9rXScgLz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1ttbjpPcmRlciBEYXRlOm9rXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoWUVBUihPcmRlciBEYXRlKSxNT05USChPcmRlciBEYXRlKSknIGRhdGF0eXBlPSd0dXBsZScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChZRUFSKE9yZGVyIERhdGUpLE1PTlRIKE9yZGVyIERhdGUpKV0nIHJvbGU9J2RpbWVuc2lvbicgdHlwZT0nbm9taW5hbCcgdXNlcjphdXRvLWNvbHVtbj0nc2hlZXRfbGluaycgLz4KICAgICAgPGdyb3VwIGNhcHRpb249J0FjdGlvbiAoWUVBUihPcmRlciBEYXRlKSxNT05USChPcmRlciBEYXRlKSxQcm9kdWN0IENhdGVnb3J5KScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChZRUFSKE9yZGVyIERhdGUpLE1PTlRIKE9yZGVyIERhdGUpLFByb2R1Y3QgQ2F0ZWdvcnkpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1t5cjpPcmRlciBEYXRlOm9rXScgLz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1ttbjpPcmRlciBEYXRlOm9rXScgLz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tub25lOkNhdGVnb3J5Om5rXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoWUVBUihPcmRlciBEYXRlKSxNT05USChPcmRlciBEYXRlKSxQcm9kdWN0IENhdGVnb3J5KScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKFlFQVIoT3JkZXIgRGF0ZSksTU9OVEgoT3JkZXIgRGF0ZSksUHJvZHVjdCBDYXRlZ29yeSldJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J01vbnRoJyBuYW1lPSdbbW46T3JkZXIgRGF0ZTpva10nIHBpdm90PSdrZXknIHR5cGU9J29yZGluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbQ2F0ZWdvcnldJyBkZXJpdmF0aW9uPSdOb25lJyBuYW1lPSdbbm9uZTpDYXRlZ29yeTpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOk9yZGVyIERhdGU6cWtdJyBwaXZvdD0na2V5JyB0eXBlPSdxdWFudGl0YXRpdmUnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbUmVnaW9uXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6UmVnaW9uOm5rXScgcGl2b3Q9J2tleScgdHlwZT0nbm9taW5hbCcgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tPcmRlciBEYXRlXScgZGVyaXZhdGlvbj0nWWVhcicgbmFtZT0nW3lyOk9yZGVyIERhdGU6b2tdJyBwaXZvdD0na2V5JyB0eXBlPSdvcmRpbmFsJyAvPgogICAgPC9kYXRhc291cmNlPgogIDwvZGF0YXNvdXJjZXM-CiAgPHdvcmtzaGVldCBuYW1lPSdQcm9kdWN0Vmlldyc-CiAgICA8dGFibGUgLz4KICA8L3dvcmtzaGVldD4KICA8d29ya3NoZWV0IG5hbWU9J1Byb2R1Y3REZXRhaWxzJz4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0Pgo8L2N1c3RvbWl6ZWQtdmlldz4K" + }, + { + "isSourceView": false, + "viewName": "Customers", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IGRhc2hib2FyZD0nQ3VzdG9tZXJzJyBzb3VyY2UtYnVpbGQ9JzIwMjQuMi4wICgyMDI0Mi4yNC4wNzE2LjE5NDQpJyB2ZXJzaW9uPScxOC4xJyB4bWxuczp1c2VyPSdodHRwOi8vd3d3LnRhYmxlYXVzb2Z0d2FyZS5jb20veG1sL3VzZXInPgogIDxhY3RpdmUgaWQ9Jy0xJyAvPgogIDxkYXRhc291cmNlcz4KICAgIDxkYXRhc291cmNlIG5hbWU9J2ZlZGVyYXRlZC4xMG5uazhkMXZnbXc4cTE3eXU3NnUwNnBuYmNqJz4KICAgICAgPGNvbHVtbiBkYXRhdHlwZT0nc3RyaW5nJyBuYW1lPSdbOk1lYXN1cmUgTmFtZXNdJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnPgogICAgICAgIDxhbGlhc2VzPgogICAgICAgICAgPGFsaWFzIGtleT0nJnF1b3Q7W2ZlZGVyYXRlZC4xMG5uazhkMXZnbXc4cTE3eXU3NnUwNnBuYmNqXS5bY3RkOkN1c3RvbWVyIE5hbWU6cWtdJnF1b3Q7JyB2YWx1ZT0nQ291bnQgb2YgQ3VzdG9tZXJzJyAvPgogICAgICAgIDwvYWxpYXNlcz4KICAgICAgPC9jb2x1bW4-CiAgICAgIDxncm91cCBjYXB0aW9uPSdBY3Rpb24gKFJlZ2lvbiknIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoUmVnaW9uKV0nIG5hbWUtc3R5bGU9J3VucXVhbGlmaWVkJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJz4KICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2Nyb3Nzam9pbic-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbUmVnaW9uXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoUmVnaW9uKScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKFJlZ2lvbildJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbQ2F0ZWdvcnldJyBkZXJpdmF0aW9uPSdOb25lJyBuYW1lPSdbbm9uZTpDYXRlZ29yeTpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOk9yZGVyIERhdGU6cWtdJyBwaXZvdD0na2V5JyB0eXBlPSdxdWFudGl0YXRpdmUnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbUmVnaW9uXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6UmVnaW9uOm5rXScgcGl2b3Q9J2tleScgdHlwZT0nbm9taW5hbCcgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tTZWdtZW50XScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6U2VnbWVudDpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J1F1YXJ0ZXInIG5hbWU9J1txcjpPcmRlciBEYXRlOm9rXScgcGl2b3Q9J2tleScgdHlwZT0nb3JkaW5hbCcgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tPcmRlciBEYXRlXScgZGVyaXZhdGlvbj0nWWVhcicgbmFtZT0nW3lyOk9yZGVyIERhdGU6b2tdJyBwaXZvdD0na2V5JyB0eXBlPSdvcmRpbmFsJyAvPgogICAgPC9kYXRhc291cmNlPgogIDwvZGF0YXNvdXJjZXM-CiAgPHdvcmtzaGVldCBuYW1lPSdDdXN0b21lclNjYXR0ZXInPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CiAgPHdvcmtzaGVldCBuYW1lPSdDdXN0b21lclJhbmsnPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CiAgPHdvcmtzaGVldCBuYW1lPSdDdXN0b21lck92ZXJ2aWV3Jz4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0Pgo8L2N1c3RvbWl6ZWQtdmlldz4K" + }, + { + "isSourceView": false, + "viewName": "Shipping", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IGRhc2hib2FyZD0nU2hpcHBpbmcnIHNvdXJjZS1idWlsZD0nMjAyNC4yLjAgKDIwMjQyLjI0LjA3MTYuMTk0NCknIHZlcnNpb249JzE4LjEnIHhtbG5zOnVzZXI9J2h0dHA6Ly93d3cudGFibGVhdXNvZnR3YXJlLmNvbS94bWwvdXNlcic-CiAgPGFjdGl2ZSBpZD0nLTEnIC8-CiAgPGRhdGFzb3VyY2VzPgogICAgPGRhdGFzb3VyY2UgbmFtZT0nZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2onPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChEZWxheWVkPyknIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoRGVsYXllZD8pXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tDYWxjdWxhdGlvbl82NDAxMTAzMTcxMjU5NzIzXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoRGVsYXllZD8pJyBkYXRhdHlwZT0ndHVwbGUnIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoRGVsYXllZD8pXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJyAvPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChTaGlwIFN0YXR1cyknIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoU2hpcCBTdGF0dXMpXScgbmFtZS1zdHlsZT0ndW5xdWFsaWZpZWQnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnPgogICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nY3Jvc3Nqb2luJz4KICAgICAgICAgIDxncm91cGZpbHRlciBmdW5jdGlvbj0nbGV2ZWwtbWVtYmVycycgbGV2ZWw9J1tDYWxjdWxhdGlvbl82NDAxMTAzMTcxMjU5NzIzXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoU2hpcCBTdGF0dXMpJyBkYXRhdHlwZT0ndHVwbGUnIGhpZGRlbj0ndHJ1ZScgbmFtZT0nW0FjdGlvbiAoU2hpcCBTdGF0dXMpXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJyAvPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChTaGlwIFN0YXR1cyxZRUFSKE9yZGVyIERhdGUpLFdFRUsoT3JkZXIgRGF0ZSkpJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKFNoaXAgU3RhdHVzLFlFQVIoT3JkZXIgRGF0ZSksV0VFSyhPcmRlciBEYXRlKSldJyBuYW1lLXN0eWxlPSd1bnF1YWxpZmllZCcgdXNlcjphdXRvLWNvbHVtbj0nc2hlZXRfbGluayc-CiAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdjcm9zc2pvaW4nPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW0NhbGN1bGF0aW9uXzY0MDExMDMxNzEyNTk3MjNdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW3lyOk9yZGVyIERhdGU6b2tdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW3R3azpPcmRlciBEYXRlOm9rXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoU2hpcCBTdGF0dXMsWUVBUihPcmRlciBEYXRlKSxXRUVLKE9yZGVyIERhdGUpKScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKFNoaXAgU3RhdHVzLFlFQVIoT3JkZXIgRGF0ZSksV0VFSyhPcmRlciBEYXRlKSldJyByb2xlPSdkaW1lbnNpb24nIHR5cGU9J25vbWluYWwnIHVzZXI6YXV0by1jb2x1bW49J3NoZWV0X2xpbmsnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbQ2FsY3VsYXRpb25fNjQwMTEwMzE3MTI1OTcyM10nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOkNhbGN1bGF0aW9uXzY0MDExMDMxNzEyNTk3MjM6bmtdJyBwaXZvdD0na2V5JyB0eXBlPSdub21pbmFsJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW1JlZ2lvbl0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOlJlZ2lvbjpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbU2hpcCBNb2RlXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6U2hpcCBNb2RlOm5rXScgcGl2b3Q9J2tleScgdHlwZT0nbm9taW5hbCcgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tPcmRlciBEYXRlXScgZGVyaXZhdGlvbj0nUXVhcnRlcicgbmFtZT0nW3FyOk9yZGVyIERhdGU6b2tdJyBwaXZvdD0na2V5JyB0eXBlPSdvcmRpbmFsJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW09yZGVyIERhdGVdJyBkZXJpdmF0aW9uPSdZZWFyJyBuYW1lPSdbeXI6T3JkZXIgRGF0ZTpva10nIHBpdm90PSdrZXknIHR5cGU9J29yZGluYWwnIC8-CiAgICA8L2RhdGFzb3VyY2U-CiAgPC9kYXRhc291cmNlcz4KICA8d29ya3NoZWV0IG5hbWU9J1NoaXBTdW1tYXJ5Jz4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0PgogIDx3b3Jrc2hlZXQgbmFtZT0nU2hpcHBpbmdUcmVuZCc-CiAgICA8dGFibGUgLz4KICA8L3dvcmtzaGVldD4KICA8d29ya3NoZWV0IG5hbWU9J0RheXN0b1NoaXAnPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CjwvY3VzdG9taXplZC12aWV3Pgo=" + }, + { + "isSourceView": false, + "viewName": "Performance", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IHNvdXJjZS1idWlsZD0nMjAyNC4yLjAgKDIwMjQyLjI0LjA3MTYuMTk0NCknIHZlcnNpb249JzE4LjEnIHhtbG5zOnVzZXI9J2h0dHA6Ly93d3cudGFibGVhdXNvZnR3YXJlLmNvbS94bWwvdXNlcic-CiAgPGRhdGFzb3VyY2VzPgogICAgPGRhdGFzb3VyY2UgbmFtZT0nZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2onPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW1JlZ2lvbl0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOlJlZ2lvbjpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J1llYXInIG5hbWU9J1t5cjpPcmRlciBEYXRlOm9rXScgcGl2b3Q9J2tleScgdHlwZT0nb3JkaW5hbCcgLz4KICAgIDwvZGF0YXNvdXJjZT4KICA8L2RhdGFzb3VyY2VzPgogIDx3b3Jrc2hlZXQgbmFtZT0nUGVyZm9ybWFuY2UnPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CjwvY3VzdG9taXplZC12aWV3Pgo=" + }, + { + "isSourceView": false, + "viewName": "Commission Model", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IGRhc2hib2FyZD0nQ29tbWlzc2lvbiBNb2RlbCcgc291cmNlLWJ1aWxkPScyMDI0LjIuMCAoMjAyNDIuMjQuMDcxNi4xOTQ0KScgdmVyc2lvbj0nMTguMScgeG1sbnM6dXNlcj0naHR0cDovL3d3dy50YWJsZWF1c29mdHdhcmUuY29tL3htbC91c2VyJz4KICA8YWN0aXZlIGlkPSctMScgLz4KICA8ZGF0YXNvdXJjZXM-CiAgICA8ZGF0YXNvdXJjZSBuYW1lPSdmZWRlcmF0ZWQuMGEwMWNvZDFveGw4M2wxZjV5dmVzMWNmY2lxbyc-CiAgICAgIDxjb2x1bW4gZGF0YXR5cGU9J3N0cmluZycgbmFtZT0nWzpNZWFzdXJlIE5hbWVzXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyAvPgogICAgPC9kYXRhc291cmNlPgogIDwvZGF0YXNvdXJjZXM-CiAgPHdvcmtzaGVldCBuYW1lPSdRdW90YUF0dGFpbm1lbnQnPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CiAgPHdvcmtzaGVldCBuYW1lPSdDb21taXNzaW9uUHJvamVjdGlvbic-CiAgICA8dGFibGUgLz4KICA8L3dvcmtzaGVldD4KICA8d29ya3NoZWV0IG5hbWU9J1NhbGVzJz4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0PgogIDx3b3Jrc2hlZXQgbmFtZT0nT1RFJz4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0Pgo8L2N1c3RvbWl6ZWQtdmlldz4K" + }, + { + "isSourceView": false, + "viewName": "Order Details", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IGRhc2hib2FyZD0nT3JkZXIgRGV0YWlscycgc291cmNlLWJ1aWxkPScyMDI0LjIuMCAoMjAyNDIuMjQuMDcxNi4xOTQ0KScgdmVyc2lvbj0nMTguMScgeG1sbnM6dXNlcj0naHR0cDovL3d3dy50YWJsZWF1c29mdHdhcmUuY29tL3htbC91c2VyJz4KICA8YWN0aXZlIGlkPSctMScgLz4KICA8ZGF0YXNvdXJjZXM-CiAgICA8ZGF0YXNvdXJjZSBuYW1lPSdmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjaic-CiAgICAgIDxjb2x1bW4gZGF0YXR5cGU9J3N0cmluZycgbmFtZT0nWzpNZWFzdXJlIE5hbWVzXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJz4KICAgICAgICA8YWxpYXNlcz4KICAgICAgICAgIDxhbGlhcyBrZXk9JyZxdW90O1tmZWRlcmF0ZWQuMTBubms4ZDF2Z213OHExN3l1NzZ1MDZwbmJjal0uW2N0ZDpDdXN0b21lciBOYW1lOnFrXSZxdW90OycgdmFsdWU9J0NvdW50IG9mIEN1c3RvbWVycycgLz4KICAgICAgICA8L2FsaWFzZXM-CiAgICAgIDwvY29sdW1uPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChPcmRlciBQcm9maXRhYmxlPyxNT05USChPcmRlciBEYXRlKSxTZWdtZW50KScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChPcmRlciBQcm9maXRhYmxlPyxNT05USChPcmRlciBEYXRlKSxTZWdtZW50KV0nIG5hbWUtc3R5bGU9J3VucXVhbGlmaWVkJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJz4KICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2Nyb3Nzam9pbic-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbQ2FsY3VsYXRpb25fOTA2MDEyMjEwNDk0NzQ3MV0nIC8-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbdG1uOk9yZGVyIERhdGU6b2tdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW1NlZ21lbnRdJyAvPgogICAgICAgIDwvZ3JvdXBmaWx0ZXI-CiAgICAgIDwvZ3JvdXA-CiAgICAgIDxjb2x1bW4gY2FwdGlvbj0nQWN0aW9uIChPcmRlciBQcm9maXRhYmxlPyxNT05USChPcmRlciBEYXRlKSxTZWdtZW50KScgZGF0YXR5cGU9J3R1cGxlJyBoaWRkZW49J3RydWUnIG5hbWU9J1tBY3Rpb24gKE9yZGVyIFByb2ZpdGFibGU_LE1PTlRIKE9yZGVyIERhdGUpLFNlZ21lbnQpXScgcm9sZT0nZGltZW5zaW9uJyB0eXBlPSdub21pbmFsJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJyAvPgogICAgICA8Z3JvdXAgY2FwdGlvbj0nQWN0aW9uIChQb3N0YWwgQ29kZSxTdGF0ZS9Qcm92aW5jZSkgMScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChQb3N0YWwgQ29kZSxTdGF0ZS9Qcm92aW5jZSkgMV0nIG5hbWUtc3R5bGU9J3VucXVhbGlmaWVkJyB1c2VyOmF1dG8tY29sdW1uPSdzaGVldF9saW5rJz4KICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2Nyb3Nzam9pbic-CiAgICAgICAgICA8Z3JvdXBmaWx0ZXIgZnVuY3Rpb249J2xldmVsLW1lbWJlcnMnIGxldmVsPSdbUG9zdGFsIENvZGVdJyAvPgogICAgICAgICAgPGdyb3VwZmlsdGVyIGZ1bmN0aW9uPSdsZXZlbC1tZW1iZXJzJyBsZXZlbD0nW1N0YXRlL1Byb3ZpbmNlXScgLz4KICAgICAgICA8L2dyb3VwZmlsdGVyPgogICAgICA8L2dyb3VwPgogICAgICA8Y29sdW1uIGNhcHRpb249J0FjdGlvbiAoUG9zdGFsIENvZGUsU3RhdGUvUHJvdmluY2UpIDEnIGRhdGF0eXBlPSd0dXBsZScgaGlkZGVuPSd0cnVlJyBuYW1lPSdbQWN0aW9uIChQb3N0YWwgQ29kZSxTdGF0ZS9Qcm92aW5jZSkgMV0nIHJvbGU9J2RpbWVuc2lvbicgdHlwZT0nbm9taW5hbCcgdXNlcjphdXRvLWNvbHVtbj0nc2hlZXRfbGluaycgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tDYXRlZ29yeV0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOkNhdGVnb3J5Om5rXScgcGl2b3Q9J2tleScgdHlwZT0nbm9taW5hbCcgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tDaXR5XScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6Q2l0eTpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbT3JkZXIgRGF0ZV0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOk9yZGVyIERhdGU6b2tdJyBwaXZvdD0na2V5JyB0eXBlPSdvcmRpbmFsJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW09yZGVyIERhdGVdJyBkZXJpdmF0aW9uPSdOb25lJyBuYW1lPSdbbm9uZTpPcmRlciBEYXRlOnFrXScgcGl2b3Q9J2tleScgdHlwZT0ncXVhbnRpdGF0aXZlJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW1JlZ2lvbl0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOlJlZ2lvbjpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICAgIDxjb2x1bW4taW5zdGFuY2UgY29sdW1uPSdbU2VnbWVudF0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOlNlZ21lbnQ6bmtdJyBwaXZvdD0na2V5JyB0eXBlPSdub21pbmFsJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW1N0YXRlL1Byb3ZpbmNlXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6U3RhdGUvUHJvdmluY2U6bmtdJyBwaXZvdD0na2V5JyB0eXBlPSdub21pbmFsJyAvPgogICAgPC9kYXRhc291cmNlPgogIDwvZGF0YXNvdXJjZXM-CiAgPHdvcmtzaGVldCBuYW1lPSdQcm9kdWN0IERldGFpbCBTaGVldCc-CiAgICA8dGFibGUgLz4KICA8L3dvcmtzaGVldD4KPC9jdXN0b21pemVkLXZpZXc-Cg==" + }, + { + "isSourceView": false, + "viewName": "Forecast", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IHNvdXJjZS1idWlsZD0nMjAyNC4yLjAgKDIwMjQyLjI0LjA3MTYuMTk0NCknIHZlcnNpb249JzE4LjEnIHhtbG5zOnVzZXI9J2h0dHA6Ly93d3cudGFibGVhdXNvZnR3YXJlLmNvbS94bWwvdXNlcic-CiAgPGRhdGFzb3VyY2VzPgogICAgPGRhdGFzb3VyY2UgbmFtZT0nZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2onPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW09yZGVyIERhdGVdJyBkZXJpdmF0aW9uPSdOb25lJyBuYW1lPSdbbm9uZTpPcmRlciBEYXRlOnFrXScgcGl2b3Q9J2tleScgdHlwZT0ncXVhbnRpdGF0aXZlJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW1JlZ2lvbl0nIGRlcml2YXRpb249J05vbmUnIG5hbWU9J1tub25lOlJlZ2lvbjpua10nIHBpdm90PSdrZXknIHR5cGU9J25vbWluYWwnIC8-CiAgICA8L2RhdGFzb3VyY2U-CiAgPC9kYXRhc291cmNlcz4KICA8d29ya3NoZWV0IG5hbWU9J0ZvcmVjYXN0Jz4KICAgIDx0YWJsZSAvPgogIDwvd29ya3NoZWV0Pgo8L2N1c3RvbWl6ZWQtdmlldz4K" + }, + { + "isSourceView": false, + "viewName": "What If Forecast", + "tcv": "PD94bWwgdmVyc2lvbj0nMS4wJyBlbmNvZGluZz0ndXRmLTgnID8-Cgo8Y3VzdG9taXplZC12aWV3IHNvdXJjZS1idWlsZD0nMjAyNC4yLjAgKDIwMjQyLjI0LjA3MTYuMTk0NCknIHZlcnNpb249JzE4LjEnIHhtbG5zOnVzZXI9J2h0dHA6Ly93d3cudGFibGVhdXNvZnR3YXJlLmNvbS94bWwvdXNlcic-CiAgPGRhdGFzb3VyY2VzPgogICAgPGRhdGFzb3VyY2UgbmFtZT0nZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2onPgogICAgICA8Y29sdW1uIGRhdGF0eXBlPSdzdHJpbmcnIG5hbWU9J1s6TWVhc3VyZSBOYW1lc10nIHJvbGU9J2RpbWVuc2lvbicgdHlwZT0nbm9taW5hbCc-CiAgICAgICAgPGFsaWFzZXM-CiAgICAgICAgICA8YWxpYXMga2V5PScmcXVvdDtbZmVkZXJhdGVkLjEwbm5rOGQxdmdtdzhxMTd5dTc2dTA2cG5iY2pdLltjdGQ6Q3VzdG9tZXIgTmFtZTpxa10mcXVvdDsnIHZhbHVlPSdDb3VudCBvZiBDdXN0b21lcnMnIC8-CiAgICAgICAgPC9hbGlhc2VzPgogICAgICA8L2NvbHVtbj4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tPcmRlciBEYXRlXScgZGVyaXZhdGlvbj0nTm9uZScgbmFtZT0nW25vbmU6T3JkZXIgRGF0ZTpxa10nIHBpdm90PSdrZXknIHR5cGU9J3F1YW50aXRhdGl2ZScgLz4KICAgICAgPGNvbHVtbi1pbnN0YW5jZSBjb2x1bW49J1tSZWdpb25dJyBkZXJpdmF0aW9uPSdOb25lJyBuYW1lPSdbbm9uZTpSZWdpb246bmtdJyBwaXZvdD0na2V5JyB0eXBlPSdub21pbmFsJyAvPgogICAgICA8Y29sdW1uLWluc3RhbmNlIGNvbHVtbj0nW09yZGVyIERhdGVdJyBkZXJpdmF0aW9uPSdZZWFyJyBuYW1lPSdbeXI6T3JkZXIgRGF0ZTpva10nIHBpdm90PSdrZXknIHR5cGU9J29yZGluYWwnIC8-CiAgICA8L2RhdGFzb3VyY2U-CiAgPC9kYXRhc291cmNlcz4KICA8d29ya3NoZWV0IG5hbWU9J1doYXQgSWYgRm9yZWNhc3QnPgogICAgPHRhYmxlIC8-CiAgPC93b3Jrc2hlZXQ-CjwvY3VzdG9taXplZC12aWV3Pgo=" + } +] \ No newline at end of file diff --git a/test/test_custom_view.py b/test/test_custom_view.py index 55dec5df..80800c86 100644 --- a/test/test_custom_view.py +++ b/test/test_custom_view.py @@ -1,23 +1,32 @@ +from contextlib import ExitStack +import io import os +from pathlib import Path +from tempfile import TemporaryDirectory import unittest import requests_mock import tableauserverclient as TSC +from tableauserverclient.config import BYTES_PER_MB from tableauserverclient.datetime_helpers import format_datetime +from tableauserverclient.server.endpoint.exceptions import MissingRequiredFieldError -TEST_ASSET_DIR = os.path.join(os.path.dirname(__file__), "assets") +TEST_ASSET_DIR = Path(__file__).parent / "assets" GET_XML = os.path.join(TEST_ASSET_DIR, "custom_view_get.xml") GET_XML_ID = os.path.join(TEST_ASSET_DIR, "custom_view_get_id.xml") POPULATE_PREVIEW_IMAGE = os.path.join(TEST_ASSET_DIR, "Sample View Image.png") CUSTOM_VIEW_UPDATE_XML = os.path.join(TEST_ASSET_DIR, "custom_view_update.xml") +CUSTOM_VIEW_DOWNLOAD = TEST_ASSET_DIR / "custom_view_download.json" +FILE_UPLOAD_INIT = TEST_ASSET_DIR / "fileupload_initialize.xml" +FILE_UPLOAD_APPEND = TEST_ASSET_DIR / "fileupload_append.xml" class CustomViewTests(unittest.TestCase): def setUp(self): self.server = TSC.Server("http://test", False) - self.server.version = "3.19" # custom views only introduced in 3.19 + self.server.version = "3.21" # custom views only introduced in 3.19 # Fake sign in self.server._site_id = "dad65087-b08b-4603-af4e-2887b8aafc67" @@ -132,3 +141,108 @@ def test_update(self) -> None: def test_update_missing_id(self) -> None: cv = TSC.CustomViewItem(name="test") self.assertRaises(TSC.MissingRequiredFieldError, self.server.custom_views.update, cv) + + def test_download(self) -> None: + cv = TSC.CustomViewItem(name="test") + cv._id = "1f951daf-4061-451a-9df1-69a8062664f2" + content = CUSTOM_VIEW_DOWNLOAD.read_bytes() + data = io.BytesIO() + with requests_mock.mock() as m: + m.get(f"{self.server.custom_views.expurl}/1f951daf-4061-451a-9df1-69a8062664f2/content", content=content) + self.server.custom_views.download(cv, data) + + assert data.getvalue() == content + + def test_publish_filepath(self) -> None: + cv = TSC.CustomViewItem(name="test") + cv._owner = TSC.UserItem() + cv._owner._id = "dd2239f6-ddf1-4107-981a-4cf94e415794" + cv._workbook = TSC.WorkbookItem() + cv._workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2" + with requests_mock.mock() as m: + m.post(self.server.custom_views.expurl, status_code=201, text=Path(GET_XML).read_text()) + view = self.server.custom_views.publish(cv, CUSTOM_VIEW_DOWNLOAD) + + assert view is not None + assert isinstance(view, TSC.CustomViewItem) + assert view.id is not None + assert view.name is not None + + def test_publish_file_str(self) -> None: + cv = TSC.CustomViewItem(name="test") + cv._owner = TSC.UserItem() + cv._owner._id = "dd2239f6-ddf1-4107-981a-4cf94e415794" + cv._workbook = TSC.WorkbookItem() + cv._workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2" + with requests_mock.mock() as m: + m.post(self.server.custom_views.expurl, status_code=201, text=Path(GET_XML).read_text()) + view = self.server.custom_views.publish(cv, str(CUSTOM_VIEW_DOWNLOAD)) + + assert view is not None + assert isinstance(view, TSC.CustomViewItem) + assert view.id is not None + assert view.name is not None + + def test_publish_file_io(self) -> None: + cv = TSC.CustomViewItem(name="test") + cv._owner = TSC.UserItem() + cv._owner._id = "dd2239f6-ddf1-4107-981a-4cf94e415794" + cv._workbook = TSC.WorkbookItem() + cv._workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2" + data = io.BytesIO(CUSTOM_VIEW_DOWNLOAD.read_bytes()) + with requests_mock.mock() as m: + m.post(self.server.custom_views.expurl, status_code=201, text=Path(GET_XML).read_text()) + view = self.server.custom_views.publish(cv, data) + + assert view is not None + assert isinstance(view, TSC.CustomViewItem) + assert view.id is not None + assert view.name is not None + + def test_publish_missing_owner_id(self) -> None: + cv = TSC.CustomViewItem(name="test") + cv._owner = TSC.UserItem() + cv._workbook = TSC.WorkbookItem() + cv._workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2" + with requests_mock.mock() as m: + m.post(self.server.custom_views.expurl, status_code=201, text=Path(GET_XML).read_text()) + with self.assertRaises(ValueError): + self.server.custom_views.publish(cv, CUSTOM_VIEW_DOWNLOAD) + + def test_publish_missing_wb_id(self) -> None: + cv = TSC.CustomViewItem(name="test") + cv._owner = TSC.UserItem() + cv._owner._id = "dd2239f6-ddf1-4107-981a-4cf94e415794" + cv._workbook = TSC.WorkbookItem() + with requests_mock.mock() as m: + m.post(self.server.custom_views.expurl, status_code=201, text=Path(GET_XML).read_text()) + with self.assertRaises(ValueError): + self.server.custom_views.publish(cv, CUSTOM_VIEW_DOWNLOAD) + + def test_large_publish(self): + cv = TSC.CustomViewItem(name="test") + cv._owner = TSC.UserItem() + cv._owner._id = "dd2239f6-ddf1-4107-981a-4cf94e415794" + cv._workbook = TSC.WorkbookItem() + cv._workbook._id = "1f951daf-4061-451a-9df1-69a8062664f2" + with ExitStack() as stack: + temp_dir = stack.enter_context(TemporaryDirectory()) + file_path = Path(temp_dir) / "test_file" + file_path.write_bytes(os.urandom(65 * BYTES_PER_MB)) + mock = stack.enter_context(requests_mock.mock()) + # Mock initializing upload + mock.post(self.server.fileuploads.baseurl, status_code=201, text=FILE_UPLOAD_INIT.read_text()) + # Mock the upload + mock.put( + f"{self.server.fileuploads.baseurl}/7720:170fe6b1c1c7422dadff20f944d58a52-1:0", + text=FILE_UPLOAD_APPEND.read_text(), + ) + # Mock the publish + mock.post(self.server.custom_views.expurl, status_code=201, text=Path(GET_XML).read_text()) + + view = self.server.custom_views.publish(cv, file_path) + + assert view is not None + assert isinstance(view, TSC.CustomViewItem) + assert view.id is not None + assert view.name is not None