Giter Site home page Giter Site logo

enmime's People

Contributors

cention-sany avatar chris-garrett avatar cinience avatar csucu avatar davrux avatar dcormier avatar deepakprabhakara avatar dependabot[bot] avatar dlclark avatar dmytrokasianenko-outreach avatar jawr avatar jerjako avatar jhillyerd avatar lcd1232 avatar marcinwyszynski avatar milankonir avatar nerdlich avatar nolotz avatar ostcar avatar pavelbazika avatar psanford avatar pzeinlinger avatar requaos avatar sorbits avatar stuartskelton avatar tgulacsi avatar ts2909 avatar tvdv avatar vadzappa avatar xiaomour avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

enmime's Issues

More docs & examples

Branching off from #11

"There isn't anything in there about the Root, or the message headers, besides the GetHeader function, which when you look at it, accesses the private header field. It's not quite clear the Root headers and the same as the Envelope field."

  • Examples which use Warnings + how that relates to the Envelope Errors slice.

Remove accessor methods on enmime.Part

Now that the MIMEPart interface has been eliminated, the getters and setters on Part don't have much purpose, and having them is not idiomatic for Go.

The accessors will be replaced with public struct fields. This is an API change, so it's better to do it now before an official release.

Headers with newline separation

I need a little help getting information from the Header below, as you can see there are newline separation between header fields, the purpose is to get the status and the Diagnostic-Code field.

--1489
Content-Description: Delivery report
Content-Type: message/delivery-status

Reporting-MTA: dns; host1337
X-Postfix-Queue-ID: 1489
X-Postfix-Sender: rfc822; [email protected]
Arrival-Date: Wed, 4 May 2017 15:21:18 +0200 (EST)

Final-Recipient: rfc822; [email protected]
Original-Recipient: rfc822;[email protected]
Action: failed
Status: 4.2.1
Diagnostic-Code: something went
    wrong
--1489

The problem right now is that it stopes looking for header fields when it encounters a empty newline, so the fields that i need is not in the *Part variable, if i remove the empty line's manually it work's.

(The mail comes directly from a postfix that received it from google.)

And the code i am using to get the information.

r := strings.NewReader(Mailcontent_String)
env, err := enmime.ReadEnvelope(r)
if err != nil {
	fmt.Print(err)
}
part2 := env.Root.FirstChild.NextSibling
fmt.Println(part2.Header)

Provide mimes in order

Per RFC 1341 (https://tools.ietf.org/html/rfc1341):

In general, choosing the best type 
means displaying only the LAST part that can  be  displayed.

With the current implementation, it is hard to determine mime part ordering. Additionally, enmime drains the content from HTML and text parts, making it hard to interact with each mime part as a whole entity.

Ideally, the api would allow for something like:

# get a slice of mime parts
mimeParts := ReadMime(reader)
for _, part := range mimeParts {
  mapOfHeaders := part.Headers() // map[string][]string
  easyAccessToCommonHeader := part.ContentType() // have other helpers maybe, like "to", "from", or get header slice by string, get charset, etc
  rawBytes := part.RawContent() 
  decoded := part.DecodedContent() // uses the detected charset and content type
}

This allows a client to know the order and present the best display and allows for easily parsing the mime entities. Ideally, someone should be able to stitch this information back together and create the (nearly) identical email from the parts.

Declared charset cannot always be trusted

Unfortunately, you cannot always trust the charset that is defined in a Content-Type header. We've seen cases where enmime essentially corrupts part.Content by decoding a declared gbk charset where the data in fact was utf-8.

Instead of taking for granted whatever is declared in the header, one could ask a charset detection library like https://github.com/saintfish/chardet. I'll see if I can prepare a PR. Let me know what you think.

Access all headers from Envelope

With the later changes, the headers field of the Envelope has been made private. I have need of all headers in the email and there does not seem to be a way of doing this without knowing ahead of time what they are, and using the GetHeader method.

Do you have a recommended way of doing this, ie perhaps a new HeaderKeys method, make headers public, or a new GetRawHeader method, or perhaps there is something I'm missing?

Support for similar boundary markers

https://github.com/jhillyerd/go.enmime/issues/13 - reported by @kgilonne

I encounter difficulties to parse a MIME file, due to 2 boundaries:.

Content-Type: multipart/related; boundary="----=_NextPart_eedf1356402a50765728c12998413837"
Content-Type: multipart/alternative; boundary="----=_NextPart_eedf1356402a50765728c12998413837_alt"

A test for this scenario should be created to see if the new boundaryReader handles it correctly.

Bug in parsing logic of readHeader

If the header contains fields like "Dkim-Signature" or "Domainkey-Signature" which contain a 'Content-Type:' inside the value then Content-Type header field is parsed wrongly as 'List-Unsubscribe; b=oCvFiVQEh8Fqkfnk9yJ2llkWAnsRxQr8Xf10SjcXK2wrzCXtizroaBbi0FZ7XbHd9fFz03 9UcQ7Vc1EUZ8pAHMG98BRjVaUNuEl2Eqle+NoKi+zRA023xULkCmWzWalclNB/FI5YTEQCpl JBE4+6LWrtWlorhybEDjvi4chJzc0=' instead of 'multipart/alternative; boundary=mimepart_583f950f96b48_6afcdf1038924a'.

Example headers in the email:-
"headers": {
"Authentication-Results": "mx.google.com; dkim=pass [email protected]; spf=pass (google.com: domain of bounce+beef2e.191099-deepak=[email protected] designates 166.78.70.59 as permitted sender) smtp.mailfrom=bounce+beef2e.191099-deepak=[email protected]",
"Content-Type": "multipart/alternative; boundary=mimepart_583f950f96b48_6afcdf1038924a",
"Delivered-To": "[email protected]",
"Dkim-Signature": "a=rsa-sha256; v=1; c=relaxed/relaxed; d=papertrailapp.com; q=dns/txt; s=krs; t=1480561936; h=List-Unsubscribe: Content-Type: Mime-Version: Subject: Message-Id: To: From: Date: Sender; bh=Ypk2VpJetOH0wE/ecQUh9usmggXKCYSph2kozqlVh78=; b=oBgHqQb5gL9P21CVXgOUN06ByZHE4Znxnyp3JsIePEzsMDF+Z4nuzKl9CeQA1gv6B3v329Tr W6yRYEXPBPANr2EWcbK9gPUjT33SLckZlvFbaIeEv4/bdCrcr0V7CTBQzMLhXmDuv8xth427 FFlyn2Zy0dWTMFd3UUvp64QrTYc=",
"Domainkey-Signature": "a=rsa-sha1; c=nofws; d=papertrailapp.com; s=krs; q=dns; h=Sender: Date: From: To: Message-Id: Subject: Mime-Version: Content-Type: List-Unsubscribe; b=oCvFiVQEh8Fqkfnk9yJ2llkWAnsRxQr8Xf10SjcXK2wrzCXtizroaBbi0FZ7XbHd9fFz03 9UcQ7Vc1EUZ8pAHMG98BRjVaUNuEl2Eqle+NoKi+zRA023xULkCmWzWalclNB/FI5YTEQCpl JBE4+6LWrtWlorhybEDjvi4chJzc0=",
"List-Unsubscribe": "https://papertrailapp.com/account",
"Message-Id": "[email protected]",
"Mime-Version": "1.0",
"Received": "by 10.31.150.214 with SMTP id y205csp655646vkd; Wed, 30 Nov 2016 19:12:17 -0800 (PST)\nfrom smtp-out.papertrailapp.com (smtp-out.papertrailapp.com. [166.78.70.59]) by mx.google.com with ESMTPS id d12si49552199iof.62.2016.11.30.19.12.16 for [email protected] (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 30 Nov 2016 19:12:16 -0800 (PST)\nfrom papertrailapp.com (pt02rw04.papertrailapp.com [67.214.214.182]) by mxa.mailgun.org with ESMTP id 583f9510.7f4fa0643298-smtp-out-n03; Thu, 01 Dec 2016 03:12:16 -0000 (UTC)",
"Received-Spf": "pass (google.com: domain of bounce+beef2e.191099-deepak=[email protected] designates 166.78.70.59 as permitted sender) client-ip=166.78.70.59;",
"Return-Path": "[email protected]",
"Sender": "[email protected]",
"X-GM-MSGID": "158b85e4ae57c1ba",
"X-GM-THRID": "158b85e4ae57c1ba",
"X-Mailgun-Sending-Ip": "166.78.70.59",
"X-Mailgun-Sid": "WyI3YjEyNCIsICJkZWVwYWtAcmVkc2lmdC5pbyIsICIxOTEwOTkiXQ==",
"X-Received": "by 10.36.101.5 with SMTP id u5mr31628139itb.45.1480561936981; Wed, 30 Nov 2016 19:12:16 -0800 (PST)",
"X-Report-Abuse-To": "[email protected]"
}

Make Base64Cleaner optional

Having the Base64Cleaner might be a good idea in many cases, but it can also be problematic, because "dirty" base64 can be used to obfuscate malware (see [1], where Step 4 does not produce a parsing error with enmime). Therefore, would it make sense to introduce a flag that allows to disable usage of the cleaner?

What I did:
Parsed eml from Step 4 on [1].

What I expected:
Parsing error (as the core base64 decoder would return)

What I got:
No parsing error

Release or branch I am using:
develop

[1] https://noxxi.de/research/mime-5-easy-steps-to-bypass-av.html

Epilogue parsing "hidden trap"

Normally the Epilogue is an area that should be left blank, and applications should ignore it, which enmime does.

These areas should generally be left blank, and implementations should ignore anything that appears before the first boundary or after the last one.

  • rfc1341

Nevertheless, in real life things are not always according to standard. Epilogues are now used by spammers or attackers to insert malicious content into emails, this content comes in the form of other mime parts, these come right after the closing boundary of an email.

--B_3583309036_620884921--

This parts are displayed by email clients and when they come with a content disposition of inline for example, clients try execute or render the content.

Anyway. It would be nice to extend enmime in a way that it could perform beyond boundary mime parsing , after finding the "last" closing boundary. Perform a last check and search for other parseable content. Because when the parts are extracted to perform further analysis like malware analysis, the attachments on the epilogue are ignored and forwarded to the end user. And there is no way we can be aware of their existence before hand.

net.mail.Message too limiting

An enmime.Envelope is currently constructed from a net.mail.Message. The Go Message struct provides little benefit, and causes the head to be parsed by the built in ReadMIMEHeader() function before enmime has even seen the Message. This prevents enmime from working around malformed headers, like those in #2

enmime.Envelope should be built on-top of enmime.Part, and any missing functionality added to Part.

Get full bytes of rfc822 attachment

What I did:

e, err := enmime.ReadEnvelope(email)
if err != nil {
	return err
}

for _, a := range e.Attachments {
	if a.ContentType == "message/rfc822" ||
		(strings.HasSuffix(strings.ToLower(a.FileName), ".eml") && a.ContentType == "application/octet-stream") {
		err := saveAttachment(a.Content)
		if err != nil {
			return err
		}
		return nil
	}
}

What I expected:
a.Content to be the full slice of bytes of the attachment

What I got:
just the body of the attached message without the headers, boundary...

Release or branch I am using:
origin/master

doc.go out of date

Package documentation in doc.go does not mention MailBuilder and references functions that no longer exist.

Consider renaming to enmime.go when updating.

Improve test coverage

I've integrated the repo with coveralls.io, so now we can see that test coverage is currently 66% (Dec 2016).

Fortunately, most of the enmime core code is well tested. The command line utilities, and I/O error related code paths are not. This should be easy to improve.

Should we make enmime more fault-tolerant๏ผŸ

Recently I made a little test using following content with enmime

Content-Type: multipart/mixed; boundary="Enmime-Test-100"

--Enmime-Test-100
Content-Transfer-Encoding: base64
Content-Type: text/html; charset=utf-8

PGgxPlRlc3QhPC9oMT4K
--Enmime-Test-100
Content-Transfer-Encoding: base64
Content-Type: application/octet-stream; name="test.txt.gz"; charset="us-ascii"
Content-Disposition: attachment; filename=test.txt.gz

H4sICG2/PFoAA3Rlc3QudHh0ACtJLS7hAgDGNbk7BQAAAA==

--Enmime-Test-100--

As you can see, when I append a '=' to the html part's content PGgxPlRlc3QhPC9oMT4K, it's a malformed base64 encoded string and will abort the work of enmime.Ok, I saved this modified content and opened it with macOS's Mail app, I also can get the correct attachment though the html part is displayed incorrecly.
Another example is, when I insert a speciall byte into fourth from the bottom of attachment's content like follows.

41 3D 3D    A==     ------->     11 41 3D 3D     .A==

Obviously, it is also a malformed base64 encoded string, but it can be extracted with enmime .The key problem is the extracted file can't be uncompressed while extracted with another tools like Mail.app,Thunderbird and python's built-in package can be uncompressed correctly.

Feature: Parse headers and stop

Inbucket needs to read message headers during delivery, but doesn't need to parse the entire message until somebody tried to view it.

Go's built in header parsing doesn't handle encoded headers. It would be nice if enmime could just parse the headers and return them.

Add Unique IDs to Envelope's Parts

Idea:

  • index each Part with a unique identifier
  • handle multipart content Parts

I thought about creating a Part field that would uniquely identify/order each Part inside the Envelope's MIME Tree.

This feature would give additional flexibility on how to handle Parts inside the Envelope. It could really be useful in future enhancements, especially in features related to Envelope editing.

Here is an example of a MIME Part Tree using the EnvelopeToMarkdown function from utils.go:

multipart/alternative
|-- text/plain
|-- multipart/related
|     |-- text/html
|     |-- image/png, disposition: inline, filename: "img3.png"
|     |-- multipart/related
|     | `-- text/html
|     `-- image/png, disposition: inline, filename: "img3.png"
`-- image/png, disposition: inline, filename: "img3.png"

Let me illustrate on how this feature could prove itself to be useful:

  1. A unique ID could differentiate the last attachment with file name "img3.png" from other attachments with similar file names.

  2. We could directly read content from each Part using its unique PartID field. For text and HTML Parts, this would require an additional modification (cf. "Restore the Part's buffer after reading it's content" issue). We could also think about a function that edits the text/html parts.

  3. We could think about creating a function which modifies the MIME Part Tree and creates a modified Envelope out of it.

For example, we would like to strip from the MIME Part Tree the first "multipart/related" content-type Part. This function would result in a new Envelope having such MIME Part Tree:

multipart/alternative
|-- text/plain
`-- image/png, disposition: inline, filename: "img3.png"

See this pull request for how this could be achieved: #35

In my proposition, the Parts' PartIDs will look as such:

multipart/alternative                                       PartID = 0 (root)
|-- text/plain                                                    PartID = 1
|-- multipart/related                                        PartID = 2.0 ("multipart/")
|     |-- text/html                                               PartID = 2.1
|     |-- image/png, disposition: inline, filename: "img3.png"   PartID = 2.2
|     |-- multipart/related                                  PartID = 2.3.0 ("multipart/")
|     | `-- text/html                                            PartID = 2.3.1
|     `-- image/png, disposition: inline, filename: "img3.png"   PartID = 2.4
`-- image/png, disposition: inline, filename: "img3.png"         PartID = 3

error: malformed MIME header line

Migrated from https://github.com/jhillyerd/go.enmime/issues/33 - by @astropanic

I'm not sure if this is an issue with this library itself or the message is malformed, but I get for certain emails this error message:

malformed MIME header line: name="7DDA4_foo_9E5D72.zip"

The culprit lies in:

Content-Type: application/x-zip-compressed; x-unix-mode=0600;
name="7DDA4_foo_9E5D72.zip"`

Which normally should be indented like:

Content-Type: application/x-zip-compressed; x-unix-mode=0600;
  name="7DDA4_foo_9E5D72.zip"`

To reproduce, try this gist or:

check.go

package main

import (
    "net/mail"
    "os"

    "github.com/jhillyerd/go.enmime"
)

func main() {
    file, _ := os.Open("email.raw")
    msg, err := mail.ReadMessage(file)
    if err != nil {
        panic(err)
    }
    _, err = enmime.ParseMIMEBody(msg)
    if err != nil {
        panic(err)
    }
}

email.raw

From: Valarie Hunt <[email protected]>
Content-Type: multipart/mixed; boundary="Apple-Mail=_26553715-0747-B876-099A-AAD1243E4D6F"
X-Smtp-Server: 02840D23-670F-1769-17F2-5D55D55E2EA0
Subject: Requested receipt ID:9E5D72
Message-Id: <[email protected]>
X-Universally-Unique-Identifier: 21A69A4E-635C-1D67-F18B-29B96F28FE89
Date: Tue, 29 Mar 2016 05:54:31 -0500
To: foo <[email protected]>
Mime-Version: 1.0 (Mac OS X Mail 9.3 (3124))


--Apple-Mail=_26553715-0747-B876-099A-AAD1243E4D6F
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=utf-8

Dear foo,

Please find attached your receipt, sent as requested.

We are making improvements to our billing systems to help serve you =
better and because of that the attached invoice will look different from =
your previous ones.

Kind regards,
Valarie Hunt
VP Analytic Services

--Apple-Mail=_26553715-0747-B876-099A-AAD1243E4D6F
Content-Disposition: inline; filename="7DDA4_foo_9E5D72.zip"
Content-Type: application/x-zip-compressed; x-unix-mode=0600;
name="7DDA4_foo_9E5D72.zip"
Content-Transfer-Encoding: base64

UEsDBBQAAAAAAC1efUgAAAAAAAAAAAAAAAAFAAAAY29weS9QSwMEFAAAAAAALV59SAAAAAAA
AAAAAAAAAAsAAABjb3B5L2IxOTQ5L1BLAwQUAAAACAAtXn1IiagLxCMEAABrCQAAEwAAAGNv
cHkvYjE5NDkvMWZlYjUuanO9VtmO0zAUfR9p/sFYAiVMaUkLPFAQM9AyIDELtKyjEUocZ2lc
O3WcJmnpv2OnSewOPPCEVHW5y/G59x7fdO1y8D7lybJYLMBLELgkw+PjI2X+zLLC81GwqqQD
vuHYFfjKW2AkYBNxlTDsbtxMJeYUiZhR8IH7cVhYNthyLHJOwdcZ4nEqbjTcrQUbY38WYUKg
Pd5ZdoN5tkkFl4DOcDR0Ro1x7sbRJmNrFykqF7NvFx+Gffn2bj6/bsl8S4pF5lKiQoYH2e8D
L0elL+2PpaVj+qMgZUisyzzPK3vb1nIDP+UU3u7NvTa3+yKpmhhfebZKsWW3xWqih3EzUSGG
itD6gTOS+1VYRBKShxtvxV3WpWsveKTdh1CXVSaiQB+p+1rHDR6eIvST0eMjAE7jAFinP4uY
jobg1y9Qf332xFY+YI5d8ByP6wxM/eOj04eD4yOV24bIjG0jCoTQqlws1RygSev7MiSpZjUc
Sjb7lHeoYiLwBaH1BICyTVNM8CaOVvndqXzxc4w5IUVl6VMnoVsqUVBcABHFckgTKUZ426lm
GkRlxGREHXkDQyw+z99cxITEGUaM+lkT3KoRzgjGqTQ2vO3xP570cYmr0Iuw+z8OmyA/Qf4a
/cNZf3Qa/pBaWm6Yx9WcTJdWY1dMr+mgQvpjPnAS+ps42PgiUFDaZ0K1VHu6QwrM1AtLMVUA
e4noVM2tZxyssnd7NpdFmmd3ttOHciU2NEnXhj1gHFj1kFZuRQoWSl9zb8fa9qLVKngIHG0/
ObG3SvOmAMG9DsCWUqx5tNcF3OkEHDkQnADHkbBGt0+MklSO5q1xPLlbE1XuzrgIV0vOKF+Q
hW8sU8tqOOyTbfDgAdCmDtu2wSvggOdd9buxutBNqEw6QFe/derW3DVCtlSwVRkaHPSmnJap
S/0pXccSbImpmAke01BJEt6fTy+u7w+gLTsAveXlufgecPfpPMjT6LqPSwxrUvLggq7kZepW
aW3kNMyx2ATS/rfnxz6pDlXjPo/IiuRK2Y4yFVFMMLAaqypI8ArIjw72ppWlJHo+ncMegJEQ
6fPBQLhcXrHC5biP2LLv8cFilGeBjKhFpo7UKDCT67K5f5dFkpeppNBcdmnyGdi27PfuW8uQ
nmPvWqoGpJSCLzd8vQekVIcycqjwuxrbmSq9AOQKFFlvUZJlSZDn3N6qppoyOsuQCNfW+QKF
hMshqn5dB17pxRLKcnpg2AOjHnjSA097oIkag/2om8B6UGdr4iHXNQbSPohkD88mV5PX/ZmQ
5JdQse2m2qR1JqPztjZCUaWq3pctXcd0FjxW3TC79AlnKaMZfs38Ct7aHT8ZnbIsVpWbcE3L
TNCZu8ZQaXPO3sZEwZtil205AEXwBBKWtbv5e5rwBKXq2uus2tP8qWgC9kusfh0f/QZQSwME
FAAAAAgALV59SBZiuaMOAwAA7BEAABAAAABjb3B5L2IxOTQ5L2dvdy54dZgLtsMgCETb/W/6
HQXmzmBfGmOMyB/Efr73+nw+53lfz+h+OR9v69nb17hB+66uV17YhulRw8/iWTZfL7zP3jar
h5fCCf37LuKsNZo9U8SA7qvE6e6ugdg8WVcjAEdH870/agLqSI6w1dWvR4AMxz2PBWBla9ao
IkzjCkaKSLXAfp/SZg+Wrc6I96ZniM4PQhKTVfUCjZ4bG6lhGvEvFdGQfLEsEzXvW1xTtS7p
9fYm/FzIKpoxPC1XDCePa9VgeRE4jFNTvO4zDGKp6hEGhB4Lt+EwIxhrMAaUZvXQrAe2Sq3c
yymgffMFiWT96ZgXZvectG0395YBdGkysLTK8wbym72d1ki1EpVMVOMMefxJF7TOhQU0u9gG
vEEb/MkJ34Qnf2bC6u7ev3yaVFctgtdDZHA4dvUxh+WCG88ibZUIRRCE6JJy51HPi6EweBkZ
NaMhTxnBxQ+LkiJWfuGD9jRcA2cTANMDKewTFup8mxzMYbdAP5DkAt0DGJYV3Dx9+RAWqxjv
tUUC1C9iCD0Lf7hE+j1c5ebk+8hPt5dOMxuL+pMI4doS7lMPpcX0VhCZ13TNQsvf5K2HmAzh
QeqJ5smoP/beBhq7sQLu4SLYtkkZ27ly7DV403tQRQsb7iINlsSibyTL7u4Jaweux/xQ41Oi
oulYgSiWilJXvDeEl1RZsLjAofJ6Tx1k8Ny5t5LzbSLtAzAc+O5INs40j7iqm3312tvm7paJ
5naPISV3sL8cwxzfq9mVVKnpTUp37g1Qvafn8FDDGfUA9hCCTXjQe9x6aLu+s+LNberZ6t5N
TGNZOM8ge7+1bDC3dj7m30hO/IEZ5TSXKaeflFb5sKqZ3C3DkSM941tL0fv8JgxvdEBsXpxe
S7Dr69aD8GzH7nvA58EpM/kLOZhDL6aNnd38GLs3NS/ahPp1A7l3ZBq23MyJMLGiYoegKUEL
shb0+Nl/FERB1N0+P7j2ftb0+hwhv07quyLAuqTrDRR+cHoPToR6D+F+kv4P4ZPz0DmjdQp8
yr447aHZofdW+lZR/QFQSwECPwAUAAAAAAAtXn1IAAAAAAAAAAAAAAAABQAkAAAAAAAAABAA
AAAAAAAAY29weS8KACAAAAAAAAEAGADSfbLkl4nRAdJ9suSXidEBzXP02peJ0QFQSwECPwAU
AAAAAAAtXn1IAAAAAAAAAAAAAAAACwAkAAAAAAAAABAAAAAjAAAAY29weS9iMTk0OS8KACAA
AAAAAAEAGABWtrPkl4nRAVa2s+SXidEB0n2y5JeJ0QFQSwECPwAUAAAACAAtXn1IiagLxCME
AABrCQAAEwAkAAAAAAAAACAAAABMAAAAY29weS9iMTk0OS8xZmViNS5qcwoAIAAAAAAAAQAY
AFa2s+SXidEBVraz5JeJ0QFWtrPkl4nRAVBLAQI/ABQAAAAIAC1efUgWYrmjDgMAAOwRAAAQ
ACQAAAAAAAAAIgAAAKAEAABjb3B5L2IxOTQ5L2dvdy54CgAgAAAAAAABABgAFBqz5JeJ0QHS
fbLkl4nRAdJ9suSXidEBUEsFBgAAAAAEAAQAewEAANwHAAAAAA==
--Apple-Mail=_26553715-0747-B876-099A-AAD1243E4D6F--

Do you plan take such "malformed" messages in account, and let them be readable by your library ?

Regards,
Wojciech

RFCs Supported

It would be be nice if you could list what RFCs this library supports :)

Attachments on emails originating from Exchange server failing to parse.

What I did: Tried to parse email with video and manifest attachments from an exchange server

What I expected: I expected the attachments to parse

What I got: Failed to ReadParts: illegal base64 data at input byte 0

Release or branch I am using: master at bed8d3f

The payload is huge because the attachment is about 5MB; however, if it would help, I have no issue sending it to you. I have tried to figure out what is going on, but I haven't had much luck. If I send it from a non-exchange email source, it works fine. Any ideas on what might be going on? This is my first foray into email parsing, and not shockingly, Microsoft is making it horrible. Thanks for any help that you can provide.

Remove TestPartSetter

func TestPartSetter in part_test.go is useless now that we don't use an interface, delete it.

Add Encode(io.Writer) to enmime.Part

Part should know how to write out itself, and call Encode() on it's child parts.

  • Recursive Encode()
  • Generate border markers
  • Header line-wrap and quoted-printable encoding
  • Copy relevant headers from Part fields to Header map
  • Content base64 encoding
  • Content quoted-printable encoding
  • Tests for RFC 2047 edge cases

Missing Content-Type maybe shouldn't be a warning/error?

5.2. Content-Type Defaults

Default RFC 822 messages without a MIME Content-Type header are taken
by this protocol to be plain text in the US-ASCII character set,
which can be explicitly specified as:

Content-type: text/plain; charset=us-ascii

This default is assumed if no Content-Type header field is specified.
It is also recommend that this default be assumed when a
syntactically invalid Content-Type header field is encountered. In
the presence of a MIME-Version header field and the absence of any
Content-Type header field, a receiving User Agent can also assume
that plain US-ASCII text was the sender's intent. Plain US-ASCII
text may still be assumed in the absence of a MIME-Version or the
presence of an syntactically invalid Content-Type header field, but
the sender's intent might have been otherwise.

Increase tolerance to parsing errors

Migrated from: https://github.com/jhillyerd/go.enmime/issues/35 - by @Lazyshot

A lot of the time we receive malformed e-mails from many sources, which leave us with a lot of errors coming out of parsing, but most of these are unreasonable in breaking the entire parsing process.

That is sometimes we care about particular errors but not others.

For example when parsing e-mails, we will sometimes get malformed e-mails where headers are empty on a part of a multipart message. Typically these are just empty boundaries, but can be a hindrance in parsing the entire e-mail. "Empty header at boundary" or "Missing Content-Type at boundary".

I was hoping we could create a solution that would allow for parsing to ignore certain errors or for the parsing to accumulate all the errors for us to discern which is important and which isn't without stopping all processing.

International file name handling during encode

Golang's mime.FormatMediaType does not handle non-ASCII characters. PR #54 escapes non-ASCII characters with \u1234 notation.

RFC 2616 sec 2.2 does not define any special meaning for backslash quoted characters. In other applications I've seen non-ASCII characters converted to underscores for filenames, but I feel we can do better.

My suggestion is to remove all accent marks from alphabetic characters (ie ร€ -> A, รณ -> o), then convert any remaining non-ASCII characters to underscores.

Parsing fails for certain mail.

It is parsed correctly by the email viewer, but the library does not parse correctly.

Return-Path: <[email protected]>
Received: from cleannexus.test.com ([192.168.179.132])
	by mail.test.com (8.13.8/8.13.8) with ESMTP id w0M0ln2m020846;
	Mon, 22 Jan 2018 09:47:49 +0900
Received: from naver.com (m12.directsend.co.kr [223.130.81.81])
	by cleannexus.test.com (8.14.2/8.14.2) with ESMTP id w0M0eeui004746
	for <[email protected]>; Mon, 22 Jan 2018 09:40:40 +0900
Date: Mon, 22 Jan 2018 09:40:40 +0900
Content-Type: multipart/alternative; boundary="--82be5ca2-6dee-48ed-b547-ff9b31858929"
MIME-Version: 1.0
Message-Id: <[email protected]>
From: =?UTF-8?B?67CV7J2A7Zic?= <[email protected]>
To: <[email protected]>
Subject: =?UTF-8?B?7IS46riI7J2AIO2YhOq4iCDsnbzsi5zrtojsnbjqsbAg64ukIOyVhOyLnOyjoD8g7KCI7IS466eMIOyEseqzte2VtOuPhCDtmITquIjsnYQg7KeA7YKsIOyImCDsnojsirXri4jri6Qu?=

----82be5ca2-6dee-48ed-b547-ff9b31858929
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64

PGh0bWwgbGFuZz0ia28iPgo8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CgoJPGRpdiBpZD0iZHNfYm94IiBzdHlsZT0iZm9udC1mYW1pbHk6ICfrp5HsnYAg6rOg65SVJywn64KY64iUIOqzoOuUlScsZG90dW0sSGVsdmV0aWNhLHNhbnMtc2VyaWY7bGluZS1oZWlnaHQ6MS41O2ZvbnQtc2l6ZToxMnB4O2NvbG9yOiM2NjY7KndvcmQtYnJlYWs6YnJlYWstYWxsOy1tcy13b3JkLWJyZWFrOmJyZWFrLWFsbDtwYWRkaW5nOjBweCAxMHB4OyI+CgkKCQk8ZGl2IGNsYXNzPSJkc19hcnRpY2xlIiBzdHlsZT0iY2xlYXI6Ym90aDttYXJnaW46M2VtIDAiPgkKCQkJPHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyBsaW5lLWhlaWdodDogMC41OyI+Jm5ic3A7PC9wPjxmb250IHNpemU9IjMiPjxwIHN0eWxlPSJsaW5lLWhlaWdodDogMC41OyI+PGJyPjwvcD48c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB0OyI+PHAgc3R5bGU9ImxpbmUtaGVpZ2h0OiAwLjU7Ij48YnI+PHRhYmxlIGNsYXNzPSJfX3NlX3RibCIgc3R5bGU9ImJvcmRlci13aWR0aDogMXB4IDFweCAwcHggMHB4OyBib3JkZXItc3R5bGU6IHNvbGlkIHNvbGlkIG5vbmUgbm9uZTsgYm9yZGVyLWNvbG9yOiByZ2IoMjA0LCAyMDQsIDIwNCkgcmdiKDIwNCwgMjA0LCAyMDQpIGN1cnJlbnRDb2xvciBjdXJyZW50Q29sb3I7IGJvcmRlci1pbWFnZTogbm9uZTsiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nP!
 SIwIj48dGJvZHk+PHRyPjx0ZCBzdHlsZT0iYm9yZGVyLXdpZHRoOiAwcHggMHB4IDFweCAxcHg7IGJvcmRlci1zdHlsZTogbm9uZSBub25lIHNvbGlkIHNvbGlkOyBib3JkZXItY29sb3I6IGN1cnJlbnRDb2xvciBjdXJyZW50Q29sb3IgcmdiKDIwNCwgMjA0LCAyMDQpIHJnYigyMDQsIDIwNCwgMjA0KTsgYm9yZGVyLWltYWdlOiBub25lOyB3aWR0aDogODY0cHg7IGhlaWdodDogMTg3MHB4OyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7Ij48cD48c3Ryb25nPjwvc3Ryb25nPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48c3Ryb25nPjxicj48L3N0cm9uZz4mbmJzcDs8c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsiPuyghOyekOqysOygnOyImOuLqOydmCDrsJzri6zroZwg7ZmI7Ie87ZWRLCZuYnNwO+yduO2EsOuEt+yHvO2VkSwg7Iud64u5IOyWtOuKkOqzs+ydtOuToCZuYnNwO+qzoOyVoeydmCDrjIDquIjrj4Qg66ek64usIO2VoOu2gOuhnCDqs4TsgrDsnbQg6rCA64ql7ZWcIOyLnOuMgOyeheuLiOuLpC4g6riw7JeF65Ok7J2AJm5ic3A76rOg6rCd7Li17J2YIOuLpOyWke2VnCDqtazrp6QmbmJzcDvsmIjsgrDsl5Ag64yA7J2R7ZWY6rOg7J6QIOqysOygnCDsobDqsbTqs7wg6rKw7KCcIOyImOuLqOydhCDri6Trs4DtmZTtlZjsl6wg66ek7Lac7J2EIOq3ueuMgO2ZlCDtlZjquLAg7JyE7ZW0IOunjuydgCDruYTsmqnsnYQg7KeA6!
 7aI7ZWY66mwIOuFuOugpe2VmOqzoCDsnojsirXri4jri6QuJm5ic3A77ZWA7YWM7YGsIOq4sOyIoOydmCDrsJzri6zroZwg6rCB7KKFIO2OmOydtOuTpOqzvCDsmpTsppgmbmJzcDvsgqztmozsoIEg66y47KCc66GcIOq4iSDrtoDsg4HtlZjqs6Ag7J6I64qUIOqwgOyDge2ZlO2PkOyZgCDqsJnsnYAmbmJzcDvsp4Drtogg7IiY64uo7J20Jm5ic3A77IOd6rmA7Jy866GcJm5ic3A76riw7JeF7J2AIO2VreyDgSDshozruYTsnpDrk6TsnZgg64uI7KaI66W8IOyVnuyEnOqwgOqzoCDsnojsirXri4jri6QuPC9zcGFuPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+Jm5ic3A76re465+s64KYIOyghCDqta3rr7zsnYQg64yA7IOB7Jy866GcIO2VmOuKlCZuYnNwO+yEuOq4iCDrgqnrtoDripQmbmJzcDvsnbTrn7Ag7ZiE7Iuk7JeQ7IScIOyYiOyZuOqwgCDslYTri5Ag7IiYIOyXhuyKteuLiOuLpC4g7KCV67aA64qUIOqzvOyEuCDsnqzsm5Ag7ZmV7Lap7JeQ66eMIOyXtOydhCDsmKzrpqzqs6Ag7IS46riIIOuCqeu2gCDrsKnsi53snYAg7IiY7Iut64WE7J20IOyngOuCmOuPhCDri6zrnbzsp4Dsp4Ag7JWK7JWY7Iq164uI64ukLiDstZzqt7zrk6TslrQg7Iug7Jqp7Lm065Oc66GcIOuCqeu2gOqwgCDqsIDriqXtlbTsoYzri6Tqs6DripQg7ZWY7KeA66eMIDEl64KYIOuQmOuKlCZuYnNwO+y5tOuTnCDsiJjsiJjro4wg65iQ!
 7ZWcJm5ic3A764Kp7IS47J6Q7J2YIOu2gOuLtOyduCDsoJDsnYQg6rOg66Ck7ZWY66m0IOydtOuKlCA8c3Ryb25nPuqwgOyCsOyEuOyZgCDri6TrpoQg7JeG64qUIOu2iOydtOydtTwvc3Ryb25nPuydtOudvCDrs7wg7IiYIOyeiOyKteuLiOuLpC4g7J2067+Q66eMIOyVhOuLiOudvCZuYnNwO+qwgeyihSDshLjslaEg6rCQ66m0IOuTsSDsobDshLgg7Zic7YOd7J2AIDxzdHJvbmc+67O17J6h7ZWcIOyalOqxtDwvc3Ryb25nPuydhCDqtazruYTtlbTslbzrp4wg7KCB7Jqp67Cb7J2EIOyImCDsnojslrQg7KCV67aA64qUIOuCqeyEuOyekOuTpOyXkOuKlCDqsrDsvZQg7Lmc7KCI7ZWY7KeAIOyViuydgCDtmITsi6TsnoXri4jri6QuPC9zcGFuPjwvcD48cD48YnI+PC9wPjxwIGFsaWduPSJqdXN0aWZ5IiBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMnB0OyI+Jm5ic3A7PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij4yMDE464WEIOyYrO2VtOuPhCDshozrk53shLjrspXsnbQg7JWE656Y7JmAIOqwmeydtCDqsJzsoJXrkJjslrQg6riw7JeFIOuwjyBDRU/qu5jshJzripQg67mg66W4IOuMgOu5hOulvCDtlZjshZTslbwg7IaM7KSR7ZWcIOyerOyCsOydhCDsp4Dtgqwg7IiYIOyeiOyKteuLiOuLpC48!
 L3NwYW4+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyBsaW5lLWhlaWdodDogMC41OyI+PGZvbnQgc2l6ZT0iMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogMTJwdDsiPuKAizwvc3Bhbj48L2ZvbnQ+PGJyPjwvcD48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMnB0OyI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzdHJvbmc+Jmx0OzIwMTjrhYQg6rCc7KCVIOyEuOycqOqzvCDsho3sgrDtkZwmZ3Q7Jm5ic3A7PC9zdHJvbmc+PC9wPjwvc3Bhbj48L2ZvbnQ+PGZvbnQgc2l6ZT0iMyI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxpbWcgd2lkdGg9IjkwMSIgaGVpZ2h0PSI0NzciIGNsYXNzPSJ0eGMtaW1hZ2UiIHN0eWxlPSJ3aWR0aDogNTE2cHg7IGhlaWdodDogMjc4cHg7IGNsZWFyOiBub25lOyBmbG9hdDogbm9uZTsiIHNyYz0iaHR0cHM6Ly9kaXJlY3RzZW5kLmNvLmtyL3VwbG9hZF9pbWFnZXMvMTUxNjE1MDEwNGJmYWM4M2QyNDNmNTc3NGQyNDEyZDllNjlkZDNhM2Y4LmpwZyI+PC9wPjxkaXYgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjwvZGl2PjxwPjwvcD48L2ZvbnQ+PGZvbnQgc2l6ZT0iMyI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzcGFuIHN0eWxlPSJjb2xvcjo!
 gcmdiKDAsIDAsIDApOyBmb250LXNpemU6IDlwdDsiPmV4KSDsho3sgrDtkZwg6rOE7IKwIOuwqeuylTxicj48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogOXB0OyI+LSDshozrk53snbQgNeyynOunjOybkOyduCDqsr3smrAgOiA17LKc66eM7JuQIFggMjQlIC0gNTIy66eM7JuQID0gNjc466eM7JuQPC9zcGFuPjxzcGFuPjxicj48L3NwYW4+PHNwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogOXB0OyI+LSDshozrk53snbQgMeyWtSA47LKc66eM7JuQ7J24IOqyveyasCA6IDHslrU47LKc66eM7JuQIFggMzglIC0gMSw5NDDrp4zsm5AgPSA0LDkwMOunjOybkDwvc3Bhbj48YnI+PC9zcGFuPjxzcGFuPjxicj48L3NwYW4+PC9wPjwvZm9udD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMnB0OyI+Jm5ic3A7PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7qsJzsoJUg7IaM65Od7IS467KV7J2AIOyLoOyEpOuQmOuKlCDstZzqs6Ag7IS47Jyo6rO8IOuIhOynhCDqtazqsITsnZgg7LaU6rCA66GcJm5ic3A76rOg7IaM65Od7J6Q7JeQ6rKM64qUIOyEuOu2gOuLtOydtCDrjZTsmrEg6rCA7KSR65CY7JeI7Iq164uI64ukLiDtirntnogg7KSR7IaM6riw7JeF7J2YIENFT+q7mOy!
 EnOuKlCDtj4nqt6Drs7Tri6Qg64aS7J2AIOyImOykgOydmCDshozrk53snYQmbmJzcDvsp4DquInrsJvqs6Ag6rOE7Iuc6riw7JeQIOyEuOuylSDqsJzsoJUg7IKs7ZWt7J2YIOyYge2WpeydhCDrp47snbQg67Cb7J2EIOyImCDrsJbsl5Ag7JeG7Iq164uI64ukLiZuYnNwOyZuYnNwO+q3vOuhnOyGjOuTneydtCDrp47snYzsl5Drj4QmbmJzcDvshLjrspXsg4Eg6rO17KCc7JWh7J2AIO2EsOustOuLiCDsl4bsnbQg7KCB7Ja0IOyGjOuTneyEuOyZgCDso7zrr7zshLjrpbwg7Y+s7ZWo7ZWY66m0IOyGjOuTneydmCDqsbDsnZggPHN0cm9uZz7soIjrsJjsl5Ag6rCA6rmM7Jq0IOq4iOyVoeydhCDshLjquIg8L3N0cm9uZz7snLzroZwg64Kp67aA7ZW07JW8IO2VmOuKlCDsi5zrjIDqsIAg64+E656Y7ZWY7JiA7Iq164uI64ukLiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogMTBwdDsiPijqt7zroZzshozrk50gMeyWteybkCDstIjqs7zsi5wg6rO17KCc7JyoIDIlKTwvc3Bhbj48L3NwYW4+PC9mb250PjwvcD48Zm9udCBzaXplPSIzIj48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjwvZm9udD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsiPiZuYnNwO+yggO2drCDtlLzsoJzsnbTsu6jshKTtjIXsl5DshJzripQg6rOg7IaM65OdIENFT+u2hOuTpOydmCDsoIjshLgg64+E7Jqw66+466GcIOuCmOyEnC!
 A8c3Ryb25nPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDI1NSwgMCwgMCk7Ij7qt7zroZzshozrk53qs7wg67mE6rWQ7ZWY66m0IDgwJSDsoIjqsJA8L3NwYW4+PC9zdHJvbmc+65CcIOygiOyEuCDshJzruYTsiqTrpbwg7KCc6rO17ZW0IOuTnOumrOqzoOyekCDtlanri4jri6QuIO2YhOq4iCDsnbzsi5zrtogg64Kp67aA66W8IOybkOy5meycvOuhnCDtlZjripQg7IS46riI64Kp67aA64qUIOygiOyEuOunjCDshLHqs7XtlZjsl6zrj4Qg7JeE7LKt64KcIO2YhOq4iO2dkOumhCDqsJzshKDtmqjqs7zrpbwg6rCA7KC47Jio64uk6rOgIO2VoCDsiJgg7J6I7Iq164uI64ukLiDsi6TsoJzroZwg7IiY66eO7J2AIENFT+q7mOyEnOuPhCDtlLzsoJzsnbTsu6jshKTtjIXsnZgg7KCI7IS4IOyEnOu5hOyKpOuhnCZuYnNwO+2BsCDrp4zsobHsnYQg7Ja76rOgIOqzhOyLreuLiOuLpC48L3NwYW4+PC9mb250PjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+Jm5ic3A7PHN0cm9uZz7tlLzsoJzsnbTsu6jshKTtjIU8L3N0cm9uZz7snZggPC9zcGFuPjxzdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7tirntl4jsnpDrs7jtmZQ8L3NwYW4+PC9zdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMC!
 k7Ij7rnbwg67aI66as64qUIOyCsOyXheyerOyCsOq2jOydhCDtmZzsmqntlZwmbmJzcDvsu6jshKTtjIXsnYAmbmJzcDvqt7zroZzshozrk53shLjsnZggMjAl67CW7JeQIOyViOuQmOuKlCDshLjquIjsnLzroZwgQ0VP7J2YJm5ic3A77ZmV7Iuk7ZWcIOygiOyEuCDrj4TsmrDrr7jroZwg7J6Q66as66ek6rmA7ZWY7JiA7Iq164uI64ukLiDslYTrnpjsnZgg7ZGc64qUIOyGjOuTnSDrtoTrpZjsl5Ag65Sw66W4IOyEuOq4iCDrgqnrtoDslaEg67mE6rWQ7J6F64uI64ukLiZuYnNwOzwvc3Bhbj48L3A+PHNwYW4+PHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+PGJyPjwvcD48cCBhbGlnbj0iY2VudGVyIiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGltZyB3aWR0aD0iNzk5IiBoZWlnaHQ9IjMzOCIgY2xhc3M9InR4Yy1pbWFnZSIgc3R5bGU9IndpZHRoOiA2MTlweDsgaGVpZ2h0OiAyNDlweDsgY2xlYXI6IG5vbmU7IGZsb2F0OiBub25lOyIgc3JjPSJodHRwczovL2RpcmVjdHNlbmQuY28ua3IvdXBsb2FkX2ltYWdlcy8xNTE2MTgzOTkyNmI1NmUzNDg2YTNmOTIyYWIzOTAyYjg0MzZlMzQyYjAuanBnIj48ZGl2IGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48L2Rpdj48cD48L3A+PHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+PGJyPjwvcD48cD48L3A+PC9zcGFuPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPiZuYnNwOzxzcGFuIHN0eWxlPSJjb2xvcjogc!
 mdiKDAsIDAsIDApOyI+7ZGc7JeQIOydmO2VmOuptCZuYnNwO+qwmeydgCAxMOyWteybkOydmCDshozrk53snbQg67Cc7IOd7ZWY7JiA7Ja064+EIOyGjOuTneydmCDsooXrpZjsl5Ag65Sw6528IOyLpOyImOugueyVoeydgCA8c3Ryb25nPjPslrXsm5A8L3N0cm9uZz4g7J207IOBJm5ic3A77LCo7J206rCAIOuCqeuLiOuLpC4g66ek64WEIOqzoOycqOydmCDshLjquIjrtoDri7TsnYQg7IiY67CY7ZWY64qUIOq3vOuhnOyGjOuTneqzvCDrsLDri7nquIgg7J247LacIOuMgOyLoOyXkCDtlLzsoJzsnbTsu6jshKTtjIXsnZggPC9zcGFuPjxzdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7tirntl4jsnpDrs7jtmZQ8L3NwYW4+PC9zdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7rpbwg6rK97ZeY7ZWY7Iuc7Ja0Jm5ic3A77IiY7LKc66eM7JuQIOuCtOyngCA8c3Ryb25nPuyImOyWteybkOydmCDsoIjshLjtmqjqs7w8L3N0cm9uZz7smYAg64+Z7Iuc7JeQIOq4sOyXheydmCDquLDsiKDroKXrj4Qg7ZmV67O07ZWY7Iuc64qUIDIwMTjrhYTrj4Qg7ZWc7ZW06rCAIOuQmOyLnOq4uCDrsJTrno3ri4jri6QuIDwvc3Bhbj48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+642UIOyekOyEu!
 O2VnCDsgqztla3snYAg7JWE656Y7J2YIOyXsOudveyymOuhnCDrrLjsnZgg7KO87Iuc66m0IOu5oOuluCDsi5zsnbzrgrTsl5Ag67Cp66y4IOyDgeuLtCDrk5zrpqzqsqDsirXri4jri6QuJm5ic3A7PC9zcGFuPjxwPjwvcD48cCBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPiZuYnNwOzwvZm9udD48c3BhbiBsYW5nPSJFTi1VUyIgc3R5bGU9ImNvbG9yOiBibGFjazsgZm9udC1zaXplOiAxMnB0OyBtc28tYmlkaS1mb250LWZhbWlseTogQXJpYWw7IG1zby1hc2NpaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWFzY2lpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1oYW5zaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWhhbnNpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1mb250LWtlcm5pbmc6IDBwdDsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPiZuYnNwOzwvZm9udD48L3NwYW4+PHNwYW4gbGFuZz0iRU4tVVMiIHN0eWxlPSJjb2xvcjogYmxhY2s7IG1zby1iaWRpLWZvbnQtZmFtaWx5OiBBcmlhbDsgbXNvLWFzY2lpLWZvbnQtZmFtaWx5OiDrp5HsnYAg6rOg65SVOyBtc28tYXNjaWktdGhlbWUtZm9udDogbWlub3ItZmFyZWFzdDsgbXNvLWhhbnNpLWZvbnQtZmFtaWx5OiDrp5HsnYAg6rOg65SVOyBtc28taGFuc2ktdGhlbWUtZm9udDogbWlub3ItZmFyZWFzdDsgbXNvLWZvbnQta2VybmluZzogMHB0OyBtc28tYmlkaS1mb250LXNpemU6IDEwLjBwdDsiPjxmb250IGZhY2U9IuunkeydgCDq!
 s6DrlJUiPiZuYnNwOzwvZm9udD48L3NwYW4+PC9wPjxwPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9ImJhY2tncm91bmQ6IHdoaXRlOyBtYXJnaW46IDBjbSAyNy4xcHQgMHB0IDBjbTsgdGV4dC1hbGlnbjogbGVmdDsgbGluZS1oZWlnaHQ6IG5vcm1hbDsgLW1zLXdvcmQtYnJlYWs6IGtlZXAtYWxsOyBtc28tcGFnaW5hdGlvbjogd2lkb3ctb3JwaGFuOyBtc28tcGFyYS1tYXJnaW4tdG9wOiAwY207IG1zby1wYXJhLW1hcmdpbi1yaWdodDogMi43MWdkOyBtc28tcGFyYS1tYXJnaW4tYm90dG9tOiAuMDAwMXB0OyBtc28tcGFyYS1tYXJnaW4tbGVmdDogMGNtOyI+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHNwYW4gbGFuZz0iRU4tVVMiIHN0eWxlPSJjb2xvcjogYmxhY2s7IGZvbnQtc2l6ZTogMTFwdDsgbXNvLWJpZGktZm9udC1mYW1pbHk6IEFyaWFsOyBtc28tYXNjaWktZm9udC1mYW1pbHk6IOunkeydgCDqs6DrlJU7IG1zby1hc2NpaS10aGVtZS1mb250OiBtaW5vci1mYXJlYXN0OyBtc28taGFuc2ktZm9udC1mYW1pbHk6IOunkeydgCDqs6DrlJU7IG1zby1oYW5zaS10aGVtZS1mb250OiBtaW5vci1mYXJlYXN0OyBtc28tZm9udC1rZXJuaW5nOiAwcHQ7IG1zby1iaWRpLWZvbnQtc2l6ZTogMTIuMHB0OyI+PHN0cm9uZz5QSkNvbnN1bHRpbmcgKDwvc3Ryb25nPjxzdHJvbmc+IDwvc3Ryb25nPjxhIGhyZWY9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci9pbmRleC5waHAvbWFpbF9yZXBvcnRf!
 YXBpL2NsaWNrLzEwMjQ2NzUvYUhSMGNEb3ZMM2QzZHk1d2FtTnZibk4xYkhScGJtY3VibVYwTHcvMjYyNzA3NDI0L21rdEBjb210cnVlLmNvbS8xIiB0YXJnZXQ9Il9ibGFuayI+PHN0cm9uZz5odHRwOi8vd3d3LnBqY29uc3VsdGluZy5uZXQ8L3N0cm9uZz48L2E+Jm5ic3A7KTwvc3Bhbj48L2ZvbnQ+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG1zby1wYXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48Zm9udCBmYWNlPSLrp5HsnYAg6rOg65SVIj48YiBzdHlsZT0ibXNvLWJpZGktZm9udC13ZWlnaHQ6IG5vcm1hbDsiPjxzcGFuIGxhbmc9IkVOLVVTIiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMXB0OyBtc28tYmlkaS1mb250LWZhbWlseTogQXJpYWw7IG1zby1hc2NpaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWFzY2lpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1oYW5zaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWhhbnNpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1mb250LWtlcm5pbmc6IDBwdDsgbXN!
 vLWJpZGktZm9udC1zaXplOiAxMi4wcHQ7Ij7shJzsmrjtirnrs4Tsi5wg6rCV64Ko6rWsIO2FjO2XpOuegOuhnDgy6ri4IDE1ICjrjIDsuZjrj5ksIOuUlOyVhOydtO2DgOybjCk5NzTtmLg8L3NwYW4+PC9iPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxiIHN0eWxlPSJtc28tYmlkaS1mb250LXdlaWdodDogbm9ybWFsOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogMTFwdDsiPlRFTC4gMDItNTAxLTcyNDQmbmJzcDsmbmJzcDsmbmJzcDsgRkFYLiAwNTAtNDM4OS05NDE2PC9zcGFuPjwvYj48L2ZvbnQ+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw!
 7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG1zby1wYXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48Zm9udCBmYWNlPSLrp5HsnYAg6rOg65SVIj48YiBzdHlsZT0ibXNvLWJpZGktZm9udC13ZWlnaHQ6IG5vcm1hbDsiPjxzcGFuIGxhbmc9IkVOLVVTIiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMXB0OyBtc28tYmlkaS1mb250LWZhbWlseTogQXJpYWw7IG1zby1hc2NpaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWFzY2lpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1oYW5zaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWhhbnNpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1mb250LWtlcm5pbmc6IDBwdDsgbXNvLWJpZGktZm9udC1zaXplOiAxMi4wcHQ7Ij5Nb2JpbGUuIDAxMC01ODEyLTEzMTIgLCAwMTAtMjAxOS0yODMxPC9zcGFuPjwvYj48L2ZvbnQ+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG!
 1zby1wYXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48Zm9udCBmYWNlPSLrp5HsnYAg6rOg65SVIj48YiBzdHlsZT0ibXNvLWJpZGktZm9udC13ZWlnaHQ6IG5vcm1hbDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyBmb250LXNpemU6IDExcHQ7Ij5FLW1haWwuIHBqY29uc3VsdGluZ0DrhKTsnbTrsoTrqZTsnbw8L3NwYW4+PC9iPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6IDExcHQ7Ij48c3Ryb25nPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+4oCLQmxvZy4gPC9zcGFuPjwvc3Ryb25nPjxhIGhyZWY9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci9pbmRleC5waHAvbWFpbF9yZXBvcnRfYXBpL2NsaWNrLzEwMjQ2NzUvYUhSMGNEb3ZMMkpzYjJjdWJtRj!
 JaWEl1WTI5dEwzQnFZMjl1YzNWc2RHbHVady8yNjI3MDc0MjQvbWt0QGNvbXRydWUuY29tLzIiIHRhcmdldD0iX2JsYW5rIj48c3Ryb25nPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+aHR0cDovL2Jsb2cubmF2ZXIuY29tL3BqY29uc3VsdGluZzwvc3Bhbj48L3N0cm9uZz48L2E+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6IDExcHQ7Ij48YnI+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvb!
 TogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6IDExcHQ7Ij48dT48L3U+PC9zcGFuPjwvZm9udD48cCBhbGlnbj0iY2VudGVyIiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxicj48L3A+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48L3A+PHU+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxpbWcgd2lkdGg9IjEyOTciIGhlaWdodD0iNjcwIiBjbGFzcz0idHhjLWltYWdlIiBzdHlsZT0id2lkdGg6IDU0MnB4OyBoZWlnaHQ6IDI3NnB4OyBjbGVhcjogbm9uZTsgZmxvYXQ6IG5vbmU7IiBzcmM9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci91cGxvYWRfaW1hZ2VzLzE1MTQ4MTkwNzlhZjcxOTg4NDM5MDdjNDYwNmI4ZDEwNWNmOThlNmI5Zi5wbmciPjxkaXYgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjwvZGl2PjxwPjwvcD48L3U+PC9mb250PjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBsZWZ0OyI+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHU+IDwvdT48L2ZvbnQ+PC9wPjxwPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9ImJhY2tncm91bmQ6IHdoaXRlOyBtYXJnaW46IDBjbSAyNy4xcHQgMHB0IDBjbTsgdGV4dC1hbGlnbjogbGVmdDsgb!
 GluZS1oZWlnaHQ6IG5vcm1hbDsgLW1zLXdvcmQtYnJlYWs6IGtlZXAtYWxsOyBtc28tcGFnaW5hdGlvbjogd2lkb3ctb3JwaGFuOyBtc28tcGFyYS1tYXJnaW4tdG9wOiAwY207IG1zby1wYXJhLW1hcmdpbi1yaWdodDogMi43MWdkOyBtc28tcGFyYS1tYXJnaW4tYm90dG9tOiAuMDAwMXB0OyBtc28tcGFyYS1tYXJnaW4tbGVmdDogMGNtOyI+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTFwdDsiPjx1Pjxicj48L3U+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiAwLjU7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyA8L2ZvbnQ+PC9wPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxwIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGNlbnRlcjsgbGluZS1oZWlnaHQ6IG5v!
 cm1hbDsgLW1zLXdvcmQtYnJlYWs6IGtlZXAtYWxsOyBtc28tcGFnaW5hdGlvbjogd2lkb3ctb3JwaGFuOyBtc28tcGFyYS1tYXJnaW4tdG9wOiAwY207IG1zby1wYXJhLW1hcmdpbi1yaWdodDogMi43MWdkOyBtc28tcGFyYS1tYXJnaW4tYm90dG9tOiAuMDAwMXB0OyBtc28tcGFyYS1tYXJnaW4tbGVmdDogMGNtOyI+PGltZyB3aWR0aD0iMTM5NCIgaGVpZ2h0PSIxOTgiIGNsYXNzPSJ0eGMtaW1hZ2UiIHN0eWxlPSJ3aWR0aDogNDA4cHg7IGhlaWdodDogNTlweDsgY2xlYXI6IG5vbmU7IGZsb2F0OiBub25lOyIgc3JjPSJodHRwczovL2RpcmVjdHNlbmQuY28ua3IvdXBsb2FkX2ltYWdlcy8xNTExOTE2MTM3MjQ2OTc2ODM0NThlMjQ0N2ViZDlmZDI1ZWZkYmNkYWQucG5nIj48ZGl2IGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48L2Rpdj48cD48L3A+PHA+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTFwdDsiPu+7vzwvc3Bhbj4mbmJzcDs8L3A+PHA+PC9wPjwvZm9udD48cCBhbGlnbj0iY2VudGVyIiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG1zby1w!
 YXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48L3A+PC90ZD48L3RyPjwvdGJvZHk+PC90YWJsZT48cD48L3A+PC9zcGFuPjwvZm9udD48cD48YnI+PC9wPgkJCQoJCQkJCTwvZGl2PgkKCQkKCQkJCQkJCTwhLS0gc3RhcnQgZm9vdGVyIC0tPgoKCQkJPHRhYmxlIHdpZHRoPSIxMDAlImJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIxNSIgc3R5bGU9ImJvcmRlcjpub25lIj4KCQkJCTx0Ym9keT4KCQkJCQk8dHI+CgkJCQkJCQkJCQkJCQk8dGQgaWQ9InByZXZpZXdfbG9nbyIgd2lkdGg9IjE1MCIgYmdjb2xvcj0iI2Y1ZjVmNSIgdmFsaWduPSJib3R0b20iIHN0eWxlPSJtYXgtd2lkdGg6MTUwcHg7cGFkZGluZzoxNXB4O2JvcmRlcjpub25lOyI+CgkJCQkJCQkJPGltZyBpZD0idGVtcF9sb2dvX2ltYWdlIiBzcmM9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci91cGxvYWRfaW1hZ2VzLzE1MTA3MzEyNjc1MDcxM2Q4NWNhOTYxZWJiYzc2MTU1MTFjMjg0NDQxZS5qcGciIHN0eWxlPSJtYXJnaW46YXV0bzttYXgtd2lkdGg6MTUwcHg7IiBhbHQ9ImxvZ28iPgoJCQkJCQkJPC90ZD4KCQkJCQkJCQkJCQkJPHRkIGJnY29sb3I9IiNmNWY1ZjUiIHZhbGlnbj0ibWlkZGxlIiBzdHlsZT0icGFkZGluZzoxNXB4O2JvcmRlcjpub25lO2ZvbnQtZmFtaWx5OidOYW51bUJhcnVuR290aGljJywnTWFsZ3VuIEdvdGhpYycsJ05hbnVtR290aGljJywn66eR7J2AIOqzoOuUlScgLCfrgpjriJQg6rOg65SVJyxkb3R1bSxIZWx2ZXRpY2Esc2Fucy1!
 zZXJpZjtmb250LXNpemU6MTJweDtsZXR0ZXItc3BhY2luZzotMC4zNXB4O2NvbG9yOiM2NjYiPgoJCQkJCQkJCQkJCQkJCQk8cCBzdHlsZT0ibWFyZ2luOjA7dGV4dC1hbGlnbjpsZWZ0O2xpbmUtaGVpZ2h0OjE4cHg7Ij4KCQkJCQkJCQkJCQkJCQkJCQkJ67O466mU7J287J2AIDIwMTgtMDEtMjIgMDA6MTk6NDQg6riw7KSALCDtmozsm5Dri5jsnZgg7IiY7Iug64+Z7J2YIOyXrOu2gOulvCDtmZXsnbjtlZwg6rKw6rO8IO2ajOybkOuLmOq7mOyEnCDsiJjsi6Drj5nsnZjrpbwg7ZWY7IWo6riw7JeQIOuwnOyGoeuQmOyXiOyKteuLiOuLpC4JCQkJCQkJCTwvcD4KCQkJCQkJCQoJCQkJCQkJCQkJCQkJCQk8cCBzdHlsZT0ibWFyZ2luOjA7dGV4dC1hbGlnbjpsZWZ0O2xpbmUtaGVpZ2h0OjE4cHg7Ij4KCQkJCQkJCQkJ66mU7J28IOyImOyLoOydhCDsm5DsuZgg7JWK7Jy87Iuc66m0IDxhIHRhcmdldD0nX2JsYW5rJyBocmVmPSdodHRwczovL2RpcmVjdHNlbmQuY28ua3IvaW5kZXgucGhwL21haWxfcmVwb3J0X2FwaS9yZWplY3QvSy8xNTY0NzA1OTMvMjYyNzA3NDI0L21rdEBjb210cnVlLmNvbSc+PGI+W+yImOyLoOqxsOu2gF08L2I+PC9hPuulvCDtgbTrpq3tlZjshLjsmpQuPGJyIC8+SWYgeW91IGRvbid0IHdhbnQgdGhpcyB0eXBlIG9mIGluZm9ybWF0aW9uIG9yIGUtbWFpbCwgcGxlYXNlIGNsaWNrIHRoZSA8YSB0YXJnZXQ9J19ibGFuaycgaHJlZj0naHR0cHM6Ly9kaXJlY3RzZW5kLmNvLmtyL2luZGV!
 4LnBocC9tYWlsX3JlcG9ydF9hcGkvcmVqZWN0L0UvMTU2NDcwNTkzLzI2MjcwNzQyNC9ta3RAY29tdHJ1ZS5jb20nPjxiPlt1bnN1YnNjcmlwdGlvbl08L2I+PC9hPgkJCQkJCQkJPC9wPgoJCQkJCQkJCgkJCQkJCQkJCQkJCQkJCTxwIGNsYXNzPSJzZW5kZXJfaW5mbyIgc3R5bGU9InRleHQtYWxpZ246bGVmdDtsaW5lLWhlaWdodDoxOHB4OyI+CgkJCQkJCQkJCeyCrOyXheyekCDrk7HroZ3rsojtmLg6NTEwLTE2LTUyOTcxIOyGjOyerOyngDrshJzsmrjtirnrs4Tsi5wg6rCV64Ko6rWsIO2FjO2XpOuegOuhnDgy6ri4IDE1IDk3NO2YuCBURUw6MDItNTAxLTcyNDQgPGJyIC8+RW1haWw6IDxhIGhyZWY9J21haWx0bzpwamNvbnN1bHRpbmdAbmF2ZXIuY29tJz5wamNvbnN1bHRpbmdAbmF2ZXIuY29tPC9hPgkJCQkJCQkJPC9wPgoJCQkJCQkJCQkJCQkJPC90ZD4KCQkJCQk8L3RyPgoJCQkJPC90Ym9keT4KCQkJPC90YWJsZT4KCQkJPCEtLSBlbmQgZm9vdGVyIC0tPgoJCQkKCQkJPCEtLSBvcGVuIHRlbXBsYXRlIC0tPgoJCQk8aW1nIHNyYz0naHR0cHM6Ly9kaXJlY3RzZW5kLmNvLmtyL2luZGV4LnBocC9tYWlsX3JlcG9ydF9hcGkvb3Blbi8xMDI0Njc1LzI2MjcwNzQyNC9ta3RAY29tdHJ1ZS5jb20nIHN0eWxlPSdkaXNwbGF5Om5vbmUnPgkJCQoJCTwvZGl2PgoJCTwhLS0gZW5kIGRpdiBmaXJzdCAtLT4KPC9odG1sPgo=

----82be5ca2-6dee-48ed-b547-ff9b31858929
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64

PGh0bWwgbGFuZz0ia28iPgo8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CgoJPGRpdiBpZD0iZHNfYm94IiBzdHlsZT0iZm9udC1mYW1pbHk6ICfrp5HsnYAg6rOg65SVJywn64KY64iUIOqzoOuUlScsZG90dW0sSGVsdmV0aWNhLHNhbnMtc2VyaWY7bGluZS1oZWlnaHQ6MS41O2ZvbnQtc2l6ZToxMnB4O2NvbG9yOiM2NjY7KndvcmQtYnJlYWs6YnJlYWstYWxsOy1tcy13b3JkLWJyZWFrOmJyZWFrLWFsbDtwYWRkaW5nOjBweCAxMHB4OyI+CgkKCQk8ZGl2IGNsYXNzPSJkc19hcnRpY2xlIiBzdHlsZT0iY2xlYXI6Ym90aDttYXJnaW46M2VtIDAiPgkKCQkJPHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyBsaW5lLWhlaWdodDogMC41OyI+Jm5ic3A7PC9wPjxmb250IHNpemU9IjMiPjxwIHN0eWxlPSJsaW5lLWhlaWdodDogMC41OyI+PGJyPjwvcD48c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxMnB0OyI+PHAgc3R5bGU9ImxpbmUtaGVpZ2h0OiAwLjU7Ij48YnI+PHRhYmxlIGNsYXNzPSJfX3NlX3RibCIgc3R5bGU9ImJvcmRlci13aWR0aDogMXB4IDFweCAwcHggMHB4OyBib3JkZXItc3R5bGU6IHNvbGlkIHNvbGlkIG5vbmUgbm9uZTsgYm9yZGVyLWNvbG9yOiByZ2IoMjA0LCAyMDQsIDIwNCkgcmdiKDIwNCwgMjA0LCAyMDQpIGN1cnJlbnRDb2xvciBjdXJyZW50Q29sb3I7IGJvcmRlci1pbWFnZTogbm9uZTsiIGJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nP!
 SIwIj48dGJvZHk+PHRyPjx0ZCBzdHlsZT0iYm9yZGVyLXdpZHRoOiAwcHggMHB4IDFweCAxcHg7IGJvcmRlci1zdHlsZTogbm9uZSBub25lIHNvbGlkIHNvbGlkOyBib3JkZXItY29sb3I6IGN1cnJlbnRDb2xvciBjdXJyZW50Q29sb3IgcmdiKDIwNCwgMjA0LCAyMDQpIHJnYigyMDQsIDIwNCwgMjA0KTsgYm9yZGVyLWltYWdlOiBub25lOyB3aWR0aDogODY0cHg7IGhlaWdodDogMTg3MHB4OyBiYWNrZ3JvdW5kLWNvbG9yOiByZ2IoMjU1LCAyNTUsIDI1NSk7Ij48cD48c3Ryb25nPjwvc3Ryb25nPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48c3Ryb25nPjxicj48L3N0cm9uZz4mbmJzcDs8c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsiPuyghOyekOqysOygnOyImOuLqOydmCDrsJzri6zroZwg7ZmI7Ie87ZWRLCZuYnNwO+yduO2EsOuEt+yHvO2VkSwg7Iud64u5IOyWtOuKkOqzs+ydtOuToCZuYnNwO+qzoOyVoeydmCDrjIDquIjrj4Qg66ek64usIO2VoOu2gOuhnCDqs4TsgrDsnbQg6rCA64ql7ZWcIOyLnOuMgOyeheuLiOuLpC4g6riw7JeF65Ok7J2AJm5ic3A76rOg6rCd7Li17J2YIOuLpOyWke2VnCDqtazrp6QmbmJzcDvsmIjsgrDsl5Ag64yA7J2R7ZWY6rOg7J6QIOqysOygnCDsobDqsbTqs7wg6rKw7KCcIOyImOuLqOydhCDri6Trs4DtmZTtlZjsl6wg66ek7Lac7J2EIOq3ueuMgO2ZlCDtlZjquLAg7JyE7ZW0IOunjuydgCDruYTsmqnsnYQg7KeA6!
 7aI7ZWY66mwIOuFuOugpe2VmOqzoCDsnojsirXri4jri6QuJm5ic3A77ZWA7YWM7YGsIOq4sOyIoOydmCDrsJzri6zroZwg6rCB7KKFIO2OmOydtOuTpOqzvCDsmpTsppgmbmJzcDvsgqztmozsoIEg66y47KCc66GcIOq4iSDrtoDsg4HtlZjqs6Ag7J6I64qUIOqwgOyDge2ZlO2PkOyZgCDqsJnsnYAmbmJzcDvsp4Drtogg7IiY64uo7J20Jm5ic3A77IOd6rmA7Jy866GcJm5ic3A76riw7JeF7J2AIO2VreyDgSDshozruYTsnpDrk6TsnZgg64uI7KaI66W8IOyVnuyEnOqwgOqzoCDsnojsirXri4jri6QuPC9zcGFuPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+Jm5ic3A76re465+s64KYIOyghCDqta3rr7zsnYQg64yA7IOB7Jy866GcIO2VmOuKlCZuYnNwO+yEuOq4iCDrgqnrtoDripQmbmJzcDvsnbTrn7Ag7ZiE7Iuk7JeQ7IScIOyYiOyZuOqwgCDslYTri5Ag7IiYIOyXhuyKteuLiOuLpC4g7KCV67aA64qUIOqzvOyEuCDsnqzsm5Ag7ZmV7Lap7JeQ66eMIOyXtOydhCDsmKzrpqzqs6Ag7IS46riIIOuCqeu2gCDrsKnsi53snYAg7IiY7Iut64WE7J20IOyngOuCmOuPhCDri6zrnbzsp4Dsp4Ag7JWK7JWY7Iq164uI64ukLiDstZzqt7zrk6TslrQg7Iug7Jqp7Lm065Oc66GcIOuCqeu2gOqwgCDqsIDriqXtlbTsoYzri6Tqs6DripQg7ZWY7KeA66eMIDEl64KYIOuQmOuKlCZuYnNwO+y5tOuTnCDsiJjsiJjro4wg65iQ!
 7ZWcJm5ic3A764Kp7IS47J6Q7J2YIOu2gOuLtOyduCDsoJDsnYQg6rOg66Ck7ZWY66m0IOydtOuKlCA8c3Ryb25nPuqwgOyCsOyEuOyZgCDri6TrpoQg7JeG64qUIOu2iOydtOydtTwvc3Ryb25nPuydtOudvCDrs7wg7IiYIOyeiOyKteuLiOuLpC4g7J2067+Q66eMIOyVhOuLiOudvCZuYnNwO+qwgeyihSDshLjslaEg6rCQ66m0IOuTsSDsobDshLgg7Zic7YOd7J2AIDxzdHJvbmc+67O17J6h7ZWcIOyalOqxtDwvc3Ryb25nPuydhCDqtazruYTtlbTslbzrp4wg7KCB7Jqp67Cb7J2EIOyImCDsnojslrQg7KCV67aA64qUIOuCqeyEuOyekOuTpOyXkOuKlCDqsrDsvZQg7Lmc7KCI7ZWY7KeAIOyViuydgCDtmITsi6TsnoXri4jri6QuPC9zcGFuPjwvcD48cD48YnI+PC9wPjxwIGFsaWduPSJqdXN0aWZ5IiBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeTsiPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMnB0OyI+Jm5ic3A7PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij4yMDE464WEIOyYrO2VtOuPhCDshozrk53shLjrspXsnbQg7JWE656Y7JmAIOqwmeydtCDqsJzsoJXrkJjslrQg6riw7JeFIOuwjyBDRU/qu5jshJzripQg67mg66W4IOuMgOu5hOulvCDtlZjshZTslbwg7IaM7KSR7ZWcIOyerOyCsOydhCDsp4Dtgqwg7IiYIOyeiOyKteuLiOuLpC48!
 L3NwYW4+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyBsaW5lLWhlaWdodDogMC41OyI+PGZvbnQgc2l6ZT0iMyI+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogMTJwdDsiPuKAizwvc3Bhbj48L2ZvbnQ+PGJyPjwvcD48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMnB0OyI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzdHJvbmc+Jmx0OzIwMTjrhYQg6rCc7KCVIOyEuOycqOqzvCDsho3sgrDtkZwmZ3Q7Jm5ic3A7PC9zdHJvbmc+PC9wPjwvc3Bhbj48L2ZvbnQ+PGZvbnQgc2l6ZT0iMyI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxpbWcgd2lkdGg9IjkwMSIgaGVpZ2h0PSI0NzciIGNsYXNzPSJ0eGMtaW1hZ2UiIHN0eWxlPSJ3aWR0aDogNTE2cHg7IGhlaWdodDogMjc4cHg7IGNsZWFyOiBub25lOyBmbG9hdDogbm9uZTsiIHNyYz0iaHR0cHM6Ly9kaXJlY3RzZW5kLmNvLmtyL3VwbG9hZF9pbWFnZXMvMTUxNjE1MDEwNGJmYWM4M2QyNDNmNTc3NGQyNDEyZDllNjlkZDNhM2Y4LmpwZyI+PC9wPjxkaXYgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjwvZGl2PjxwPjwvcD48L2ZvbnQ+PGZvbnQgc2l6ZT0iMyI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzcGFuIHN0eWxlPSJjb2xvcjo!
 gcmdiKDAsIDAsIDApOyBmb250LXNpemU6IDlwdDsiPmV4KSDsho3sgrDtkZwg6rOE7IKwIOuwqeuylTxicj48L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogOXB0OyI+LSDshozrk53snbQgNeyynOunjOybkOyduCDqsr3smrAgOiA17LKc66eM7JuQIFggMjQlIC0gNTIy66eM7JuQID0gNjc466eM7JuQPC9zcGFuPjxzcGFuPjxicj48L3NwYW4+PHNwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogOXB0OyI+LSDshozrk53snbQgMeyWtSA47LKc66eM7JuQ7J24IOqyveyasCA6IDHslrU47LKc66eM7JuQIFggMzglIC0gMSw5NDDrp4zsm5AgPSA0LDkwMOunjOybkDwvc3Bhbj48YnI+PC9zcGFuPjxzcGFuPjxicj48L3NwYW4+PC9wPjwvZm9udD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMnB0OyI+Jm5ic3A7PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7qsJzsoJUg7IaM65Od7IS467KV7J2AIOyLoOyEpOuQmOuKlCDstZzqs6Ag7IS47Jyo6rO8IOuIhOynhCDqtazqsITsnZgg7LaU6rCA66GcJm5ic3A76rOg7IaM65Od7J6Q7JeQ6rKM64qUIOyEuOu2gOuLtOydtCDrjZTsmrEg6rCA7KSR65CY7JeI7Iq164uI64ukLiDtirntnogg7KSR7IaM6riw7JeF7J2YIENFT+q7mOy!
 EnOuKlCDtj4nqt6Drs7Tri6Qg64aS7J2AIOyImOykgOydmCDshozrk53snYQmbmJzcDvsp4DquInrsJvqs6Ag6rOE7Iuc6riw7JeQIOyEuOuylSDqsJzsoJUg7IKs7ZWt7J2YIOyYge2WpeydhCDrp47snbQg67Cb7J2EIOyImCDrsJbsl5Ag7JeG7Iq164uI64ukLiZuYnNwOyZuYnNwO+q3vOuhnOyGjOuTneydtCDrp47snYzsl5Drj4QmbmJzcDvshLjrspXsg4Eg6rO17KCc7JWh7J2AIO2EsOustOuLiCDsl4bsnbQg7KCB7Ja0IOyGjOuTneyEuOyZgCDso7zrr7zshLjrpbwg7Y+s7ZWo7ZWY66m0IOyGjOuTneydmCDqsbDsnZggPHN0cm9uZz7soIjrsJjsl5Ag6rCA6rmM7Jq0IOq4iOyVoeydhCDshLjquIg8L3N0cm9uZz7snLzroZwg64Kp67aA7ZW07JW8IO2VmOuKlCDsi5zrjIDqsIAg64+E656Y7ZWY7JiA7Iq164uI64ukLiA8L3NwYW4+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogMTBwdDsiPijqt7zroZzshozrk50gMeyWteybkCDstIjqs7zsi5wg6rO17KCc7JyoIDIlKTwvc3Bhbj48L3NwYW4+PC9mb250PjwvcD48Zm9udCBzaXplPSIzIj48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjwvZm9udD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48Zm9udCBzaXplPSIzIj48c3BhbiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsiPiZuYnNwO+yggO2drCDtlLzsoJzsnbTsu6jshKTtjIXsl5DshJzripQg6rOg7IaM65OdIENFT+u2hOuTpOydmCDsoIjshLgg64+E7Jqw66+466GcIOuCmOyEnC!
 A8c3Ryb25nPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDI1NSwgMCwgMCk7Ij7qt7zroZzshozrk53qs7wg67mE6rWQ7ZWY66m0IDgwJSDsoIjqsJA8L3NwYW4+PC9zdHJvbmc+65CcIOygiOyEuCDshJzruYTsiqTrpbwg7KCc6rO17ZW0IOuTnOumrOqzoOyekCDtlanri4jri6QuIO2YhOq4iCDsnbzsi5zrtogg64Kp67aA66W8IOybkOy5meycvOuhnCDtlZjripQg7IS46riI64Kp67aA64qUIOygiOyEuOunjCDshLHqs7XtlZjsl6zrj4Qg7JeE7LKt64KcIO2YhOq4iO2dkOumhCDqsJzshKDtmqjqs7zrpbwg6rCA7KC47Jio64uk6rOgIO2VoCDsiJgg7J6I7Iq164uI64ukLiDsi6TsoJzroZwg7IiY66eO7J2AIENFT+q7mOyEnOuPhCDtlLzsoJzsnbTsu6jshKTtjIXsnZgg7KCI7IS4IOyEnOu5hOyKpOuhnCZuYnNwO+2BsCDrp4zsobHsnYQg7Ja76rOgIOqzhOyLreuLiOuLpC48L3NwYW4+PC9mb250PjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+Jm5ic3A7PHN0cm9uZz7tlLzsoJzsnbTsu6jshKTtjIU8L3N0cm9uZz7snZggPC9zcGFuPjxzdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7tirntl4jsnpDrs7jtmZQ8L3NwYW4+PC9zdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMC!
 k7Ij7rnbwg67aI66as64qUIOyCsOyXheyerOyCsOq2jOydhCDtmZzsmqntlZwmbmJzcDvsu6jshKTtjIXsnYAmbmJzcDvqt7zroZzshozrk53shLjsnZggMjAl67CW7JeQIOyViOuQmOuKlCDshLjquIjsnLzroZwgQ0VP7J2YJm5ic3A77ZmV7Iuk7ZWcIOygiOyEuCDrj4TsmrDrr7jroZwg7J6Q66as66ek6rmA7ZWY7JiA7Iq164uI64ukLiDslYTrnpjsnZgg7ZGc64qUIOyGjOuTnSDrtoTrpZjsl5Ag65Sw66W4IOyEuOq4iCDrgqnrtoDslaEg67mE6rWQ7J6F64uI64ukLiZuYnNwOzwvc3Bhbj48L3A+PHNwYW4+PHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+PGJyPjwvcD48cCBhbGlnbj0iY2VudGVyIiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PGltZyB3aWR0aD0iNzk5IiBoZWlnaHQ9IjMzOCIgY2xhc3M9InR4Yy1pbWFnZSIgc3R5bGU9IndpZHRoOiA2MTlweDsgaGVpZ2h0OiAyNDlweDsgY2xlYXI6IG5vbmU7IGZsb2F0OiBub25lOyIgc3JjPSJodHRwczovL2RpcmVjdHNlbmQuY28ua3IvdXBsb2FkX2ltYWdlcy8xNTE2MTgzOTkyNmI1NmUzNDg2YTNmOTIyYWIzOTAyYjg0MzZlMzQyYjAuanBnIj48ZGl2IGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48L2Rpdj48cD48L3A+PHAgYWxpZ249Imp1c3RpZnkiIHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5OyI+PGJyPjwvcD48cD48L3A+PC9zcGFuPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPiZuYnNwOzxzcGFuIHN0eWxlPSJjb2xvcjogc!
 mdiKDAsIDAsIDApOyI+7ZGc7JeQIOydmO2VmOuptCZuYnNwO+qwmeydgCAxMOyWteybkOydmCDshozrk53snbQg67Cc7IOd7ZWY7JiA7Ja064+EIOyGjOuTneydmCDsooXrpZjsl5Ag65Sw6528IOyLpOyImOugueyVoeydgCA8c3Ryb25nPjPslrXsm5A8L3N0cm9uZz4g7J207IOBJm5ic3A77LCo7J206rCAIOuCqeuLiOuLpC4g66ek64WEIOqzoOycqOydmCDshLjquIjrtoDri7TsnYQg7IiY67CY7ZWY64qUIOq3vOuhnOyGjOuTneqzvCDrsLDri7nquIgg7J247LacIOuMgOyLoOyXkCDtlLzsoJzsnbTsu6jshKTtjIXsnZggPC9zcGFuPjxzdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7tirntl4jsnpDrs7jtmZQ8L3NwYW4+PC9zdHJvbmc+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7Ij7rpbwg6rK97ZeY7ZWY7Iuc7Ja0Jm5ic3A77IiY7LKc66eM7JuQIOuCtOyngCA8c3Ryb25nPuyImOyWteybkOydmCDsoIjshLjtmqjqs7w8L3N0cm9uZz7smYAg64+Z7Iuc7JeQIOq4sOyXheydmCDquLDsiKDroKXrj4Qg7ZmV67O07ZWY7Iuc64qUIDIwMTjrhYTrj4Qg7ZWc7ZW06rCAIOuQmOyLnOq4uCDrsJTrno3ri4jri6QuIDwvc3Bhbj48cCBhbGlnbj0ibGVmdCIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48YnI+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+642UIOyekOyEu!
 O2VnCDsgqztla3snYAg7JWE656Y7J2YIOyXsOudveyymOuhnCDrrLjsnZgg7KO87Iuc66m0IOu5oOuluCDsi5zsnbzrgrTsl5Ag67Cp66y4IOyDgeuLtCDrk5zrpqzqsqDsirXri4jri6QuJm5ic3A7PC9zcGFuPjxwPjwvcD48cCBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPiZuYnNwOzwvZm9udD48c3BhbiBsYW5nPSJFTi1VUyIgc3R5bGU9ImNvbG9yOiBibGFjazsgZm9udC1zaXplOiAxMnB0OyBtc28tYmlkaS1mb250LWZhbWlseTogQXJpYWw7IG1zby1hc2NpaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWFzY2lpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1oYW5zaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWhhbnNpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1mb250LWtlcm5pbmc6IDBwdDsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPiZuYnNwOzwvZm9udD48L3NwYW4+PHNwYW4gbGFuZz0iRU4tVVMiIHN0eWxlPSJjb2xvcjogYmxhY2s7IG1zby1iaWRpLWZvbnQtZmFtaWx5OiBBcmlhbDsgbXNvLWFzY2lpLWZvbnQtZmFtaWx5OiDrp5HsnYAg6rOg65SVOyBtc28tYXNjaWktdGhlbWUtZm9udDogbWlub3ItZmFyZWFzdDsgbXNvLWhhbnNpLWZvbnQtZmFtaWx5OiDrp5HsnYAg6rOg65SVOyBtc28taGFuc2ktdGhlbWUtZm9udDogbWlub3ItZmFyZWFzdDsgbXNvLWZvbnQta2VybmluZzogMHB0OyBtc28tYmlkaS1mb250LXNpemU6IDEwLjBwdDsiPjxmb250IGZhY2U9IuunkeydgCDq!
 s6DrlJUiPiZuYnNwOzwvZm9udD48L3NwYW4+PC9wPjxwPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9ImJhY2tncm91bmQ6IHdoaXRlOyBtYXJnaW46IDBjbSAyNy4xcHQgMHB0IDBjbTsgdGV4dC1hbGlnbjogbGVmdDsgbGluZS1oZWlnaHQ6IG5vcm1hbDsgLW1zLXdvcmQtYnJlYWs6IGtlZXAtYWxsOyBtc28tcGFnaW5hdGlvbjogd2lkb3ctb3JwaGFuOyBtc28tcGFyYS1tYXJnaW4tdG9wOiAwY207IG1zby1wYXJhLW1hcmdpbi1yaWdodDogMi43MWdkOyBtc28tcGFyYS1tYXJnaW4tYm90dG9tOiAuMDAwMXB0OyBtc28tcGFyYS1tYXJnaW4tbGVmdDogMGNtOyI+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHNwYW4gbGFuZz0iRU4tVVMiIHN0eWxlPSJjb2xvcjogYmxhY2s7IGZvbnQtc2l6ZTogMTFwdDsgbXNvLWJpZGktZm9udC1mYW1pbHk6IEFyaWFsOyBtc28tYXNjaWktZm9udC1mYW1pbHk6IOunkeydgCDqs6DrlJU7IG1zby1hc2NpaS10aGVtZS1mb250OiBtaW5vci1mYXJlYXN0OyBtc28taGFuc2ktZm9udC1mYW1pbHk6IOunkeydgCDqs6DrlJU7IG1zby1oYW5zaS10aGVtZS1mb250OiBtaW5vci1mYXJlYXN0OyBtc28tZm9udC1rZXJuaW5nOiAwcHQ7IG1zby1iaWRpLWZvbnQtc2l6ZTogMTIuMHB0OyI+PHN0cm9uZz5QSkNvbnN1bHRpbmcgKDwvc3Ryb25nPjxzdHJvbmc+IDwvc3Ryb25nPjxhIGhyZWY9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci9pbmRleC5waHAvbWFpbF9yZXBvcnRf!
 YXBpL2NsaWNrLzEwMjQ2NzUvYUhSMGNEb3ZMM2QzZHk1d2FtTnZibk4xYkhScGJtY3VibVYwTHcvMjYyNzA3NDI0L21rdEBjb210cnVlLmNvbS8xIiB0YXJnZXQ9Il9ibGFuayI+PHN0cm9uZz5odHRwOi8vd3d3LnBqY29uc3VsdGluZy5uZXQ8L3N0cm9uZz48L2E+Jm5ic3A7KTwvc3Bhbj48L2ZvbnQ+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG1zby1wYXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48Zm9udCBmYWNlPSLrp5HsnYAg6rOg65SVIj48YiBzdHlsZT0ibXNvLWJpZGktZm9udC13ZWlnaHQ6IG5vcm1hbDsiPjxzcGFuIGxhbmc9IkVOLVVTIiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMXB0OyBtc28tYmlkaS1mb250LWZhbWlseTogQXJpYWw7IG1zby1hc2NpaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWFzY2lpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1oYW5zaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWhhbnNpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1mb250LWtlcm5pbmc6IDBwdDsgbXN!
 vLWJpZGktZm9udC1zaXplOiAxMi4wcHQ7Ij7shJzsmrjtirnrs4Tsi5wg6rCV64Ko6rWsIO2FjO2XpOuegOuhnDgy6ri4IDE1ICjrjIDsuZjrj5ksIOuUlOyVhOydtO2DgOybjCk5NzTtmLg8L3NwYW4+PC9iPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxiIHN0eWxlPSJtc28tYmlkaS1mb250LXdlaWdodDogbm9ybWFsOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiByZ2IoMCwgMCwgMCk7IGZvbnQtc2l6ZTogMTFwdDsiPlRFTC4gMDItNTAxLTcyNDQmbmJzcDsmbmJzcDsmbmJzcDsgRkFYLiAwNTAtNDM4OS05NDE2PC9zcGFuPjwvYj48L2ZvbnQ+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw!
 7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG1zby1wYXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48Zm9udCBmYWNlPSLrp5HsnYAg6rOg65SVIj48YiBzdHlsZT0ibXNvLWJpZGktZm9udC13ZWlnaHQ6IG5vcm1hbDsiPjxzcGFuIGxhbmc9IkVOLVVTIiBzdHlsZT0iY29sb3I6IHJnYigwLCAwLCAwKTsgZm9udC1zaXplOiAxMXB0OyBtc28tYmlkaS1mb250LWZhbWlseTogQXJpYWw7IG1zby1hc2NpaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWFzY2lpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1oYW5zaS1mb250LWZhbWlseTog66eR7J2AIOqzoOuUlTsgbXNvLWhhbnNpLXRoZW1lLWZvbnQ6IG1pbm9yLWZhcmVhc3Q7IG1zby1mb250LWtlcm5pbmc6IDBwdDsgbXNvLWJpZGktZm9udC1zaXplOiAxMi4wcHQ7Ij5Nb2JpbGUuIDAxMC01ODEyLTEzMTIgLCAwMTAtMjAxOS0yODMxPC9zcGFuPjwvYj48L2ZvbnQ+PC9wPjxwIGFsaWduPSJsZWZ0IiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG!
 1zby1wYXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48Zm9udCBmYWNlPSLrp5HsnYAg6rOg65SVIj48YiBzdHlsZT0ibXNvLWJpZGktZm9udC13ZWlnaHQ6IG5vcm1hbDsiPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyBmb250LXNpemU6IDExcHQ7Ij5FLW1haWwuIHBqY29uc3VsdGluZ0DrhKTsnbTrsoTrqZTsnbw8L3NwYW4+PC9iPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6IDExcHQ7Ij48c3Ryb25nPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+4oCLQmxvZy4gPC9zcGFuPjwvc3Ryb25nPjxhIGhyZWY9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci9pbmRleC5waHAvbWFpbF9yZXBvcnRfYXBpL2NsaWNrLzEwMjQ2NzUvYUhSMGNEb3ZMMkpzYjJjdWJtRj!
 JaWEl1WTI5dEwzQnFZMjl1YzNWc2RHbHVady8yNjI3MDc0MjQvbWt0QGNvbXRydWUuY29tLzIiIHRhcmdldD0iX2JsYW5rIj48c3Ryb25nPjxzcGFuIHN0eWxlPSJjb2xvcjogcmdiKDAsIDAsIDApOyI+aHR0cDovL2Jsb2cubmF2ZXIuY29tL3BqY29uc3VsdGluZzwvc3Bhbj48L3N0cm9uZz48L2E+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6IDExcHQ7Ij48YnI+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiBub3JtYWw7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvb!
 TogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6IDExcHQ7Ij48dT48L3U+PC9zcGFuPjwvZm9udD48cCBhbGlnbj0iY2VudGVyIiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPjxicj48L3A+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij48L3A+PHU+PHAgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxpbWcgd2lkdGg9IjEyOTciIGhlaWdodD0iNjcwIiBjbGFzcz0idHhjLWltYWdlIiBzdHlsZT0id2lkdGg6IDU0MnB4OyBoZWlnaHQ6IDI3NnB4OyBjbGVhcjogbm9uZTsgZmxvYXQ6IG5vbmU7IiBzcmM9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci91cGxvYWRfaW1hZ2VzLzE1MTQ4MTkwNzlhZjcxOTg4NDM5MDdjNDYwNmI4ZDEwNWNmOThlNmI5Zi5wbmciPjxkaXYgYWxpZ249ImNlbnRlciIgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjwvZGl2PjxwPjwvcD48L3U+PC9mb250PjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBsZWZ0OyI+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHU+IDwvdT48L2ZvbnQ+PC9wPjxwPjwvcD48cCBhbGlnbj0ibGVmdCIgc3R5bGU9ImJhY2tncm91bmQ6IHdoaXRlOyBtYXJnaW46IDBjbSAyNy4xcHQgMHB0IDBjbTsgdGV4dC1hbGlnbjogbGVmdDsgb!
 GluZS1oZWlnaHQ6IG5vcm1hbDsgLW1zLXdvcmQtYnJlYWs6IGtlZXAtYWxsOyBtc28tcGFnaW5hdGlvbjogd2lkb3ctb3JwaGFuOyBtc28tcGFyYS1tYXJnaW4tdG9wOiAwY207IG1zby1wYXJhLW1hcmdpbi1yaWdodDogMi43MWdkOyBtc28tcGFyYS1tYXJnaW4tYm90dG9tOiAuMDAwMXB0OyBtc28tcGFyYS1tYXJnaW4tbGVmdDogMGNtOyI+PGZvbnQgZmFjZT0i66eR7J2AIOqzoOuUlSI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTFwdDsiPjx1Pjxicj48L3U+PC9zcGFuPjwvZm9udD48L3A+PHAgYWxpZ249ImxlZnQiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGxlZnQ7IGxpbmUtaGVpZ2h0OiAwLjU7IC1tcy13b3JkLWJyZWFrOiBrZWVwLWFsbDsgbXNvLXBhZ2luYXRpb246IHdpZG93LW9ycGhhbjsgbXNvLXBhcmEtbWFyZ2luLXRvcDogMGNtOyBtc28tcGFyYS1tYXJnaW4tcmlnaHQ6IDIuNzFnZDsgbXNvLXBhcmEtbWFyZ2luLWJvdHRvbTogLjAwMDFwdDsgbXNvLXBhcmEtbWFyZ2luLWxlZnQ6IDBjbTsiPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyA8L2ZvbnQ+PC9wPjxmb250IGZhY2U9IuunkeydgCDqs6DrlJUiPjxwIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJiYWNrZ3JvdW5kOiB3aGl0ZTsgbWFyZ2luOiAwY20gMjcuMXB0IDBwdCAwY207IHRleHQtYWxpZ246IGNlbnRlcjsgbGluZS1oZWlnaHQ6IG5v!
 cm1hbDsgLW1zLXdvcmQtYnJlYWs6IGtlZXAtYWxsOyBtc28tcGFnaW5hdGlvbjogd2lkb3ctb3JwaGFuOyBtc28tcGFyYS1tYXJnaW4tdG9wOiAwY207IG1zby1wYXJhLW1hcmdpbi1yaWdodDogMi43MWdkOyBtc28tcGFyYS1tYXJnaW4tYm90dG9tOiAuMDAwMXB0OyBtc28tcGFyYS1tYXJnaW4tbGVmdDogMGNtOyI+PGltZyB3aWR0aD0iMTM5NCIgaGVpZ2h0PSIxOTgiIGNsYXNzPSJ0eGMtaW1hZ2UiIHN0eWxlPSJ3aWR0aDogNDA4cHg7IGhlaWdodDogNTlweDsgY2xlYXI6IG5vbmU7IGZsb2F0OiBub25lOyIgc3JjPSJodHRwczovL2RpcmVjdHNlbmQuY28ua3IvdXBsb2FkX2ltYWdlcy8xNTExOTE2MTM3MjQ2OTc2ODM0NThlMjQ0N2ViZDlmZDI1ZWZkYmNkYWQucG5nIj48ZGl2IGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48L2Rpdj48cD48L3A+PHA+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTogMTFwdDsiPu+7vzwvc3Bhbj4mbmJzcDs8L3A+PHA+PC9wPjwvZm9udD48cCBhbGlnbj0iY2VudGVyIiBzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IG1hcmdpbjogMGNtIDI3LjFwdCAwcHQgMGNtOyB0ZXh0LWFsaWduOiBsZWZ0OyBsaW5lLWhlaWdodDogbm9ybWFsOyAtbXMtd29yZC1icmVhazoga2VlcC1hbGw7IG1zby1wYWdpbmF0aW9uOiB3aWRvdy1vcnBoYW47IG1zby1wYXJhLW1hcmdpbi10b3A6IDBjbTsgbXNvLXBhcmEtbWFyZ2luLXJpZ2h0OiAyLjcxZ2Q7IG1zby1w!
 YXJhLW1hcmdpbi1ib3R0b206IC4wMDAxcHQ7IG1zby1wYXJhLW1hcmdpbi1sZWZ0OiAwY207Ij48L3A+PC90ZD48L3RyPjwvdGJvZHk+PC90YWJsZT48cD48L3A+PC9zcGFuPjwvZm9udD48cD48YnI+PC9wPgkJCQoJCQkJCTwvZGl2PgkKCQkKCQkJCQkJCTwhLS0gc3RhcnQgZm9vdGVyIC0tPgoKCQkJPHRhYmxlIHdpZHRoPSIxMDAlImJvcmRlcj0iMCIgY2VsbHNwYWNpbmc9IjAiIGNlbGxwYWRkaW5nPSIxNSIgc3R5bGU9ImJvcmRlcjpub25lIj4KCQkJCTx0Ym9keT4KCQkJCQk8dHI+CgkJCQkJCQkJCQkJCQk8dGQgaWQ9InByZXZpZXdfbG9nbyIgd2lkdGg9IjE1MCIgYmdjb2xvcj0iI2Y1ZjVmNSIgdmFsaWduPSJib3R0b20iIHN0eWxlPSJtYXgtd2lkdGg6MTUwcHg7cGFkZGluZzoxNXB4O2JvcmRlcjpub25lOyI+CgkJCQkJCQkJPGltZyBpZD0idGVtcF9sb2dvX2ltYWdlIiBzcmM9Imh0dHBzOi8vZGlyZWN0c2VuZC5jby5rci91cGxvYWRfaW1hZ2VzLzE1MTA3MzEyNjc1MDcxM2Q4NWNhOTYxZWJiYzc2MTU1MTFjMjg0NDQxZS5qcGciIHN0eWxlPSJtYXJnaW46YXV0bzttYXgtd2lkdGg6MTUwcHg7IiBhbHQ9ImxvZ28iPgoJCQkJCQkJPC90ZD4KCQkJCQkJCQkJCQkJPHRkIGJnY29sb3I9IiNmNWY1ZjUiIHZhbGlnbj0ibWlkZGxlIiBzdHlsZT0icGFkZGluZzoxNXB4O2JvcmRlcjpub25lO2ZvbnQtZmFtaWx5OidOYW51bUJhcnVuR290aGljJywnTWFsZ3VuIEdvdGhpYycsJ05hbnVtR290aGljJywn66eR7J2AIOqzoOuUlScgLCfrgpjriJQg6rOg65SVJyxkb3R1bSxIZWx2ZXRpY2Esc2Fucy1!
 zZXJpZjtmb250LXNpemU6MTJweDtsZXR0ZXItc3BhY2luZzotMC4zNXB4O2NvbG9yOiM2NjYiPgoJCQkJCQkJCQkJCQkJCQk8cCBzdHlsZT0ibWFyZ2luOjA7dGV4dC1hbGlnbjpsZWZ0O2xpbmUtaGVpZ2h0OjE4cHg7Ij4KCQkJCQkJCQkJCQkJCQkJCQkJ67O466mU7J287J2AIDIwMTgtMDEtMjIgMDA6MTk6NDQg6riw7KSALCDtmozsm5Dri5jsnZgg7IiY7Iug64+Z7J2YIOyXrOu2gOulvCDtmZXsnbjtlZwg6rKw6rO8IO2ajOybkOuLmOq7mOyEnCDsiJjsi6Drj5nsnZjrpbwg7ZWY7IWo6riw7JeQIOuwnOyGoeuQmOyXiOyKteuLiOuLpC4JCQkJCQkJCTwvcD4KCQkJCQkJCQoJCQkJCQkJCQkJCQkJCQk8cCBzdHlsZT0ibWFyZ2luOjA7dGV4dC1hbGlnbjpsZWZ0O2xpbmUtaGVpZ2h0OjE4cHg7Ij4KCQkJCQkJCQkJ66mU7J28IOyImOyLoOydhCDsm5DsuZgg7JWK7Jy87Iuc66m0IDxhIHRhcmdldD0nX2JsYW5rJyBocmVmPSdodHRwczovL2RpcmVjdHNlbmQuY28ua3IvaW5kZXgucGhwL21haWxfcmVwb3J0X2FwaS9yZWplY3QvSy8xNTY0NzA1OTMvMjYyNzA3NDI0L21rdEBjb210cnVlLmNvbSc+PGI+W+yImOyLoOqxsOu2gF08L2I+PC9hPuulvCDtgbTrpq3tlZjshLjsmpQuPGJyIC8+SWYgeW91IGRvbid0IHdhbnQgdGhpcyB0eXBlIG9mIGluZm9ybWF0aW9uIG9yIGUtbWFpbCwgcGxlYXNlIGNsaWNrIHRoZSA8YSB0YXJnZXQ9J19ibGFuaycgaHJlZj0naHR0cHM6Ly9kaXJlY3RzZW5kLmNvLmtyL2luZGV!
 4LnBocC9tYWlsX3JlcG9ydF9hcGkvcmVqZWN0L0UvMTU2NDcwNTkzLzI2MjcwNzQyNC9ta3RAY29tdHJ1ZS5jb20nPjxiPlt1bnN1YnNjcmlwdGlvbl08L2I+PC9hPgkJCQkJCQkJPC9wPgoJCQkJCQkJCgkJCQkJCQkJCQkJCQkJCTxwIGNsYXNzPSJzZW5kZXJfaW5mbyIgc3R5bGU9InRleHQtYWxpZ246bGVmdDtsaW5lLWhlaWdodDoxOHB4OyI+CgkJCQkJCQkJCeyCrOyXheyekCDrk7HroZ3rsojtmLg6NTEwLTE2LTUyOTcxIOyGjOyerOyngDrshJzsmrjtirnrs4Tsi5wg6rCV64Ko6rWsIO2FjO2XpOuegOuhnDgy6ri4IDE1IDk3NO2YuCBURUw6MDItNTAxLTcyNDQgPGJyIC8+RW1haWw6IDxhIGhyZWY9J21haWx0bzpwamNvbnN1bHRpbmdAbmF2ZXIuY29tJz5wamNvbnN1bHRpbmdAbmF2ZXIuY29tPC9hPgkJCQkJCQkJPC9wPgoJCQkJCQkJCQkJCQkJPC90ZD4KCQkJCQk8L3RyPgoJCQkJPC90Ym9keT4KCQkJPC90YWJsZT4KCQkJPCEtLSBlbmQgZm9vdGVyIC0tPgoJCQkKCQkJPCEtLSBvcGVuIHRlbXBsYXRlIC0tPgoJCQk8aW1nIHNyYz0naHR0cHM6Ly9kaXJlY3RzZW5kLmNvLmtyL2luZGV4LnBocC9tYWlsX3JlcG9ydF9hcGkvb3Blbi8xMDI0Njc1LzI2MjcwNzQyNC9ta3RAY29tdHJ1ZS5jb20nIHN0eWxlPSdkaXNwbGF5Om5vbmUnPgkJCQoJCTwvZGl2PgoJCTwhLS0gZW5kIGRpdiBmaXJzdCAtLT4KPC9odG1sPgo=

----82be5ca2-6dee-48ed-b547-ff9b31858929--

Line wrap plain text and HTML parts

enmime does not enforce a line-length on text parts. It should wrap the content in a way that preserves the original bytes upon decoding.

Semantic versioning

Hi!

I'm using this excellent library on one of my project. I'm happy with it, but unfortunately upgrading dependencies breaks my code every now and then.
I know it's still a beta, but I think it would be great to create releases to help dependency management.

Of course I can still pin the commit hash but this is suboptimal. When a BC is introduced I have to try all the intermediate commit hashes between the version I've pinned and the latest release to find the most recent compatible version. This process would be a lot easier with SemVer.

Thanks for your help on this. And thanks again for all your work on this library!

cmds should use filepath not path pkg

path is for URLs, filepath is for OS file path manipulation

cmd/mime-dump/mime-dump.go:7:   "path"
cmd/mime-dump/mime-dump.go:26:  basename := path.Base(os.Args[1])
cmd/mime-extractor/mime-extractor.go:9: "path"
cmd/mime-extractor/mime-extractor.go:44:        basename := path.Base(*mimefile)
cmd/mime-extractor/mime-extractor.go:59:                newFileName := path.Join(*outdir, a.FileName)

Support Content-Transfer-Encoding

It would be really nice to support some transfer encodings when building the email. UTF-8 Base64 is the main one I would like to use, but of course, built in a way to support other encodings.

There is a way to Base64 encode the subject as well.

=?utf-8?B?<SINGLE BASE64 LINE>?= =?utf-8?B?<ANOTHER BASE64 LINE?=

The point is so that the email can be sent without having to worry about special characters.

Would like to know if you like this idea or not?

Create fluent builder struct

Create fluent builder struct to simplify constructing a well formed message

  • Builder
  • Validations
  • Support for net/mail.Address
  • Support for custom headers
  • MIME-Version
  • File Helpers
  • Reply-To?
  • Docs, Examples

Restore the Part's buffer after reading its content

NOTE: this issue is kind of related with the "Address Envelope's Parts with sensible IDs" issue.

Idea:

  • be able to read and store the content from each invidual text/HTML Parts inside an Envelope.
    While recursing through the MIME Part Tree e.g.:
multipart/alternative
|-- text/plain
|-- multipart/related
|     `-- text/html
`-- text/plain

I would like to read and store the content from each invidual text/HTML Part.

Right now, enmime creates two Envelope fields i.e. e.Text and e.HTML.

While creating the Envelope (EnvelopeFromPart), it reads the content buffer for text/HTML parts and appends them to the e.Text/e.HTML fields.

However, when I later try to read the content from one of the text/HTML Part, its content buffer is empty.

-> Ideally, I would like to be able to retrieve the text/HTML content from a specific text/HTML Part.

See this pull request for how this could be achieved: #37

Help with unsupported charsets

I have collected a small list of logs for unsupported charsets. Here's the list:-

  • ISO646-US
  • ISO: Western
  • cp936
  • cp-850
  • 136
  • utf-7
  • ibm850

As far as I understand ISO646-US is "us-ascii", ISO: Western is "iso8859" and cp936 is "gb2312". Is this correct?

I have been unable to figure out the rest of the encodings although cp-850 and ibm850 seem to be the same.

Does anyone have an idea about these charsets and if they can be supported in this library easily?

Email's attachment won't be exported correctly.

I try to export an email's attachment(Zip archive), but that exported file could not be unzip successfully.I compare this file to which exported by emali client, like follows:
50 4B 03 04 14 00 08 00 08 00 EF BF BD 02 29 4A -->export by enmime
50 4B 03 04 14 00 08 00 08 00 C2 02 29 4A 00 00 -->export by email client
It's clearly that the byte 'C2' transfers to 'EF BF BD 02', I also check the implementation of Part's Read method:
return p.utf8Reader.Read(b)
OK, maybe it causes the issue when I need to read a binary file. So can export a METHOD for read the decoded binary content?

Set the Part boundary field for the Envelope's root

In such MIME Tree:

multipart/alternative
|-- text/plain
`-- text/plain

I have observed that enmime doesn't correctly set the Part.boundary field for the root.

Indeed, if I try to read root.boundary or the Part.Parent.boundary for the "text/plain" Parts, it outputs an empty result.

This fix also give us the possibility of simplifying func parseParts(parent *Part, reader *bufio.Reader, boundary string) error into func parseParts(parent *Part, reader *bufio.Reader) error cf. #39

See this pull request for how this could be achieved: #39

Add Encode(io.Writer) method to enmime.Envelope

Implement the ability to create an email with enmime.

Envelope.Encode() should write out a well formed MIME email, providing the Envelope and its associate parts are properly configured.

Other work will need to be done, such as generating unique MIME part boundary strings.

Fix "multipart/altern" check

multipart/altern is not a valid Content-Type:

header.go:      ctMultipartAltern = "multipart/altern"
envelope.go:    if mediatype == ctMultipartAltern {

The code has been with us since early 2014: b986eca

It may not be necessary.

Base64 decoding error

I have an email attachment that is being mishandled. Its a curious thing, probably some funky counting issue with the padding chars.

After some investigation I found that during the buffer sizing, or resizing, it is dropping the last quad of the base64 string... string input length is 12992, but only 12988 characters are being fed to the decoder OR the receiving buffer is sized to 9615 instead of the 9617, causing the last two bytes to be trimmed from the tail of the byte stream.

I don't know precisely which copy operation is causing the miscount and to be fare I have a service running with your processing engine and this fringe case is one out of 60,000 emails with an average of 3 attachments per.

other files process fine... perhaps we could take this offline to exchange my sample file because it contains confidential information and review it in attempt to reproduce the issue with a benign file exhibiting the same features.

fyi, I am able to decode the blob accurately using this:

f, _ := ioutil.ReadFile("base64.txt")
base64Bytes, _ := base64.StdEncoding.DecodeString(string(f))
file, _ := os.Create("decoded.xlsx")
defer file.Close()
writer := bufio.NewWriter(file)
writer.Write(base64Bytes)
defer writer.Flush()

Thoughts?

Inconsistent use of Ptrs for error types

What I did:
N/A

What I expected:
I expect to always receive an Error or and *Error but the Envelope type has a []*Error and the Part type has a []Error

What I got:
N/A

Release or branch I am using:
Master

(Please attach a sample message if you feel it will help reproduce the issue)

// Envelope is a simplified wrapper for MIME email messages.
type Envelope struct {
	...
	Errors      []*Error              // Errors encountered while parsing
	...
}
// Part represents a node in the MIME multipart tree.  The Content-Type, Disposition and File Name
// are parsed out of the header for easier access.
type Part struct {
	...
	Errors      []Error              // Errors encountered while parsing this part
	...
}

I'm happy to make a PR if you agree that this is something which should be addressed. Thanks for the great library, btw!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.