[Attachment Support] Don't Blob-convert images and attachments with https:, http...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Jan 2018 00:06:41 +0000 (00:06 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 3 Jan 2018 00:06:41 +0000 (00:06 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181143
<rdar://problem/36200381>

Reviewed by Tim Horton.

Source/WebCore:

Clients such as Mail would expect pasting or dropping an image with src="https://..." to result in the source
URL being preserved (i.e. staying as remote images) instead of creating image attachments out of them. This
patch hooks into the shouldConvertToBlob() check added in r226272 so that it applies to attachment element
replacement as well.

Test: WKAttachmentTests.DoNotInsertDataURLImagesAsAttachments

* editing/cocoa/WebContentReaderCocoa.mm:
(WebCore::shouldConvertToBlob):
(WebCore::replaceRichContentWithAttachments):

Tools:

Add a new API test to ensure that a copied image with a data URL does not get pasted as an attachment when
attachment elements are enabled.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226340 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/editing/cocoa/WebContentReaderCocoa.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm
Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-data-url.html [new file with mode: 0644]

index 2a7c4816c3c88a808fcc4e24efc0d38c638f8b41..f87ce8381bdfcc4df256b6804d9a8276afca2d16 100644 (file)
@@ -1,3 +1,22 @@
+2018-01-02  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Attachment Support] Don't Blob-convert images and attachments with https:, http: or data: urls
+        https://bugs.webkit.org/show_bug.cgi?id=181143
+        <rdar://problem/36200381>
+
+        Reviewed by Tim Horton.
+
+        Clients such as Mail would expect pasting or dropping an image with src="https://..." to result in the source
+        URL being preserved (i.e. staying as remote images) instead of creating image attachments out of them. This
+        patch hooks into the shouldConvertToBlob() check added in r226272 so that it applies to attachment element
+        replacement as well.
+
+        Test: WKAttachmentTests.DoNotInsertDataURLImagesAsAttachments
+
+        * editing/cocoa/WebContentReaderCocoa.mm:
+        (WebCore::shouldConvertToBlob):
+        (WebCore::replaceRichContentWithAttachments):
+
 2018-01-02  Brady Eidson  <beidson@apple.com>
 
         Identify MessagePorts by a globally unique MessagePortIdentifier.
 2018-01-02  Brady Eidson  <beidson@apple.com>
 
         Identify MessagePorts by a globally unique MessagePortIdentifier.
index 10d3021638a0597ed6446e606b692d677488b6c9..1e3bbfd19d345c5094b1033afec716d199f93620 100644 (file)
@@ -175,6 +175,12 @@ private:
     bool m_didDisableImage { false };
 };
 
     bool m_didDisableImage { false };
 };
 
+
+static bool shouldConvertToBlob(const URL& url)
+{
+    return !(url.protocolIsInHTTPFamily() || url.protocolIsData());
+}
+
 static bool shouldReplaceRichContentWithAttachments()
 {
 #if ENABLE(ATTACHMENT_ELEMENT)
 static bool shouldReplaceRichContentWithAttachments()
 {
 #if ENABLE(ATTACHMENT_ELEMENT)
@@ -217,8 +223,11 @@ static void replaceRichContentWithAttachments(DocumentFragment& fragment, const
 
     // FIXME: Handle resources in subframe archives.
     HashMap<AtomicString, Ref<Blob>> urlToBlobMap;
 
     // FIXME: Handle resources in subframe archives.
     HashMap<AtomicString, Ref<Blob>> urlToBlobMap;
-    for (const Ref<ArchiveResource>& subresource : subresources)
-        urlToBlobMap.set(subresource->url().string(), Blob::create(subresource->data(), subresource->mimeType()));
+    for (const Ref<ArchiveResource>& subresource : subresources) {
+        auto& url = subresource->url();
+        if (shouldConvertToBlob(url))
+            urlToBlobMap.set(url.string(), Blob::create(subresource->data(), subresource->mimeType()));
+    }
 
     Vector<Ref<Element>> elementsToRemove;
     Vector<AttachmentReplacementInfo> attachmentReplacementInfo;
 
     Vector<Ref<Element>> elementsToRemove;
     Vector<AttachmentReplacementInfo> attachmentReplacementInfo;
@@ -353,11 +362,6 @@ static String markupForFragmentInDocument(Ref<DocumentFragment>&& fragment, Docu
     return createMarkup(range.get(), nullptr, AnnotateForInterchange, false, ResolveNonLocalURLs);
 }
 
     return createMarkup(range.get(), nullptr, AnnotateForInterchange, false, ResolveNonLocalURLs);
 }
 
-static bool shouldConvertToBlob(const URL& url)
-{
-    return !(url.protocolIsInHTTPFamily() || url.protocolIsData());
-}
-
 static String sanitizeMarkupWithArchive(Document& destinationDocument, MarkupAndArchive& markupAndArchive, const std::function<bool(const String)>& canShowMIMETypeAsHTML)
 {
     auto page = createPageForSanitizingWebContent();
 static String sanitizeMarkupWithArchive(Document& destinationDocument, MarkupAndArchive& markupAndArchive, const std::function<bool(const String)>& canShowMIMETypeAsHTML)
 {
     auto page = createPageForSanitizingWebContent();
index f9907a02f9c3d9dae98a9d0f05b9fe978d1473e4..b11644959bce0d4592535167e754ff9d2a2b7754 100644 (file)
@@ -1,3 +1,18 @@
+2018-01-02  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Attachment Support] Don't Blob-convert images and attachments with https:, http: or data: urls
+        https://bugs.webkit.org/show_bug.cgi?id=181143
+        <rdar://problem/36200381>
+
+        Reviewed by Tim Horton.
+
+        Add a new API test to ensure that a copied image with a data URL does not get pasted as an attachment when
+        attachment elements are enabled.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/WKAttachmentTests.mm:
+        (TestWebKitAPI::TEST):
+
 2018-01-02  Jiewen Tan  <jiewen_tan@apple.com>
 
         Update Credential Management API for WebAuthentication
 2018-01-02  Jiewen Tan  <jiewen_tan@apple.com>
 
         Update Credential Management API for WebAuthentication
index bd0c002209e37a3147ff646af75806b6f2b4249f..724789034481506e51726819ac51cc27c4c7438a 100644 (file)
                F486B1D01F67952300F34BDD /* DataTransfer-setDragImage.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */; };
                F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */; };
                F4A32ECB1F0643370047C544 /* contenteditable-in-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */; };
                F486B1D01F67952300F34BDD /* DataTransfer-setDragImage.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F486B1CF1F6794FF00F34BDD /* DataTransfer-setDragImage.html */; };
                F4A32EC41F05F3850047C544 /* dragstart-change-selection-offscreen.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */; };
                F4A32ECB1F0643370047C544 /* contenteditable-in-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */; };
+               F4A9202F1FEE34E900F59590 /* apple-data-url.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4A9202E1FEE34C800F59590 /* apple-data-url.html */; };
                F4AB578A1F65165400DB0DA1 /* custom-draggable-div.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */; };
                F4B825D81EF4DBFB006E417F /* compressed-files.zip in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4B825D61EF4DBD4006E417F /* compressed-files.zip */; };
                F4BFA68E1E4AD08000154298 /* DragAndDropPasteboardTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */; };
                F4AB578A1F65165400DB0DA1 /* custom-draggable-div.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */; };
                F4B825D81EF4DBFB006E417F /* compressed-files.zip in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4B825D61EF4DBD4006E417F /* compressed-files.zip */; };
                F4BFA68E1E4AD08000154298 /* DragAndDropPasteboardTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */; };
                                1C2B81871C8925A000A5529F /* Ahem.ttf in Copy Resources */,
                                1A63479F183D72A4005B1707 /* all-content-in-one-iframe.html in Copy Resources */,
                                C25CCA0D1E5141840026CB8A /* AllAhem.svg in Copy Resources */,
                                1C2B81871C8925A000A5529F /* Ahem.ttf in Copy Resources */,
                                1A63479F183D72A4005B1707 /* all-content-in-one-iframe.html in Copy Resources */,
                                C25CCA0D1E5141840026CB8A /* AllAhem.svg in Copy Resources */,
+                               F4A9202F1FEE34E900F59590 /* apple-data-url.html in Copy Resources */,
                                F46A095A1ED8A6E600D4AA55 /* apple.gif in Copy Resources */,
                                5C9E59411D3EB5AC00E3C62E /* ApplicationCache.db in Copy Resources */,
                                5C9E59421D3EB5AC00E3C62E /* ApplicationCache.db-shm in Copy Resources */,
                                F46A095A1ED8A6E600D4AA55 /* apple.gif in Copy Resources */,
                                5C9E59411D3EB5AC00E3C62E /* ApplicationCache.db in Copy Resources */,
                                5C9E59421D3EB5AC00E3C62E /* ApplicationCache.db-shm in Copy Resources */,
                F493247C1F44DF8D006F4336 /* UIKitSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIKitSPI.h; sourceTree = "<group>"; };
                F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-change-selection-offscreen.html"; sourceTree = "<group>"; };
                F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-in-iframe.html"; sourceTree = "<group>"; };
                F493247C1F44DF8D006F4336 /* UIKitSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UIKitSPI.h; sourceTree = "<group>"; };
                F4A32EC31F05F3780047C544 /* dragstart-change-selection-offscreen.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "dragstart-change-selection-offscreen.html"; sourceTree = "<group>"; };
                F4A32ECA1F0642F40047C544 /* contenteditable-in-iframe.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "contenteditable-in-iframe.html"; sourceTree = "<group>"; };
+               F4A9202E1FEE34C800F59590 /* apple-data-url.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "apple-data-url.html"; sourceTree = "<group>"; };
                F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "custom-draggable-div.html"; sourceTree = "<group>"; };
                F4B825D61EF4DBD4006E417F /* compressed-files.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "compressed-files.zip"; sourceTree = "<group>"; };
                F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropPasteboardTests.mm; sourceTree = "<group>"; };
                F4AB57891F65164B00DB0DA1 /* custom-draggable-div.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "custom-draggable-div.html"; sourceTree = "<group>"; };
                F4B825D61EF4DBD4006E417F /* compressed-files.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = "compressed-files.zip"; sourceTree = "<group>"; };
                F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropPasteboardTests.mm; sourceTree = "<group>"; };
                        isa = PBXGroup;
                        children = (
                                C25CCA0C1E5140E50026CB8A /* AllAhem.svg */,
                        isa = PBXGroup;
                        children = (
                                C25CCA0C1E5140E50026CB8A /* AllAhem.svg */,
+                               F4A9202E1FEE34C800F59590 /* apple-data-url.html */,
                                F47D30EB1ED28619000482E1 /* apple.gif */,
                                5C9E593E1D3EB1DE00E3C62E /* ApplicationCache.db */,
                                5C9E593F1D3EB1DE00E3C62E /* ApplicationCache.db-shm */,
                                F47D30EB1ED28619000482E1 /* apple.gif */,
                                5C9E593E1D3EB1DE00E3C62E /* ApplicationCache.db */,
                                5C9E593F1D3EB1DE00E3C62E /* ApplicationCache.db-shm */,
                                7C83DED41D0A590C00FEBCF3 /* HashSet.cpp in Sources */,
                                7C83DEE01D0A590C00FEBCF3 /* IntegerToStringConversion.cpp in Sources */,
                                7A0509411FB9F06400B33FB8 /* JSONValue.cpp in Sources */,
                                7C83DED41D0A590C00FEBCF3 /* HashSet.cpp in Sources */,
                                7C83DEE01D0A590C00FEBCF3 /* IntegerToStringConversion.cpp in Sources */,
                                7A0509411FB9F06400B33FB8 /* JSONValue.cpp in Sources */,
-                               FE05FB061FE84FB700093230 /* PoisonedUniquePtr.cpp in Sources */,
                                531C1D8E1DF8EF72006E979F /* LEBDecoder.cpp in Sources */,
                                A57D54F91F3397B400A97AA7 /* LifecycleLogger.cpp in Sources */,
                                93E2C5551FD3204100E1DF6A /* LineEnding.cpp in Sources */,
                                531C1D8E1DF8EF72006E979F /* LEBDecoder.cpp in Sources */,
                                A57D54F91F3397B400A97AA7 /* LifecycleLogger.cpp in Sources */,
                                93E2C5551FD3204100E1DF6A /* LineEnding.cpp in Sources */,
                                FE05FAEF1FE0645B00093230 /* Poisoned.cpp in Sources */,
                                FE05FAEC1FDB510A00093230 /* PoisonedRef.cpp in Sources */,
                                FE05FAED1FDB510E00093230 /* PoisonedRefPtr.cpp in Sources */,
                                FE05FAEF1FE0645B00093230 /* Poisoned.cpp in Sources */,
                                FE05FAEC1FDB510A00093230 /* PoisonedRef.cpp in Sources */,
                                FE05FAED1FDB510E00093230 /* PoisonedRefPtr.cpp in Sources */,
+                               FE05FB061FE84FB700093230 /* PoisonedUniquePtr.cpp in Sources */,
+                               FEC8F4EB1FE9F5AF0056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp in Sources */,
+                               FEC8F4E71FE9C9050056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp in Sources */,
                                53EC25411E96FD87000831B9 /* PriorityQueue.cpp in Sources */,
                                7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */,
                                7C83DF141D0A590C00FEBCF3 /* Ref.cpp in Sources */,
                                53EC25411E96FD87000831B9 /* PriorityQueue.cpp in Sources */,
                                7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */,
                                7C83DF141D0A590C00FEBCF3 /* Ref.cpp in Sources */,
                                7C83DF321D0A590C00FEBCF3 /* StringBuilder.cpp in Sources */,
                                7CD4C26E1E2C0E6E00929470 /* StringConcatenate.cpp in Sources */,
                                7C83DF361D0A590C00FEBCF3 /* StringHasher.cpp in Sources */,
                                7C83DF321D0A590C00FEBCF3 /* StringBuilder.cpp in Sources */,
                                7CD4C26E1E2C0E6E00929470 /* StringConcatenate.cpp in Sources */,
                                7C83DF361D0A590C00FEBCF3 /* StringHasher.cpp in Sources */,
-                               FEC8F4E71FE9C9050056FD8A /* PoisonedUniquePtrForTriviallyDestructibleArrays.cpp in Sources */,
                                7C83DF371D0A590C00FEBCF3 /* StringImpl.cpp in Sources */,
                                7C83DF381D0A590C00FEBCF3 /* StringOperators.cpp in Sources */,
                                7C83DF3A1D0A590C00FEBCF3 /* StringView.cpp in Sources */,
                                7C83DF371D0A590C00FEBCF3 /* StringImpl.cpp in Sources */,
                                7C83DF381D0A590C00FEBCF3 /* StringOperators.cpp in Sources */,
                                7C83DF3A1D0A590C00FEBCF3 /* StringView.cpp in Sources */,
                                9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */,
                                E3DEA8111F0A589000CBC2E8 /* ThreadGroup.cpp in Sources */,
                                E38A0D351FD50CC300E98C8B /* Threading.cpp in Sources */,
                                9329AA291DE3F81E003ABD07 /* TextBreakIterator.cpp in Sources */,
                                E3DEA8111F0A589000CBC2E8 /* ThreadGroup.cpp in Sources */,
                                E38A0D351FD50CC300E98C8B /* Threading.cpp in Sources */,
-                               FEC8F4EB1FE9F5AF0056FD8A /* PoisonedUniquePtrForNonTriviallyDestructibleArrays.cpp in Sources */,
                                5311BD5E1EA9490E00525281 /* ThreadMessages.cpp in Sources */,
                                0F2C20B81DCD545000542D9E /* Time.cpp in Sources */,
                                7C83E03B1D0A602700FEBCF3 /* UtilitiesCocoa.mm in Sources */,
                                5311BD5E1EA9490E00525281 /* ThreadMessages.cpp in Sources */,
                                0F2C20B81DCD545000542D9E /* Time.cpp in Sources */,
                                7C83E03B1D0A602700FEBCF3 /* UtilitiesCocoa.mm in Sources */,
index 08bdb147ec6b4a7a0537ee1eda5d42c8528c3719..f93fa6b53fb6701467abb51b5418494dca85535e 100644 (file)
@@ -893,6 +893,25 @@ TEST(WKAttachmentTests, InsertPastedAttributedStringContainingMultipleAttachment
     }
 }
 
     }
 }
 
+TEST(WKAttachmentTests, DoNotInsertDataURLImagesAsAttachments)
+{
+    auto webContentSourceView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]);
+    [webContentSourceView synchronouslyLoadTestPageNamed:@"apple-data-url"];
+    [webContentSourceView selectAll:nil];
+    [webContentSourceView _synchronouslyExecuteEditCommand:@"Copy" argument:nil];
+
+    auto webView = webViewForTestingAttachments();
+    {
+        ObserveAttachmentUpdatesForScope observer(webView.get());
+        [webView _synchronouslyExecuteEditCommand:@"Paste" argument:nil];
+        EXPECT_EQ(0U, observer.observer().inserted.count);
+    }
+
+    EXPECT_FALSE([webView stringByEvaluatingJavaScript:@"Boolean(document.querySelector('attachment'))"].boolValue);
+    EXPECT_EQ(1990, [webView stringByEvaluatingJavaScript:@"document.querySelector('img').src.length"].integerValue);
+    EXPECT_WK_STREQ("This is an apple", [webView stringByEvaluatingJavaScript:@"document.body.textContent"]);
+}
+
 #pragma mark - Platform-specific tests
 
 #if PLATFORM(MAC)
 #pragma mark - Platform-specific tests
 
 #if PLATFORM(MAC)
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-data-url.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/apple-data-url.html
new file mode 100644 (file)
index 0000000..63435fe
--- /dev/null
@@ -0,0 +1,3 @@
+<body>
+This is an apple<img src="data:image/gif;base64,R0lGODlhNABAAMQfAGJiYvLz9ImKitvb2/39/cnJyaSkpOPj49TU1MHBwbW1terq7Lu7u/X19uXm5+3u7+fo6eDg4e/w8t7e3/n5+RcXF87Oz/f398fHx9fX16+vr9HR0fDw8Pj4+MzMzAAAACH5BAEAAB8ALAAAAAA0AEAAQAX/4CeOZGme5iFUlYC+cCwKD7FAxxElAiTDnATAcCEYj8aABiBIDCIbjQCgqBEojUCjQSEEpoXTAUCQLB4PiZoTaG/fjcuFgj1kBrnIZDLoDzIIgRsTAgYmBk8TEQ4OEGdpbBQLDAUQEA55e32AGxsWHh4FBRgJCQgFAhQoCwIDlgsSFxyFOnt8foAInp+jpQkMwArCGsQaCg0KBgEoDwAAHoHRgroW1aEYpL7A28LDxcUGGgalhi8IAAgYoOvrn5/soL2lwcThEBQAAz/7JxYAXVcCPNjggp/BEwIYOHNmwMHBErMSEMgCR47FC3EwwnlzocOFBxMy3NHkp88EBwU///gjcKCRo0cPOEhwM6fDgUGWMuHKtQvUBgBhThhQ4CBCSwhoJDToQKxljlq4BPHCNo+bggXEXnwZMNMAupJ/ckm9RvUXg27dvqllkEFADxMQAKirZs3Du1CiRpX1ZfasN3EGAlsYIIADv3MCDnBowKEAQwSGSRzAMEVABIwTmCB4yHkEQQMACQDY0LmzgAlXZF0ac6D0QwUJOAxAkMArgAyuT3gQ5zYwBh8jBmhgoG9EBgYG3BbSQHpfBAEKjHSYTt3jxQ4BH3DB2EaLnAYLIgC6EyGuBhMDyDSI2X3jlu8Vay7480TPrU250p8n0SrASzQxsTGTFu9hF4B45WESgf8e+EWzy0/NlTBOeDk0AtNMcVAQQCcH5LTgLSJJ9c4ooQiwjFAI7GGUhWkE0AFWv+GQB4N/6OJJPNnMY0EAACyAgmMSLIKUBBxQgEoGRX0IIk8j5hiMNwxQkBAKDAhgxgMdeCBXBGCJFGInvMhj1V/fJMCjmSVEAEBcAFiQS4jS9HSNNk+mpZZaBmAwWgmZUeNJJ4DWJUqOdI6JZ2DjEHKiCRwEBg88BbCTl15O+lUPoo3u94MCAERAijrx+NQHBuIo4EGNgBRQigcRdAFAArl9EAAbBnWgRaylObCEiQQIECGu+2i5gBEaxgUcsDJk1sAVtp4xJbIy6JkdJhBAB63/DCstoOAGXhV3LQxeubWQZd/+kBBDuF17AKcAaDDAAuEp1G4GDZiAgBRMYODAAgdYYBsD+zjgFUAUVGedERf8NO49AQ2YkX85ZNDuCyoUcEVGBlunEUVbuBHHdBwcMNtIfkwQFwYlUMDDRA5v9B18FRUMHn22gBUWIZp+QEGeBKShRnceu5cRHbLdodNO0aSngAlV2vCIBD4PSOB7c0hidCb31TgNDyfEdcElLz3Cwdgt07HAHY0crbWN7iiQUgluN7DiK2eQ3cYcFwywQYcy0ggnmLx48FNrQllQ1FGvxIQhBQ+o0wgmUIU1Fl7YbEBZByggskeFjiQVAAUQKFDJ/2p5REUNjlSx1dYFmWOgh5BiazhcTlhvMpZedMIm2q8kuE1h5zNRkMxJM97HJI65D7NBBz2ekNkDLZ0hQQeEJZAkjbafPmdVdhKDQAMAEC5hAg8g9XlyeNRs+o1kVeWXAncywDwD9ZKQmSMBLDAEl13ydCPu3CPTnRKgPwP4aARVuoBjEBGW8fivSdkYE/zudCcPCMADvUOXNOIEJtQVCi0CxFN6HlCCKgFqA4II1F0A6L46kQlRgRkDBk0ghV3Q5YYQxAahtvGkb8DQgM94gWPuAoq6xCMvGKDUDl8YmOigIwYyjNSjpriOQUXQUpfilwAc8gMhZCABc8HhNSJlgTkOgoIUZykG+UQTFIMohBEIKGN9BmCbQgRmCq+awAIwgh0bvMo1C6hNZfJ0wBdMwG29KQAJy/WtEAAAO1BvbG9udXMK"></img>
+</body>
\ No newline at end of file