7 Commits
v0.8 ... v0.12

Author SHA1 Message Date
Bel LaPointe
19aa5f82fb accept , in values 2021-12-10 07:25:57 -07:00
Bel LaPointe
f0f7c1d3f0 go.mod 2021-12-10 07:21:56 -07:00
bel
a5927b0485 manual test add new subject filter term 2021-09-10 09:17:01 -06:00
bel
c6d88f6abe impl bofa payment 2021-09-10 09:12:26 -06:00
bel
0449e7bdaa shrink 2021-09-08 14:41:41 -06:00
Bel LaPointe
10bc441e1e bankofamerica impl charges 2021-09-07 15:46:01 -06:00
Bel LaPointe
6f3bf1f6a4 dont negate payment 2021-09-07 15:03:38 -06:00
11 changed files with 1087 additions and 154 deletions

View File

@@ -3,13 +3,16 @@ package main
type Bank int type Bank int
const ( const (
Chase Bank = iota + 1 Chase Bank = iota + 1
Citi Bank = iota + 1 Citi Bank = iota + 1
UCCU Bank = iota + 1 UCCU Bank = iota + 1
BankOfAmerica Bank = iota + 1
) )
func (b Bank) String() string { func (b Bank) String() string {
switch b { switch b {
case BankOfAmerica:
return "BankOfAmerica"
case Chase: case Chase:
return "Chase" return "Chase"
case Citi: case Citi:

View File

@@ -7,6 +7,7 @@ import (
"local/args" "local/args"
"local/oauth2" "local/oauth2"
"local/storage" "local/storage"
"log"
"net/http" "net/http"
"strings" "strings"
) )
@@ -55,7 +56,7 @@ func NewConfig() Config {
as.Append(args.STRING, "todolist", "todo list", "") as.Append(args.STRING, "todolist", "todo list", "")
as.Append(args.STRING, "todotag", "todo tag", "expense") as.Append(args.STRING, "todotag", "todo tag", "expense")
as.Append(args.STRING, "banks", "uccu,citi,chase", "uccu,citi,chase") as.Append(args.STRING, "banks", "uccu,citi,chase,bankofamerica", "uccu,citi,chase,bankofamerica")
as.Append(args.STRING, "accounts", "regex to include filter accounts", ".*") as.Append(args.STRING, "accounts", "regex to include filter accounts", ".*")
as.Append(args.STRING, "not-accounts", "regex to exclude filter accounts", "zzzzzz") as.Append(args.STRING, "not-accounts", "regex to exclude filter accounts", "zzzzzz")
@@ -91,11 +92,13 @@ func NewConfig() Config {
Storage: storage, Storage: storage,
Uploader: ul, Uploader: ul,
Banks: map[Bank]bool{ Banks: map[Bank]bool{
Chase: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Chase.String())), BankOfAmerica: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(BankOfAmerica.String())),
Citi: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Citi.String())), Chase: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Chase.String())),
UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())), Citi: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(Citi.String())),
UCCU: strings.Contains(strings.ToLower(as.GetString("banks")), strings.ToLower(UCCU.String())),
}, },
} }
log.Printf("config: %+v", config)
if config.Uploader == UploaderTodo { if config.Uploader == UploaderTodo {
token := as.GetString("todotoken") token := as.GetString("todotoken")

75
go.mod Normal file
View File

@@ -0,0 +1,75 @@
module local/email-xactions-to-todo
go 1.17
require (
github.com/google/uuid v1.3.0
local/args v0.0.0-00010101000000-000000000000
local/oauth2 v0.0.0-00010101000000-000000000000
local/sandbox/contact/contact v0.0.0-00010101000000-000000000000
local/storage v0.0.0-00010101000000-000000000000
)
require (
cloud.google.com/go v0.33.1 // indirect
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619 // indirect
github.com/abbot/go-http-auth v0.4.0 // indirect
github.com/aws/aws-sdk-go v1.15.81 // indirect
github.com/boltdb/bolt v1.3.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/buraksezer/consistent v0.9.0 // indirect
github.com/bytbox/go-pop3 v0.0.0-20120201222208-3046caf0763e // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/emersion/go-imap v1.2.0 // indirect
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/protobuf v1.2.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/gomodule/redigo v1.8.5 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/klauspost/compress v1.9.5 // indirect
github.com/klauspost/cpuid v1.2.3 // indirect
github.com/minio/md5-simd v1.1.0 // indirect
github.com/minio/minio-go/v6 v6.0.57 // indirect
github.com/minio/sha256-simd v0.1.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/ncw/rclone v1.46.0 // indirect
github.com/ncw/swift v1.0.44 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 // indirect
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.mongodb.org/mongo-driver v1.7.2 // indirect
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 // indirect
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 // indirect
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a // indirect
google.golang.org/appengine v1.3.0 // indirect
gopkg.in/ini.v1 v1.42.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
local/logb v0.0.0-00010101000000-000000000000 // indirect
)
replace local/args => ../args
replace local/oauth2 => ../oauth2
replace local/sandbox/contact/contact => ../sandbox/contact/contact
replace local/storage => ../storage
replace local/router => ../router
replace local/logb => ../logb

274
go.sum Normal file
View File

@@ -0,0 +1,274 @@
bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
cloud.google.com/go v0.33.1 h1:fmJQWZ1w9PGkHR1YL/P7HloDvqlmKQ4Vpb7PC2e+aCk=
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-storage-blob-go v0.0.0-20181023070848-cf01652132cc/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619 h1:6X8iB881g299aNEv6KXrcjL31iLOH7yA6NXoQX+MbDg=
github.com/Unknwon/goconfig v0.0.0-20181105214110-56bd8ab18619/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
github.com/a8m/tree v0.0.0-20180321023834-3cf936ce15d6/go.mod h1:FSdwKX97koS5efgm8WevNf7XS3PqtyFkKDDXrz778cg=
github.com/abbot/go-http-auth v0.4.0 h1:QjmvZ5gSC7jm3Zg54DqWE/T5m1t2AfDu6QlXJT0EVT0=
github.com/abbot/go-http-auth v0.4.0/go.mod h1:Cz6ARTIzApMJDzh5bRMSUou6UMSp0IEXg9km/ci7TJM=
github.com/anacrolix/dms v0.0.0-20180117034613-8af4925bffb5/go.mod h1:DGqLjaZ3ziKKNRt+U5Q9PLWJ52Q/4rxfaaH/b3QYKaE=
github.com/aws/aws-sdk-go v1.15.81 h1:va7uoFaV9uKAtZ6BTmp1u7paoMsizYRRLvRuoC07nQ8=
github.com/aws/aws-sdk-go v1.15.81/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/billziss-gh/cgofuse v1.1.0/go.mod h1:LJjoaUojlVjgo5GQoEJTcJNqZJeRU0nCR84CyxKt2YM=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/buraksezer/consistent v0.9.0 h1:Zfs6bX62wbP3QlbPGKUhqDw7SmNkOzY5bHZIYXYpR5g=
github.com/buraksezer/consistent v0.9.0/go.mod h1:6BrVajWq7wbKZlTOUPs/XVfR8c0maujuPowduSpZqmw=
github.com/bytbox/go-pop3 v0.0.0-20120201222208-3046caf0763e h1:mQTN05gz0rDZSABqKMzAPMb5ATWcvvdMljRzEh0LjBo=
github.com/bytbox/go-pop3 v0.0.0-20120201222208-3046caf0763e/go.mod h1:alXX+s7a4cKaIprgjeEboqi4Tm7XR/HXEwUTxUV/ywU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/coreos/bbolt v0.0.0-20180318001526-af9db2027c98/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/cpuguy83/go-md2man v1.0.8/go.mod h1:N6JayAiVKtlHSnuTCeuLSQVs75hb8q+dYQLjr7cDsKY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/djherbis/times v1.1.0/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8=
github.com/dropbox/dropbox-sdk-go-unofficial v5.4.0+incompatible/go.mod h1:lr+LhMM3F6Y3lW1T9j2U5l7QeuWm87N9+PPXo3yH4qY=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/emersion/go-imap v1.2.0 h1:lyUQ3+EVM21/qbWE/4Ya5UG9r5+usDxlg4yfp3TgHFA=
github.com/emersion/go-imap v1.2.0/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss=
github.com/goftp/server v0.0.0-20190111142836-88de73f463af/go.mod h1:k/SS6VWkxY7dHPhoMQ8IdRu8L4lQtmGbhyXGg+vCnXE=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jlaffaye/ftp v0.0.0-20181101112434-47f21d10f0ee/go.mod h1:lli8NYPQOFy3O++YmYbqVgOcQ1JPCwdOy+5zSjKJ9qY=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
github.com/minio/minio-go/v6 v6.0.57 h1:ixPkbKkyD7IhnluRgQpGSpHdpvNVaW6OD5R9IAO/9Tw=
github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/ncw/go-acd v0.0.0-20171120105400-887eb06ab6a2/go.mod h1:MLIrzg7gp/kzVBxRE1olT7CWYMCklcUWU+ekoxOD9x0=
github.com/ncw/rclone v1.46.0 h1:5SY9lB6LIIXqwOaCWp5twUqNWgJVZMW+0D4rX90A2+E=
github.com/ncw/rclone v1.46.0/go.mod h1:+uFY4HNpat/yXXIEin5ETWXxIwEplC+eDe/vT8vlk1w=
github.com/ncw/swift v1.0.44 h1:EKvOTvUxElbpDWqxsyVaVGvc2IfuOqQnRmjnR2AGhQ4=
github.com/ncw/swift v1.0.44/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/nsf/termbox-go v0.0.0-20181027232701-60ab7e3d12ed/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd/go.mod h1:4soZNh0zW0LtYGdQ416i0jO0EIqMGcbtaspRS4BDvRQ=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pengsrc/go-shared v0.2.0/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46 h1:w2CpS5muK+jyydnmlkqpAhzKmHmMBzBkfYUDjQNS1Dk=
github.com/rfjakob/eme v0.0.0-20171028163933-2222dbd4ba46/go.mod h1:U2bmx0hDj8EyDdcxmD5t3XHDnBFnyNNc22n1R4008eM=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sevlyar/go-daemon v0.1.4/go.mod h1:6dJpPatBT9eUwM5VCw9Bt6CdX9Tk6UWvhW3MebLDRKE=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c h1:fyKiXKO1/I/B6Y2U8T7WdQGWzwehOuGIrljPtt7YTTI=
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/t3rm1n4l/go-mega v0.0.0-20190205172012-55a226cf41da/go.mod h1:XWL4vDyd3JKmJx+hZWUVgCNmmhZ2dTBcaNDcxH465s0=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yunify/qingstor-sdk-go v2.2.15+incompatible/go.mod h1:w6wqLDQ5bBTzxGJ55581UrSwLrsTAsdo9N6yX/8d9RY=
go.mongodb.org/mongo-driver v1.7.2 h1:pFttQyIiJUHEn50YfZgC9ECjITMT44oiN36uArf/OFg=
go.mongodb.org/mongo-driver v1.7.2/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba h1:YDkOrzGLLYybtuP6ZgebnO4OWYEYVMFSniazXsxrFN8=
golang.org/x/oauth2 v0.0.0-20181120190819-8f65e3013eba/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 h1:T5DasATyLQfmbTpfEXx/IOL9vfjzW6up+ZDkmHvIf2s=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a h1:yMfgT1baklxtECXVk3UtZBELVXtVhDbK3/7xLFkFypw=
google.golang.org/api v0.0.0-20181120235003-faade3cbb06a/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

122
scrape.go
View File

@@ -15,6 +15,7 @@ type scraper interface {
scrape(*mail.Message) ([]*Transaction, error) scrape(*mail.Message) ([]*Transaction, error)
} }
type bankOfAmericaScraper struct{}
type chaseScraper struct{} type chaseScraper struct{}
type citiScraper struct{} type citiScraper struct{}
type uccuScraper struct{} type uccuScraper struct{}
@@ -29,13 +30,16 @@ func Scrape(m *mail.Message, banks map[Bank]bool) ([]*Transaction, error) {
func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) { func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) {
subject := fmt.Sprint(m.Header["Subject"]) subject := fmt.Sprint(m.Header["Subject"])
if !containsAny(subject, "transaction", "report", "Transaction", "payment") { if !containsAny(subject, "transaction", "report", "Transaction", "payment", "Payment") {
return nil, errors.New("cannot build scraper for subject " + subject) return nil, errors.New("cannot build scraper for subject " + subject)
} }
from := fmt.Sprint(m.Header["From"]) from := fmt.Sprint(m.Header["From"])
if strings.Contains(from, "Chase") && banks[Chase] { if strings.Contains(from, "Chase") && banks[Chase] {
return newChaseScraper(), nil return newChaseScraper(), nil
} }
if strings.Contains(from, "Bank of America") && banks[BankOfAmerica] {
return newBankOfAmericaScraper(), nil
}
if strings.Contains(from, "Citi") && banks[Citi] { if strings.Contains(from, "Citi") && banks[Citi] {
return newCitiScraper(), nil return newCitiScraper(), nil
} }
@@ -45,6 +49,10 @@ func buildScraper(m *mail.Message, banks map[Bank]bool) (scraper, error) {
return nil, errors.New("unknown sender: " + from) return nil, errors.New("unknown sender: " + from)
} }
func newBankOfAmericaScraper() scraper {
return &bankOfAmericaScraper{}
}
func newChaseScraper() scraper { func newChaseScraper() scraper {
return &chaseScraper{} return &chaseScraper{}
} }
@@ -92,8 +100,10 @@ func (c *chaseScraper) scrape2021Payment(m *mail.Message) ([]*Transaction, error
return nil, err return nil, err
} }
re = regexp.MustCompile(`\$[0-9]+\.[0-9]{2}`) re = regexp.MustCompile(`\$[0-9,]+\.[0-9]{2}`)
amount := "-" + strings.TrimLeft(string(re.Find(b)), "$") amount := "-" + strings.TrimLeft(string(re.Find(b)), "$")
amount = strings.TrimLeft(string(re.Find(b)), "$")
amount = strings.ReplaceAll(amount, ",", "")
vendor := "Payment" vendor := "Payment"
@@ -106,12 +116,13 @@ func (c *chaseScraper) scrape2021Payment(m *mail.Message) ([]*Transaction, error
} }
func (c *chaseScraper) scrape2021Charge(m *mail.Message) ([]*Transaction, error) { func (c *chaseScraper) scrape2021Charge(m *mail.Message) ([]*Transaction, error) {
re := regexp.MustCompile(`^Your \$(?P<amount>[0-9\.]*) transaction with (?P<vendor>.*)$`) re := regexp.MustCompile(`^Your \$(?P<amount>[,0-9\.]*) transaction with (?P<vendor>.*)$`)
matches := re.FindSubmatch([]byte(m.Header["Subject"][0])) matches := re.FindSubmatch([]byte(m.Header["Subject"][0]))
if len(matches) < 1 { if len(matches) < 1 {
return nil, errors.New("no match subject search") return nil, errors.New("no match subject search")
} }
amount := string(matches[1]) amount := string(matches[1])
amount = strings.ReplaceAll(amount, ",", "")
vendor := string(matches[2]) vendor := string(matches[2])
b, _ := ioutil.ReadAll(m.Body) b, _ := ioutil.ReadAll(m.Body)
@@ -159,60 +170,21 @@ func (c *citiScraper) scrape(m *mail.Message) ([]*Transaction, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
re := regexp.MustCompile(`Citi Alert: A \$[0-9][0-9]*\.[0-9][0-9] transaction was made at .* on card ending in`) re := regexp.MustCompile(`Citi Alert: A \$[,0-9][,0-9]*\.[0-9][0-9] transaction was made at .* on card ending in`)
match := re.Find(b) match := re.Find(b)
if len(match) == 0 { if len(match) == 0 {
return nil, nil return nil, nil
} }
rePrice := regexp.MustCompile(`[0-9][0-9]*\.[0-9][0-9]`) rePrice := regexp.MustCompile(`[0-9][0-9,]*\.[0-9][0-9]`)
price := rePrice.Find(match) price := rePrice.Find(match)
price = []byte(strings.ReplaceAll(string(price), ",", ""))
vendor := bytes.Split(bytes.Split(match, []byte(" on card ending in"))[0], []byte("transaction was made at "))[1] vendor := bytes.Split(bytes.Split(match, []byte(" on card ending in"))[0], []byte("transaction was made at "))[1]
transaction := NewTransaction(Citi.String(), string(price), string(vendor), date, Citi) transaction := NewTransaction(Citi.String(), string(price), string(vendor), date, Citi)
return []*Transaction{transaction}, nil return []*Transaction{transaction}, nil
//Citi Alert: A $598.14 transaction was made at REMIX MUSIC SPRINGDA on card ending in 3837
/*
b, err := ioutil.ReadAll(m.Body)
if err != nil {
return nil, err
}
targetLineRegexp := regexp.MustCompile(`Account #: XXXX[0-9]{4} .*`)
targetMatches := targetLineRegexp.FindAll(b, -1)
if len(targetMatches) == 0 {
return nil, errors.New("no lines with transactions found")
}
results := make(map[string][]string)
for _, b := range targetMatches {
// Account #: XXXX3837 $137.87 at AMZN Mktp US Amzn.com/bill WA on 04/03/2020, 09:05 PM ET
regexp := regexp.MustCompile(`Account #: XXXX[0-9]{4} \$(?P<amount>[0-9]+\.[0-9]*) at (?P<account>[^,]*)`)
matches := regexp.FindSubmatch(b)
if len(matches) < 2 {
return nil, fmt.Errorf("no full matches found: %s", b)
}
for i, name := range regexp.SubexpNames() {
if i != 0 && name != "" {
if name == "account" {
matches[i] = bytes.Split(matches[i], []byte(" on "))[0]
}
results[name] = append(results[name], string(matches[i]))
}
}
if len(results) != 2 || len(results["amount"]) != len(results["account"]) {
return nil, fmt.Errorf("unexpected matches found looking for transactions: %+v", results)
}
}
transactions := make([]*Transaction, len(results["amount"]))
for i := range results["amount"] {
transactions[i] = NewTransaction(Citi.String(), results["amount"][i], results["account"][i], fmt.Sprint(m.Header["Date"]), Citi)
}
return transactions, nil
*/
} }
func (c *uccuScraper) scrape(m *mail.Message) ([]*Transaction, error) { func (c *uccuScraper) scrape(m *mail.Message) ([]*Transaction, error) {
@@ -237,3 +209,63 @@ func (c *uccuScraper) scrape(m *mail.Message) ([]*Transaction, error) {
transaction := NewTransaction(UCCU.String(), fmt.Sprintf("%.2f", f), "?", fmt.Sprint(m.Header["Date"]), UCCU) transaction := NewTransaction(UCCU.String(), fmt.Sprintf("%.2f", f), "?", fmt.Sprint(m.Header["Date"]), UCCU)
return []*Transaction{transaction}, nil return []*Transaction{transaction}, nil
} }
func (c *bankOfAmericaScraper) scrape(m *mail.Message) ([]*Transaction, error) {
subject := fmt.Sprint(m.Header["Subject"])
if strings.Contains(subject, "Credit card transaction") {
return c.scrapeCharge(m)
}
if strings.Contains(subject, "Credit Card Payment") {
return c.scrapePayment(m)
}
return nil, errors.New("not impl")
}
func (c *bankOfAmericaScraper) scrapeCharge(m *mail.Message) ([]*Transaction, error) {
b, err := ioutil.ReadAll(m.Body)
if err != nil {
return nil, err
}
amount := c.findFloatAfter(b, "Amount: $")
acc := string(c.findLineAfter(b, "Where: "))
if amount == "" || acc == "" {
return nil, errors.New("no amount/account found")
}
transaction := NewTransaction(BankOfAmerica.String(), amount, acc, fmt.Sprint(m.Header["Date"]), BankOfAmerica)
return []*Transaction{transaction}, nil
}
func (c *bankOfAmericaScraper) scrapePayment(m *mail.Message) ([]*Transaction, error) {
b, err := ioutil.ReadAll(m.Body)
if err != nil {
return nil, err
}
amount := "-" + c.findFloatAfter(b, "Payment: $")
acc := "Payment"
if amount == "" || acc == "" {
return nil, errors.New("no amount/account found")
}
transaction := NewTransaction(BankOfAmerica.String(), amount, acc, fmt.Sprint(m.Header["Date"]), BankOfAmerica)
return []*Transaction{transaction}, nil
}
func (c *bankOfAmericaScraper) findFloatAfter(b []byte, prefix string) string {
amount := string(c.findLineAfter(b, prefix))
words := strings.Split(amount, " ")
lastword := words[len(words)-1]
escapedfloat := strings.TrimPrefix(lastword, "$")
fixEscape := strings.ReplaceAll(escapedfloat, "=2E", ".")
amount = fixEscape
return amount
}
func (c *bankOfAmericaScraper) findLineAfter(b []byte, prefix string) []byte {
for _, line := range bytes.Split(b, []byte("\n")) {
if bytes.HasPrefix(line, []byte(prefix)) {
return bytes.TrimSpace(bytes.TrimPrefix(line, []byte(prefix)))
}
}
return nil
}

View File

@@ -7,6 +7,41 @@ import (
"testing" "testing"
) )
func TestScrapeChase202112Payment(t *testing.T) {
b, err := ioutil.ReadFile("./testdata/chase.2021.12.payment.txt")
if err != nil {
t.Fatal(err)
}
message := &mail.Message{
Header: map[string][]string{
"Subject": []string{"We've received your Chase Freedom Unlimited payment"},
},
Body: bytes.NewReader(b),
}
chase := &chaseScraper{}
gots, err := chase.scrape2021(message)
if err != nil {
t.Fatal(err)
}
if len(gots) != 1 {
t.Fatal(gots)
}
got := gots[0]
if got.Account != "1049" {
t.Fatalf("bad account: %v: %+v", got.Account, got)
}
if got.Amount != "1750.00" {
t.Fatalf("bad amount: %v: %+v", got.Amount, got)
}
if got.Vendor != "Payment" {
t.Fatalf("bad vendor: %v: %+v", got.Vendor, got)
}
t.Logf("%+v", got)
}
func TestScrapeChase2021Payment(t *testing.T) { func TestScrapeChase2021Payment(t *testing.T) {
b, err := ioutil.ReadFile("./testdata/chase.2021.payment.txt") b, err := ioutil.ReadFile("./testdata/chase.2021.payment.txt")
if err != nil { if err != nil {
@@ -108,3 +143,73 @@ func TestScrapeChase2020(t *testing.T) {
} }
t.Logf("%+v", got) t.Logf("%+v", got)
} }
func TestScrapeBofAPayment(t *testing.T) {
b, err := ioutil.ReadFile("./testdata/bofa.payment.txt")
if err != nil {
t.Fatal(err)
}
message := &mail.Message{
Header: map[string][]string{
"Subject": []string{"Confirmation: Thanks for Your Credit Card Payment"},
},
Body: bytes.NewReader(b),
}
bofa := &bankOfAmericaScraper{}
gots, err := bofa.scrape(message)
if err != nil {
t.Fatal(err)
}
if len(gots) != 1 {
t.Fatal(len(gots))
}
got := gots[0]
want := Transaction{
ID: got.ID,
Bank: BankOfAmerica,
Amount: "-251.74",
Vendor: "Payment",
Date: "[]",
Account: BankOfAmerica.String(),
}
if *got != want {
t.Fatalf("want:\n\t%+v, got\n\t%+v", want, *got)
}
}
func TestScrapeBofACharge(t *testing.T) {
b, err := ioutil.ReadFile("./testdata/bofa.charge.txt")
if err != nil {
t.Fatal(err)
}
message := &mail.Message{
Header: map[string][]string{
"Subject": []string{"Credit card transaction exceeds alert limit you set"},
},
Body: bytes.NewReader(b),
}
bofa := &bankOfAmericaScraper{}
gots, err := bofa.scrape(message)
if err != nil {
t.Fatal(err)
}
if len(gots) != 1 {
t.Fatal(len(gots))
}
got := gots[0]
want := Transaction{
ID: got.ID,
Bank: BankOfAmerica,
Amount: "75.08",
Vendor: "PAYPAL GIBBDOGENTE MA",
Date: "[]",
Account: BankOfAmerica.String(),
}
if *got != want {
t.Fatalf("want:\n\t%+v, got\n\t%+v", want, *got)
}
}

46
testdata/bofa.charge.txt vendored Normal file
View File

@@ -0,0 +1,46 @@
Credit card transaction exceeds alert limit you set
National Education Association World Mas ending in 7522
Amount: $75=2E08
Date: September 05, 2021
Where: PAYPAL GIBBDOGENTE MA
View details by going to
https://www=2Ebankofamerica=2Ecom/deeplink/redirect=2Ego?target=3Dbofasigni=
n&screen=3DAccounts:Home&version=3D7=2E0=2E0
If you made this purchase or payment but don=27t recognize the amount,
wait until the final purchase amount has posted before filing a dispute
claim=2E
If you don=27t recognize this activity, please contact us at the number
on the back of your card=2E
Did you know?
You can choose how you get alerts from us including text messages and
mobile notifications=2E Go to Alert Settings at
https://www=2Ebankofamerica=2Ecom/deeplink/redirect=2Ego?target=3Dalerts_se=
ttings&screen=3DAlerts:Home&gotoSetting=3Dtrue&version=3D7=2E1=2E0
We'll never ask for your personal information such as SSN or ATM PIN in
email messages=2E If you get an email that looks suspicious or you are not =
the intended recipient of this email, don't click on any links=2E Instead, =
forward to abuse@bankofamerica=2Ecom then delete it=2E
Please don't reply to this automatically generated service email=2E
Read our Privacy Notice https://www=2Ebankofamerica=2Ecom/privacy/consumer-=
privacy-notice=2Ego
Equal Housing Lender: https://www=2Ebankofamerica=2Ecom/help/equalhousing=
=2Ecfm
Bank of America, N=2EA=2E Member FDIC
(C) 2021 Bank of America Corporation
=20

88
testdata/bofa.payment.txt vendored Normal file
View File

@@ -0,0 +1,88 @@
Delivered-To: breellocaldev@gmail.com
Received: by 2002:a4f:f556:0:0:0:0:0 with SMTP id s22csp88584ivo;
Fri, 10 Sep 2021 03:09:37 -0700 (PDT)
X-Google-Smtp-Source: ABdhPJy5KOCCQILLhifnSPNnjMikzSGgZX0rSLKqSzdRkpjWyZAZB7Ml4gWSWxuiMPuJMUFQZPnF
X-Received: by 2002:a05:620a:15e8:: with SMTP id p8mr6940748qkm.27.1631268577237;
Fri, 10 Sep 2021 03:09:37 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1631268577; cv=none;
d=google.com; s=arc-20160816;
b=fRiwZLXmORGlNgDHdYZ3g7DbcggjP3zVkUX1gIVHo3z/c4SLgmwu1FVu4qiUr7M2+6
9Ez7xjq0rG3JCLUk77q4I2MJW9pWL5LZdcMtoP9bbu5KYoZ0JwLQldFuzUOFp1qyLICc
pegPsozU1lTG3WSr2fxAi4kGgvr1PQUGd5EaeztK+u7I9SNyyOdXsgavbx0Dr+XLFAyG
eGo1WzDGy7NG8TMstFxQu+cfZiWKKtEeTFUGEjcXAUxCm/jvqK8MT1fPTwac9c66cCls
7bvBpXlmoSEmTz6NseH0DblgWZsdmGgkYZhIUS2cJaqIhGJUFxNqbMQswEXT29LrmnbG
zz0w==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=content-transfer-encoding:feedback-id:message-id:list-id:reply-to
:mime-version:date:subject:to:from:dkim-signature;
bh=RNAxijcTyDxYmdzbEHMEKXkbCbc/Wnnsez0HenNHbUA=;
b=KtJdTZ9LFxfJTwq0gldceho7ktEybby+DLrKgjgjI2yUlaS4u0IJC2nDvkA21HjV1w
R2HMT4UITrQVoi9xa/fTsbdVIfEDjBl2rdbvO+gOthaonsCvxAsiQGFRPhmKHlbb1IiE
9GbgjYaf4qEZCO4nQUnMKTQPK+TalO1pX3UNPHf2/KTeAuXCUrySVKgierhZIxnkS3WQ
/GUsV4gDHMhmRKEQF8yxgLv3podfCm63iOBgOZ/CCITcKkQTFUByLQ2HdAmLo9TUXHNM
sJKv6pK7e05Dxp4ZeNKlm15c5xSo3OXoRqupvsXYCbzjvR2moBrVRSB7iwZHGL45zQXQ
OVug==
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@ealerts.bankofamerica.com header.s=200608 header.b=niVgyX92;
spf=pass (google.com: domain of bounce-29_html-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com designates 68.232.194.2 as permitted sender) smtp.mailfrom=bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bankofamerica.com
Return-Path: <bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com>
Received: from mta5.ealerts.bankofamerica.com (mta5.ealerts.bankofamerica.com. [68.232.194.2])
by mx.google.com with ESMTPS id a7si3031949qtn.85.2021.09.10.03.09.36
for <breellocaldev@gmail.com>
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Fri, 10 Sep 2021 03:09:37 -0700 (PDT)
Received-SPF: pass (google.com: domain of bounce-29_html-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com designates 68.232.194.2 as permitted sender) client-ip=68.232.194.2;
Authentication-Results: mx.google.com;
dkim=pass header.i=@ealerts.bankofamerica.com header.s=200608 header.b=niVgyX92;
spf=pass (google.com: domain of bounce-29_html-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com designates 68.232.194.2 as permitted sender) smtp.mailfrom=bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bankofamerica.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; s=200608; d=ealerts.bankofamerica.com;
h=From:To:Subject:Date:MIME-Version:Reply-To:List-ID:X-CSA-Complaints:
Message-ID:Content-Type:Content-Transfer-Encoding;
i=onlinebanking@ealerts.bankofamerica.com;
bh=RNAxijcTyDxYmdzbEHMEKXkbCbc/Wnnsez0HenNHbUA=;
b=niVgyX923ETmQwhHEaUcs91DEv/nznIH0c7CyqIgwu0h5KtgJZIKbkIw3inZNwLL9hF+/7lfV57q
ZYXmHQVV1aXIqJLQDD5RlAq2YZvghgLdglRBbq5N9cCDTsKIA3VlrKicwN+sAwDq2JlfBv4I8rzw
Vcmfup5eqf0vJnn6k9c=
Received: by mta5.ealerts.bankofamerica.com id h7cne22fmd4j for <breellocaldev@gmail.com>; Fri, 10 Sep 2021 10:09:35 +0000 (envelope-from <bounce-29_HTML-819616257-1667962-73720-2833596@bounce.ealerts.bankofamerica.com>)
From: "Bank of America" <onlinebanking@ealerts.bankofamerica.com>
To: <breellocaldev@gmail.com>
Subject: Confirmation: Thanks for Your Credit Card Payment
Date: Fri, 10 Sep 2021 04:09:32 -0600
MIME-Version: 1.0
Reply-To: "Bank of America" <reply-fe8a157673630d7b77-29_HTML-819616257-73720-2833596@ealerts.bankofamerica.com>
List-ID: <71108.xt.local>
X-CSA-Complaints: whitelistcomplaints@eco.de
x-job: 73720_1667962
Message-ID: <3fb2377b-699b-411c-9ea5-a3b8817aa853@las1s04mta1081.xt.local>
Feedback-ID: 73720:1667962:68.232.194.2:sfmktgcld
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Hi, BEL, we've received your credit card payment
Payment: $251.74
To: National Education Association World Mas ending in - 7522
Date posted: September 09, 2021
Sign in to bankofamerica.com to view your account details.
Thank you for being our customer.
We'll never ask for your personal information such as SSN or ATM PIN in
email messages. If you get an email that looks suspicious or you are
not the intended recipient of this email, don't click on any links.
Instead, forward to abuse@bankofamerica.com then delete it.
Please don't reply to this automatically generated service email.
Read our Privacy Notice https://www.bankofamerica.com/privacy/consumer-privacy-notice.go
Equal Housing Lender: https://www.bankofamerica.com/help/equalhousing.cfm
Bank of America, N.A. Member FDIC
(C) 2019 Bank of America Corporation

408
testdata/chase.2021.12.payment.txt vendored Normal file
View File

@@ -0,0 +1,408 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.=
w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns=3D"http://www.w3.org/1999/xhtml" lang=3D"en">
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3DUTF-8" />
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=3D1.=
0"/>
<title>This payment has been applied to your account.</title>
<style type=3D"text/css">
* {
=09line-height: normal !important;
}
strong {
=09font-weight: bold !important;
}
em {
=09font-style: italic !important;
}
body {
=09background-color: #d7dbe0 !important;
=09-webkit-text-size-adjust: none !important;
}
.ExternalClass * {
=09line-height: 112%
}
.ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass =
td {
=09line-height: 112%
}
td {
=09-webkit-text-size-adjust: none;
}
a[href^=3Dtel] {
=09color: inherit;
=09text-decoration: none;
}
.applelinksgray41 a {
=09color: #414042 !important;
=09text-decoration: none;
}
.applelinksgray a {
=09color: #717171 !important;
=09text-decoration: none;
}
.wordBreak {
=09overflow-wrap: break-word;
=09word-wrap: break-word;
=09word-break: break-all;
=09word-break: break-word;
}
@media screen and (max-width: 800px) {
.fullWidth {
=09width: 100% !important;
=09min-width: 100% !important;
=09margin-left: auto !important;
=09margin-right: auto !important;
=09padding: 0px !important;
=09text-align: center !important;
}
.hero {
=09width: 100% !important;
=09height: auto !important;
}
.moPad {
=09padding-right: 20px !important;
=09padding-left: 20px !important;
}
.zeroPad {
=09padding-right: 0px !important;
=09padding-left: 0px !important;
}
.font14 {
=09font-size: 14px !important;
}
.font24 {
=09font-size: 24px !important;
}
}
@media print and (max-width: 800px) {
.fullWidth {
=09width: 100% !important;
=09min-width: 100% !important;
=09margin-left: auto !important;
=09margin-right: auto !important;
=09padding: 0px !important;
=09text-align: center !important;
}
.hero {
=09width: 100% !important;
=09height: auto !important;
}
.moPad {
=09padding-right: 20px !important;
=09padding-left: 20px !important;
}
.zeroPad {
=09padding-right: 0px !important;
=09padding-left: 0px !important;
}
.font14 {
=09font-size: 14px !important;
}
.font24 {
=09font-size: 24px !important;
}
}
</style>
</head>
<body style=3D"padding: 0px;margin: 0px; background-color:#d7dbe0;">
<table align=3D"center" width=3D"100%" border=3D"0" cellspacing=3D"0" cellp=
adding=3D"0" style=3D"min-width:800px; background-color:#d7dbe0;" class=3D"=
fullWidth">
<tr>
<td align=3D"center" style=3D"vertical-align:top; padding:0px 0px 20px =
0px; min-width:800px; background-color:#d7dbe0;" class=3D"fullWidth"><table=
align=3D"center" width=3D"800" cellpadding=3D"0" cellspacing=3D"0" border=
=3D"0" class=3D"fullWidth" style=3D"background-color:#FFFFFF;">
<!-- Start of Content -->
<tr>
<td align=3D"center" style=3D"vertical-align:top; padding: 23px 0=
px 0px;background-color: #005EB8;"><table cellpadding=3D"0" cellspacing=3D"=
0" border=3D"0">
<tr>
<td align=3D"right" style=3D"vertical-align:bottom; padding=
:0px 0px; width:12px;"><img src=3D"https://www.chase.com/content/dam/email/=
images/blue-left.jpg" width=3D"12" height=3D"226" border=3D"0" style=3D"dis=
play:block;" alt=3D""/></td>
<td align=3D"center" style=3D"vertical-align:bottom; paddin=
g: 0px 0px 0px;width:616px; background-color: #FFFFFF;"><table width=3D"100=
%" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-align:top; paddi=
ng: 0px 0px; background-color: #ffffff;"><table width=3D"100%" cellpadding=
=3D"0" cellspacing=3D"0" border=3D"0">
<!-- Start hidden preview text -->
<div style=3D"display: none; max-height: 0px; ove=
rflow: hidden;">This payment has been applied to your account.</div>
<!-- Insert &zwnj;&nbsp; after hidden preview tex=
t -->
<div style=3D"display: none; max-height: 0px; ove=
rflow: hidden;"> &nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwn=
j;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&=
nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwn=
j;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&=
nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbs=
p;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&=
zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwn=
j;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&=
nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbs=
p;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&=
zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&nbsp;&zwnj;&nbs=
p;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&=
zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwn=
j;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&=
nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbs=
p;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&=
zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwnj;&nbsp;&zwn=
j;&nbsp;</div>
<!-- End hidden preview text -->
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
padding-left: 30px; background-color: #ffffff;" class=3D"moPad"><table widt=
h=3D"100%" cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-alig=
n:bottom; padding:36px 0px 20px;"><img src=3D"https://www.chase.com/content=
/dam/email/images/chase-logo-h-rgb.png" width=3D"104" height=3D"20" border=
=3D"0" style=3D"display:block;" alt=3D"Chase Logo"/></td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
padding: 20px 28px 0px;" class=3D"moPad"><table align=3D"left" cellpadding=
=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-alig=
n:top;"><table width=3D"100%" cellpadding=3D"0" cellspacing=3D"0" border=3D=
"0">
<tr>
<td align=3D"left" style=3D"vertica=
l-align:top; padding:5px 10px; font-family:Arial, Helvetica, sans-serif; fo=
nt-size:12px; font-weight:bold; color:#000000; background-color:#24e16b; bo=
rder-radius:20px; -moz-border-radius: 20px; -webkit-border-radius:20px; whi=
te-space: nowrap;" class=3D"font14">Payment received</td>
</tr>
</table></td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
background-color: #ffffff;"><table width=3D"100%" cellpadding=3D"0" cellsp=
acing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-alig=
n:top; padding: 20px 30px 28px;" class=3D"moPad"><table width=3D"100%" cell=
padding=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertica=
l-align:top; padding: 0px 20px 0px 0px;"><img src=3D"https://static.chasecd=
n.com/content/services/rendition/image.small.png/unified-assets/digital-car=
ds/chase-freedom/41473417013.png" width=3D"57" height=3D"auto" alt=3D"" bo=
rder=3D"0" style=3D"display:block;"/></td>
<td align=3D"left" style=3D"vertica=
l-align:top; padding:0px 50px 0px 0px; font-family:Arial, Helvetica, sans-s=
erif; font-size:30px; font-weight: bold; color:#414042;" class=3D"zeroPad">=
We've received your credit card payment</td>
</tr>
</table></td>
</tr>
</table></td>
</tr>
</table></td>
</tr>
</table></td>
<td align=3D"left" style=3D"vertical-align:bottom; padding:=
0px 0px;width:12px; "><img src=3D"https://www.chase.com/content/dam/email/i=
mages/blue-right.jpg " width=3D"12" height=3D"226" border=3D"0" style=3D"di=
splay:block;" alt=3D""/></td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"center" style=3D"vertical-align:top; padding: 0px 0p=
x 0px; background-color: #FFFFFF;"><table cellpadding=3D"0" cellspacing=3D"=
0" border=3D"0">
<tr>
<td align=3D"right" style=3D"vertical-align:top; padding:0p=
x 0px; width:12px;"><img src=3D"https://www.chase.com/content/dam/email/ima=
ges/white-left.jpg" width=3D"12" height=3D"77" border=3D"0" style=3D"displa=
y:block;" alt=3D""/></td>
<td align=3D"center" style=3D"vertical-align:top; padding: =
0px 0px 0px;width:616px;"><table width=3D"100%" cellpadding=3D"0" cellspaci=
ng=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-align:top; paddi=
ng:0px 150px 20px 30px; font-family:Arial, Helvetica, sans-serif; font-size=
:16px; color:#414042;" class=3D"moPad">This payment has been applied to you=
r account.</td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top; paddi=
ng: 0px 150px 0px 30px;" class=3D"moPad"><table width=3D"100%" cellpadding=
=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
padding: 10px 0px;border-bottom: solid 1px #414042;"><table width=3D"100%"=
cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-alig=
n:top; padding:0px 0px 0px 0px; font-family:Arial, Helvetica, sans-serif; f=
ont-size:16px; color:#414042;" class=3D"font14">Account</td>
<td align=3D"right" style=3D"vertical-ali=
gn:top; padding:0px 0px 0px 5px; font-family:Arial, Helvetica, sans-serif; =
font-size:16px; font-weight:bold; color:#414042;" class=3D"font14">Chase Fr=
eedom Unlimited (...1049)</td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
padding: 10px 0px;border-bottom: solid 1px #414042;"><table width=3D"100%"=
cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-alig=
n:top; padding:0px 0px 0px 0px; font-family:Arial, Helvetica, sans-serif; f=
ont-size:16px; color:#414042;" class=3D"font14">Posted date</td>
<td align=3D"right" style=3D"vertical-ali=
gn:top; padding:0px 0px 0px 5px; font-family:Arial, Helvetica, sans-serif; =
font-size:16px; font-weight:bold; color:#414042;" class=3D"font14">Dec 9, 2=
021</td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
padding: 10px 0px;border-bottom: solid 1px #414042;"><table width=3D"100%"=
cellpadding=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-alig=
n:top; padding:0px 0px 0px 0px; font-family:Arial, Helvetica, sans-serif; f=
ont-size:16px; color:#414042;" class=3D"font14">Payment amount</td>
<td align=3D"right" style=3D"vertical-ali=
gn:top; padding:0px 0px 0px 5px; font-family:Arial, Helvetica, sans-serif; =
font-size:16px; font-weight:bold; color:#414042;" class=3D"font14"><span cl=
ass=3D"applelinksgray41"><a style=3D"color:#414042;text-decoration: none;">=
$1,750.00</a></span></td>
</tr>
</table></td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top; paddi=
ng:40px 150px 40px 30px; font-family:Arial, Helvetica, sans-serif; font-siz=
e:16px; color:#414042;" class=3D"moPad">Find <a style=3D"text-decoration: u=
nderline; color:#0060F0;" href=3D"https://www.chase.com/personal/credit-car=
ds/login-epay" rel=3D"noopener noreferrer" target=3D"_blank">more informat=
ion</a> about the credit card payments process.</td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top;"><tab=
le width=3D"100%" align=3D"left" cellpadding=3D"0" cellspacing=3D"0" border=
=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
"><table width=3D"100%" align=3D"left" cellpadding=3D"0" cellspacing=3D"0" =
border=3D"0" class=3D"fullWidth">
<tr>
<td align=3D"left" style=3D"padding:0px; =
vertical-align:top; padding: 0px 0px 30px 30px;" class=3D"moPad"><table ali=
gn=3D"left" cellpadding=3D"0" cellspacing=3D"0" border=3D"0" style=3D"verti=
cal-align:top;">
<tr>
<td role=3D"button" align=3D"center=
" style=3D"background-color:#0060f0; color: #fffffe; font-size: 16px; font-=
family: Arial, Helvetica, sans-serif; padding: 10px 0px; border: 1px solid =
#0060f0; vertical-align:top; border-radius:4px; -moz-border-radius: 4px; -w=
ebkit-border-radius:4px;width: 200px;"><a href=3D"https://www.chase.com/per=
sonal/mobile-online-banking/payment-activity" target=3D"_blank" style=3D"co=
lor: #fffffe; text-decoration:none;">See payment activity</a></td>
</tr>
</table></td>
</tr>
</table></td>
</tr>
</table></td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top; paddi=
ng:0px 30px 20px; font-family:Arial, Helvetica, sans-serif; font-size:12px;=
color:#717171;" class=3D"moPad font14">Securely access your accounts with =
the <a style=3D"text-decoration: underline; color:#0060F0;" href=3D"https:/=
/www.chase.com/digital/mobile-banking" rel=3D"noopener noreferrer" target=
=3D"_blank">Chase&nbsp;Mobile<span style=3D"font-size:70%; line-height:0; v=
ertical-align:3px; text-decoration: none;">&reg;</span> app</a> or <a style=
=3D"text-decoration: underline; color:#0060F0;" href=3D"https://secure.chas=
e.com/web/auth/nav?navKey=3DrequestDashboard" rel=3D"noopener noreferrer" =
target=3D"_blank">chase.com</a>. </td>
</tr>
<tr>
<td align=3D"left" style=3D"vertical-align:top; paddi=
ng: 0px 0px; background-color: #F6F6F6;"><table width=3D"100%" cellpadding=
=3D"0" cellspacing=3D"0" border=3D"0">
<tr>
<td align=3D"left" style=3D"vertical-align:top;=
padding:20px 30px 60px; font-family:Arial, Helvetica, sans-serif; font-siz=
e:12px; color:#717171;" class=3D"moPad font14"><span role=3D"heading" style=
=3D"text-transform: uppercase; font-weight: bold;">About this message</span=
><br />
<br />
Chase&nbsp;Mobile<span style=3D"font-size:70%=
; line-height:0; vertical-align:3px;">&reg;</span> app is available for se=
lect mobile devices. Message and data rates may apply.<br />
<br />
This service email was sent based on your ale=
rt settings. Use the Chase&nbsp;Mobile app or visit <a href=3D"https://www.=
chase.com/personal/mobile-online-banking/login-alerts" target=3D"_blank" st=
yle=3D"text-decoration: underline; color:#0060F0;" rel=3D"noopener noreferr=
er">chase.com/alerts</a> to view or manage your settings.<br />
<br />
Chase cannot guarantee the delivery of alerts=
and notifications. Wireless or internet service provider outages or other =
circumstances could delay them. You can always check <span class=3D"appleli=
nksgray"><a style=3D"color:#717171;text-decoration: none;">chase.com</a></s=
pan> or the Chase&nbsp;Mobile app for the status of your accounts including=
your latest account balances and transaction details.<br />
<br />
To protect your personal information, please =
don't reply to this message. Chase won't ask for confidential information i=
n an email. <br />
<br />
If you have concerns about the authenticity o=
f this message or have questions about your account visit <a style=3D"text-=
decoration: underline; color:#0060F0;" href=3D"https://www.chase.com/digita=
l/customer-service" target=3D"_blank" rel=3D"noopener noreferrer">chase.com=
/CustomerService</a> for ways to contact us.<br />
<br />
Your privacy is important to us. See our onli=
ne <a style=3D"text-decoration: underline; color:#0060F0;" href=3D"https://=
www.chase.com/digital/resources/privacy-security" target=3D"_blank" rel=3D"=
noopener noreferrer">Security Center</a> to learn how to protect your infor=
mation.<br />
<br />
&copy; 2021 JPMorgan Chase &amp; Co. </td>
</tr>
</table></td>
</tr>
</table></td>
<td align=3D"left" style=3D"vertical-align:top; padding:0px=
0px; width:12px;"><img src=3D"https://www.chase.com/content/dam/email/imag=
es/white-right.jpg" width=3D"12" height=3D"77" border=3D"0" style=3D"displa=
y:block;" alt=3D""/></td>
</tr>
</table></td>
</tr>
<!--End of Content -->
</table></td>
</tr>
</table>
</body>
</html>

View File

@@ -8,107 +8,6 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=3D1.= <meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=3D1.=
0"/> 0"/>
<title>This payment has been applied to your account.</title> <title>This payment has been applied to your account.</title>
<style type=3D"text/css">
* {
=09line-height: normal !important;
}
strong {
=09font-weight: bold !important;
}
em {
=09font-style: italic !important;
}
body {
=09background-color: #d7dbe0 !important;
=09-webkit-text-size-adjust: none !important;
}
.ExternalClass * {
=09line-height: 112%
}
.ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass =
td {
=09line-height: 112%
}
td {
=09-webkit-text-size-adjust: none;
}
a[href^=3Dtel] {
=09color: inherit;
=09text-decoration: none;
}
.applelinksgray41 a {
=09color: #414042 !important;
=09text-decoration: none;
}
.applelinksgray a {
=09color: #717171 !important;
=09text-decoration: none;
}
.wordBreak {
=09overflow-wrap: break-word;
=09word-wrap: break-word;
=09word-break: break-all;
=09word-break: break-word;
}
@media screen and (max-width: 800px) {
.fullWidth {
=09width: 100% !important;
=09min-width: 100% !important;
=09margin-left: auto !important;
=09margin-right: auto !important;
=09padding: 0px !important;
=09text-align: center !important;
}
.hero {
=09width: 100% !important;
=09height: auto !important;
}
.moPad {
=09padding-right: 20px !important;
=09padding-left: 20px !important;
}
.zeroPad {
=09padding-right: 0px !important;
=09padding-left: 0px !important;
}
.font14 {
=09font-size: 14px !important;
}
.font24 {
=09font-size: 24px !important;
}
}
@media print and (max-width: 800px) {
.fullWidth {
=09width: 100% !important;
=09min-width: 100% !important;
=09margin-left: auto !important;
=09margin-right: auto !important;
=09padding: 0px !important;
=09text-align: center !important;
}
.hero {
=09width: 100% !important;
=09height: auto !important;
}
.moPad {
=09padding-right: 20px !important;
=09padding-left: 20px !important;
}
.zeroPad {
=09padding-right: 0px !important;
=09padding-left: 0px !important;
}
.font14 {
=09font-size: 14px !important;
}
.font24 {
=09font-size: 24px !important;
}
}
</style>
</head> </head>
<body style=3D"padding: 0px;margin: 0px; background-color:#d7dbe0;"> <body style=3D"padding: 0px;margin: 0px; background-color:#d7dbe0;">
<table align=3D"center" width=3D"100%" border=3D"0" cellspacing=3D"0" cellp= <table align=3D"center" width=3D"100%" border=3D"0" cellspacing=3D"0" cellp=

View File

@@ -22,7 +22,7 @@ func (t *Transaction) Format() string {
} }
func (t *Transaction) String() string { func (t *Transaction) String() string {
return fmt.Sprint(*t) return fmt.Sprintf("%+v", *t)
} }
func NewTransaction(account, amount, vendor, date string, bank Bank) *Transaction { func NewTransaction(account, amount, vendor, date string, bank Bank) *Transaction {