GODT-1650: sending tests with attachments

This commit is contained in:
James Houlahan
2022-10-04 18:56:01 +02:00
parent c953b8030a
commit 0badd69409
5 changed files with 415 additions and 4 deletions

3
go.mod
View File

@ -38,7 +38,7 @@ require (
github.com/sirupsen/logrus v1.9.0
github.com/stretchr/testify v1.8.0
github.com/urfave/cli/v2 v2.16.3
gitlab.protontech.ch/go/liteapi v0.32.1-0.20221004164551-596cce482fb0
gitlab.protontech.ch/go/liteapi v0.32.1
golang.org/x/exp v0.0.0-20220921164117-439092de6870
golang.org/x/net v0.1.0
golang.org/x/sys v0.1.0
@ -131,5 +131,4 @@ replace (
github.com/emersion/go-imap => github.com/ProtonMail/go-imap v0.0.0-20201228133358-4db68cea0cac
github.com/emersion/go-message => github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753
github.com/keybase/go-keychain => github.com/cuthix/go-keychain v0.0.0-20220405075754-31e7cee908fe
gitlab.protontech.ch/go/liteapi => ../liteapi
)

2
go.sum
View File

@ -463,6 +463,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0=
github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA=
gitlab.protontech.ch/go/liteapi v0.32.1 h1:EiaLP+LkVVDqFxU6Uux4w5HHfPj6dSnOILJPzIny5l4=
gitlab.protontech.ch/go/liteapi v0.32.1/go.mod h1:SVxEeF4uYYYpSlfeAj2ZqluVEP95pbZ8LyoieSxU0pM=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=

View File

@ -27,13 +27,13 @@ func createSendReq(
if recs := recipients.scheme(liteapi.InternalScheme, liteapi.ClearScheme, liteapi.PGPInlineScheme); len(recs) > 0 {
if recs := recs.content(rfc822.TextHTML); len(recs) > 0 {
if err := req.AddPackage(kr, string(richBody), rfc822.TextHTML, recs, attKeys); err != nil {
if err := req.AddTextPackage(kr, string(richBody), rfc822.TextHTML, recs, attKeys); err != nil {
return liteapi.SendDraftReq{}, err
}
}
if recs := recs.content(rfc822.TextPlain); len(recs) > 0 {
if err := req.AddPackage(kr, string(plainBody), rfc822.TextPlain, recs, attKeys); err != nil {
if err := req.AddTextPackage(kr, string(plainBody), rfc822.TextPlain, recs, attKeys); err != nil {
return liteapi.SendDraftReq{}, err
}
}

View File

@ -0,0 +1,217 @@
Feature: SMTP sending of plain messages
Background:
Given there exists an account with username "user@pm.me" and password "password"
And there exists an account with username "bridgetest@protonmail.com" and password "password"
And there exists an account with username "bridgetest2@protonmail.com" and password "password"
And bridge starts
And the user logs in with username "user@pm.me" and password "password"
And user "user@pm.me" connects and authenticates SMTP client "1"
Scenario: HTML message with attachment to internal account
When SMTP client "1" sends the following message from "user@pm.me" to "bridgetest@protonmail.com":
"""
From: Bridge Test <user@pm.me>
To: Internal Bridge <bridgetest@protonmail.com>
Subject: HTML with attachment internal
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=utf-8
<html><body>This is body of <b>HTML mail</b> with attachment<body></html>
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: attachment; filename=outline-light-instagram-48.png
Content-Id: <9114fe6f0adfaf7fdf7a@protonmail.com>
Content-Transfer-Encoding: base64
Content-Type: image/png
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD/////////////////
//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd
OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg
WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv
1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I
BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6
9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0
YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP
HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy
KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg==
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606--
"""
Then it succeeds
When user "user@pm.me" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following messages in "Sent":
| from | to | subject |
| user@pm.me | bridgetest@protonmail.com | HTML with attachment internal |
And the body in the "POST" request to "/mail/v4/messages" is:
"""
{
"Message": {
"Subject": "HTML with attachment internal",
"Sender": {
"Name": "Bridge Test"
},
"ToList": [
{
"Address": "bridgetest@protonmail.com",
"Name": "Internal Bridge"
}
],
"CCList": [],
"BCCList": [],
"MIMEType": "text/html"
}
}
"""
Scenario: HTML message with attachment to external account
When SMTP client "1" sends the following message from "user@pm.me" to "pm.bridge.qa@gmail.com":
"""
From: Bridge Test <user@pm.me>
To: External Bridge <pm.bridge.qa@gmail.com>
Subject: HTML with attachment external PGP
Content-Type: multipart/mixed; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=utf-8
<html><body>This is body of <b>HTML mail</b> with attachment<body></html>
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: attachment; filename=outline-light-instagram-48.png
Content-Id: <9114fe6f0adfaf7fdf7a@protonmail.com>
Content-Transfer-Encoding: base64
Content-Type: image/png
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD/////////////////
//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd
OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg
WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv
1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I
BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6
9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0
YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP
HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy
KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg==
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606--
"""
Then it succeeds
When user "user@pm.me" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following messages in "Sent":
| from | to | subject |
| user@pm.me | pm.bridge.qa@gmail.com | HTML with attachment external PGP |
And the body in the "POST" request to "/mail/v4/messages" is:
"""
{
"Message": {
"Subject": "HTML with attachment external PGP",
"Sender": {
"Name": "Bridge Test"
},
"ToList": [
{
"Address": "pm.bridge.qa@gmail.com",
"Name": "External Bridge"
}
],
"CCList": [],
"BCCList": [],
"MIMEType": "text/html"
}
}
"""
Scenario: Alternative plain and HTML message with rfc822 attachment
When SMTP client "1" sends the following message from "user@pm.me" to "pm.bridge.qa@gmail.com":
"""
From: Bridge Test <user@pm.me>
To: External Bridge <pm.bridge.qa@gmail.com>
Subject: Alternative plain and HTML with rfc822 attachment
Content-Type: multipart/mixed; boundary=main-parts
This is a multipart message in MIME format
--main-parts
Content-Type: multipart/alternative; boundary=alternatives
--alternatives
Content-Type: text/plain
There is an attachment
--alternatives
Content-Type: text/html
<html><body>There <b>is</b> an attachment<body></html>
--alternatives--
--main-parts
Content-Type: message/rfc822
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment
Received: from mx1.opensuse.org (mx1.infra.opensuse.org [192.168.47.95]) by
mailman3.infra.opensuse.org (Postfix) with ESMTP id 38BE2AC3 for
<factory@lists.opensuse.org>; Sun, 11 Jul 2021 19:50:34 +0000 (UTC)
From: "Bob " <Bob@something.net>
Sender: "Bob" <Bob@gmail.com>
To: "opensuse-factory" <opensuse-factory@opensuse.org>
Cc: "Bob" <Bob@something.net>
References: <y6ZUV5yEyOVQHETZRmi1GFe-Xumzct7QcLpGoSsi1MefGaoovfrUqdkmQ5gM6uySZ7JPIJhDkPJFDqHS1fb_mQ==@protonmail.internalid>
Subject: VirtualBox problems with kernel 5.13
Date: Sun, 11 Jul 2021 21:50:25 +0200
Message-ID: <71672e5f-24a2-c79f-03cc-4c923eb1790b@lwfinger.net>
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
X-Mailer: Microsoft Outlook 16.0
List-Unsubscribe: <mailto:factory-leave@lists.opensuse.org>
Content-Language: en-us
List-Help: <mailto:factory-request@lists.opensuse.org?subject=help>
List-Subscribe: <mailto:factory-join@lists.opensuse.org>
Thread-Index: AQFWvbNSAqFOch49YPlLU4eJWPObaQK2iKDq
I am writing this message as openSUSE's maintainer of VirtualBox.
Nearly every update of the Linux kernel to a new 5.X version breaks =
VirtualBox.
Bob
--main-parts--
"""
Then it succeeds
When user "user@pm.me" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following messages in "Sent":
| from | to | subject |
| user@pm.me | pm.bridge.qa@gmail.com | Alternative plain and HTML with rfc822 attachment |
And the body in the "POST" request to "/mail/v4/messages" is:
"""
{
"Message": {
"Subject": "Alternative plain and HTML with rfc822 attachment",
"Sender": {
"Name": "Bridge Test"
},
"ToList": [
{
"Address": "pm.bridge.qa@gmail.com",
"Name": "External Bridge"
}
],
"CCList": [],
"BCCList": [],
"MIMEType": "text/html"
}
}
"""

View File

@ -0,0 +1,193 @@
Feature: SMTP sending of plain messages
Background:
Given there exists an account with username "user@pm.me" and password "password"
And there exists an account with username "bridgetest@protonmail.com" and password "password"
And bridge starts
And the user logs in with username "user@pm.me" and password "password"
And user "user@pm.me" connects and authenticates SMTP client "1"
Scenario: Basic message with attachment to internal account
When SMTP client "1" sends the following message from "user@pm.me" to "bridgetest@protonmail.com":
"""
From: Bridge Test <user@pm.me>
To: Internal Bridge <bridgetest@protonmail.com>
Subject: Plain with attachment
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=utf-8
This is body of mail with attachment
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: attachment; filename=outline-light-instagram-48.png
Content-Id: <9114fe6f0adfaf7fdf7a@protonmail.com>
Content-Transfer-Encoding: base64
Content-Type: image/png
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD/////////////////
//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd
OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg
WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv
1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I
BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6
9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0
YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP
HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy
KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg==
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606--
"""
Then it succeeds
When user "user@pm.me" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following messages in "Sent":
| from | to | subject |
| user@pm.me | bridgetest@protonmail.com | Plain with attachment |
And the body in the "POST" request to "/mail/v4/messages" is:
"""
{
"Message": {
"Subject": "Plain with attachment",
"Sender": {
"Name": "Bridge Test"
},
"ToList": [
{
"Address": "bridgetest@protonmail.com",
"Name": "Internal Bridge"
}
],
"CCList": [],
"BCCList": [],
"MIMEType": "text/plain"
}
}
"""
Scenario: Plain message with attachment to external account
When SMTP client "1" sends the following message from "user@pm.me" to "pm.bridge.qa@gmail.com":
"""
From: Bridge Test <user@pm.me>
To: External Bridge <pm.bridge.qa@gmail.com>
Subject: Plain with attachment external
Content-Type: multipart/related; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=utf-8
This is body of mail with attachment
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: attachment; filename=outline-light-instagram-48.png
Content-Id: <9114fe6f0adfaf7fdf7a@protonmail.com>
Content-Transfer-Encoding: base64
Content-Type: image/png
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD/////////////////
//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd
OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg
WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv
1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I
BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6
9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0
YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP
HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy
KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg==
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606--
"""
Then it succeeds
When user "user@pm.me" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following messages in "Sent":
| from | to | subject |
| user@pm.me | pm.bridge.qa@gmail.com | Plain with attachment external |
And the body in the "POST" request to "/mail/v4/messages" is:
"""
{
"Message": {
"Subject": "Plain with attachment external",
"Sender": {
"Name": "Bridge Test"
},
"ToList": [
{
"Address": "pm.bridge.qa@gmail.com",
"Name": "External Bridge"
}
],
"CCList": [],
"BCCList": [],
"MIMEType": "text/plain"
}
}
"""
Scenario: Plain message with attachment to two external accounts
When SMTP client "1" sends the following message from "user@pm.me" to "pm.bridge.qa@gmail.com":
"""
From: Bridge Test <user@pm.me>
To: External Bridge 1 <pm.bridge.qa@gmail.com>
CC: External Bridge 2 <bridgeqa@seznam.cz>
Subject: Plain with attachment external PGP and external CC
Content-Type: multipart/mixed; boundary=bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=utf-8
This is body of mail with attachment
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606
Content-Disposition: attachment; filename=outline-light-instagram-48.png
Content-Id: <9114fe6f0adfaf7fdf7a@protonmail.com>
Content-Transfer-Encoding: base64
Content-Type: image/png
iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD/////////////////
//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd
OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg
WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv
1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I
BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6
9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0
YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP
HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy
KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg==
--bc5bd30245232f31b6c976adcd59bb0069c9b13f986f9e40c2571bb80aa16606--
"""
Then it succeeds
When user "user@pm.me" connects and authenticates IMAP client "1"
Then IMAP client "1" eventually sees the following messages in "Sent":
| from | to | cc | subject |
| user@pm.me | pm.bridge.qa@gmail.com | bridgeqa@seznam.cz | Plain with attachment external PGP and external CC |
And the body in the "POST" request to "/mail/v4/messages" is:
"""
{
"Message": {
"Subject": "Plain with attachment external PGP and external CC",
"Sender": {
"Name": "Bridge Test"
},
"ToList": [
{
"Address": "pm.bridge.qa@gmail.com",
"Name": "External Bridge 1"
}
],
"CCList": [
{
"Address": "bridgeqa@seznam.cz",
"Name": "External Bridge 2"
}
],
"BCCList": [],
"MIMEType": "text/plain"
}
}
"""