From d6f186f2ffe5f2e5b2c919225c1a321be14f33fa Mon Sep 17 00:00:00 2001 From: Hayelom Tizazu Date: Thu, 25 Jan 2024 10:20:35 +0300 Subject: [PATCH] email reply parser port --- .gitignore | 107 +++++++++ .vscode/launch.json | 23 ++ .vscode/settings.json | 5 + LICENSE | 21 ++ README.md | 30 +++ deno.jsonc | 8 + deno.lock | 425 ++++++++++++++++++++++++++++++++++ src/lib/email-parser.ts | 180 ++++++++++++++ src/lib/email-reply-parser.ts | 15 ++ src/lib/utils/email.ts | 27 +++ src/lib/utils/fragment-dto.ts | 13 ++ src/lib/utils/fragment.ts | 42 ++++ src/lib/utils/regex.ts | 54 +++++ src/test/fixtures.ts | 113 +++++++++ src/test/test.ts | 417 +++++++++++++++++++++++++++++++++ 15 files changed, 1480 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 LICENSE create mode 100644 README.md create mode 100644 deno.jsonc create mode 100644 deno.lock create mode 100644 src/lib/email-parser.ts create mode 100644 src/lib/email-reply-parser.ts create mode 100644 src/lib/utils/email.ts create mode 100644 src/lib/utils/fragment-dto.ts create mode 100644 src/lib/utils/fragment.ts create mode 100644 src/lib/utils/regex.ts create mode 100644 src/test/fixtures.ts create mode 100644 src/test/test.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f762f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,107 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +deps +npm \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..71136bf --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "request": "launch", + "name": "Launch Program", + "type": "node", + "program": "${workspaceFolder}/main.ts", + "cwd": "${workspaceFolder}", + "runtimeExecutable": "/home/ht/.deno/bin/deno", + "runtimeArgs": [ + "run", + "--unstable", + "--inspect-wait", + "--allow-all" + ], + "attachSimplePort": 9229 + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e40716f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "deno.enable": true, + "deno.lint": true, + "deno.unstable": true +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1feddb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2021 Crisp IM SAS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..06d5cef --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# Email Reply Parser + +**Email Reply Parser is a deno port of [Email reply parser node](https://github.com/crisp-oss/email-reply-parser) library to parse plain-text email replies and extract content** + +This library supports most email replies, signatures and locales. + +## Features + +This library is used at [Crisp](https://crisp.chat/) everyday with around 1 million inbound emails. Over the years, we improved this library so it can work with most emails. + +- Strip email replies like `On DATE, NAME wrote:` +- Supports around **10 locales**, including English, French, Spanish, Portuguese, Italian, Japanese, Chinese. +- Removes signatures like `Sent from my iPhone` +- Removes signatures like `Best wishes` + +## Usage + +```typescript +var email = new EmailReplyParser().read(MY_EMAIL_STRING); + +console.log(email.getVisibleText()); +``` + +## Credits + +- [@baptistejamin](https://github.com/baptistejamin) + +## License + +email-reply-parser is released under the MIT License. See the bundled LICENSE file for details. diff --git a/deno.jsonc b/deno.jsonc new file mode 100644 index 0000000..142ce4d --- /dev/null +++ b/deno.jsonc @@ -0,0 +1,8 @@ +{ + "tasks": { + "test": "deno test src/test/test.ts" + }, + "imports": { + "$std/": "https://deno.land/std@0.213.0/" + } +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..bb37fa9 --- /dev/null +++ b/deno.lock @@ -0,0 +1,425 @@ +{ + "version": "3", + "packages": { + "specifiers": { + "npm:express@4": "npm:express@4.18.2" + }, + "npm": { + "accepts@1.3.8": { + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "mime-types@2.1.35", + "negotiator": "negotiator@0.6.3" + } + }, + "array-flatten@1.1.1": { + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dependencies": {} + }, + "body-parser@1.20.1": { + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "bytes@3.1.2", + "content-type": "content-type@1.0.5", + "debug": "debug@2.6.9", + "depd": "depd@2.0.0", + "destroy": "destroy@1.2.0", + "http-errors": "http-errors@2.0.0", + "iconv-lite": "iconv-lite@0.4.24", + "on-finished": "on-finished@2.4.1", + "qs": "qs@6.11.0", + "raw-body": "raw-body@2.5.1", + "type-is": "type-is@1.6.18", + "unpipe": "unpipe@1.0.0" + } + }, + "bytes@3.1.2": { + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dependencies": {} + }, + "call-bind@1.0.5": { + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "function-bind@1.1.2", + "get-intrinsic": "get-intrinsic@1.2.2", + "set-function-length": "set-function-length@1.2.0" + } + }, + "content-disposition@0.5.4": { + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "safe-buffer@5.2.1" + } + }, + "content-type@1.0.5": { + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dependencies": {} + }, + "cookie-signature@1.0.6": { + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dependencies": {} + }, + "cookie@0.5.0": { + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dependencies": {} + }, + "debug@2.6.9": { + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "ms@2.0.0" + } + }, + "define-data-property@1.1.1": { + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "get-intrinsic@1.2.2", + "gopd": "gopd@1.0.1", + "has-property-descriptors": "has-property-descriptors@1.0.1" + } + }, + "depd@2.0.0": { + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dependencies": {} + }, + "destroy@1.2.0": { + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dependencies": {} + }, + "ee-first@1.1.1": { + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dependencies": {} + }, + "encodeurl@1.0.2": { + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dependencies": {} + }, + "escape-html@1.0.3": { + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dependencies": {} + }, + "etag@1.8.1": { + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dependencies": {} + }, + "express@4.18.2": { + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "accepts@1.3.8", + "array-flatten": "array-flatten@1.1.1", + "body-parser": "body-parser@1.20.1", + "content-disposition": "content-disposition@0.5.4", + "content-type": "content-type@1.0.5", + "cookie": "cookie@0.5.0", + "cookie-signature": "cookie-signature@1.0.6", + "debug": "debug@2.6.9", + "depd": "depd@2.0.0", + "encodeurl": "encodeurl@1.0.2", + "escape-html": "escape-html@1.0.3", + "etag": "etag@1.8.1", + "finalhandler": "finalhandler@1.2.0", + "fresh": "fresh@0.5.2", + "http-errors": "http-errors@2.0.0", + "merge-descriptors": "merge-descriptors@1.0.1", + "methods": "methods@1.1.2", + "on-finished": "on-finished@2.4.1", + "parseurl": "parseurl@1.3.3", + "path-to-regexp": "path-to-regexp@0.1.7", + "proxy-addr": "proxy-addr@2.0.7", + "qs": "qs@6.11.0", + "range-parser": "range-parser@1.2.1", + "safe-buffer": "safe-buffer@5.2.1", + "send": "send@0.18.0", + "serve-static": "serve-static@1.15.0", + "setprototypeof": "setprototypeof@1.2.0", + "statuses": "statuses@2.0.1", + "type-is": "type-is@1.6.18", + "utils-merge": "utils-merge@1.0.1", + "vary": "vary@1.1.2" + } + }, + "finalhandler@1.2.0": { + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "debug@2.6.9", + "encodeurl": "encodeurl@1.0.2", + "escape-html": "escape-html@1.0.3", + "on-finished": "on-finished@2.4.1", + "parseurl": "parseurl@1.3.3", + "statuses": "statuses@2.0.1", + "unpipe": "unpipe@1.0.0" + } + }, + "forwarded@0.2.0": { + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dependencies": {} + }, + "fresh@0.5.2": { + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dependencies": {} + }, + "function-bind@1.1.2": { + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dependencies": {} + }, + "get-intrinsic@1.2.2": { + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "function-bind@1.1.2", + "has-proto": "has-proto@1.0.1", + "has-symbols": "has-symbols@1.0.3", + "hasown": "hasown@2.0.0" + } + }, + "gopd@1.0.1": { + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "get-intrinsic@1.2.2" + } + }, + "has-property-descriptors@1.0.1": { + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "get-intrinsic@1.2.2" + } + }, + "has-proto@1.0.1": { + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dependencies": {} + }, + "has-symbols@1.0.3": { + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dependencies": {} + }, + "hasown@2.0.0": { + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "function-bind@1.1.2" + } + }, + "http-errors@2.0.0": { + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "depd@2.0.0", + "inherits": "inherits@2.0.4", + "setprototypeof": "setprototypeof@1.2.0", + "statuses": "statuses@2.0.1", + "toidentifier": "toidentifier@1.0.1" + } + }, + "iconv-lite@0.4.24": { + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": "safer-buffer@2.1.2" + } + }, + "inherits@2.0.4": { + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dependencies": {} + }, + "ipaddr.js@1.9.1": { + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dependencies": {} + }, + "media-typer@0.3.0": { + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dependencies": {} + }, + "merge-descriptors@1.0.1": { + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dependencies": {} + }, + "methods@1.1.2": { + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dependencies": {} + }, + "mime-db@1.52.0": { + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dependencies": {} + }, + "mime-types@2.1.35": { + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "mime-db@1.52.0" + } + }, + "mime@1.6.0": { + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dependencies": {} + }, + "ms@2.0.0": { + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dependencies": {} + }, + "ms@2.1.3": { + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dependencies": {} + }, + "negotiator@0.6.3": { + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dependencies": {} + }, + "object-inspect@1.13.1": { + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dependencies": {} + }, + "on-finished@2.4.1": { + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "ee-first@1.1.1" + } + }, + "parseurl@1.3.3": { + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dependencies": {} + }, + "path-to-regexp@0.1.7": { + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dependencies": {} + }, + "proxy-addr@2.0.7": { + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "forwarded@0.2.0", + "ipaddr.js": "ipaddr.js@1.9.1" + } + }, + "qs@6.11.0": { + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "side-channel@1.0.4" + } + }, + "range-parser@1.2.1": { + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dependencies": {} + }, + "raw-body@2.5.1": { + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "bytes@3.1.2", + "http-errors": "http-errors@2.0.0", + "iconv-lite": "iconv-lite@0.4.24", + "unpipe": "unpipe@1.0.0" + } + }, + "safe-buffer@5.2.1": { + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dependencies": {} + }, + "safer-buffer@2.1.2": { + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dependencies": {} + }, + "send@0.18.0": { + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "debug@2.6.9", + "depd": "depd@2.0.0", + "destroy": "destroy@1.2.0", + "encodeurl": "encodeurl@1.0.2", + "escape-html": "escape-html@1.0.3", + "etag": "etag@1.8.1", + "fresh": "fresh@0.5.2", + "http-errors": "http-errors@2.0.0", + "mime": "mime@1.6.0", + "ms": "ms@2.1.3", + "on-finished": "on-finished@2.4.1", + "range-parser": "range-parser@1.2.1", + "statuses": "statuses@2.0.1" + } + }, + "serve-static@1.15.0": { + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "encodeurl@1.0.2", + "escape-html": "escape-html@1.0.3", + "parseurl": "parseurl@1.3.3", + "send": "send@0.18.0" + } + }, + "set-function-length@1.2.0": { + "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "dependencies": { + "define-data-property": "define-data-property@1.1.1", + "function-bind": "function-bind@1.1.2", + "get-intrinsic": "get-intrinsic@1.2.2", + "gopd": "gopd@1.0.1", + "has-property-descriptors": "has-property-descriptors@1.0.1" + } + }, + "setprototypeof@1.2.0": { + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dependencies": {} + }, + "side-channel@1.0.4": { + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "call-bind@1.0.5", + "get-intrinsic": "get-intrinsic@1.2.2", + "object-inspect": "object-inspect@1.13.1" + } + }, + "statuses@2.0.1": { + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dependencies": {} + }, + "toidentifier@1.0.1": { + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dependencies": {} + }, + "type-is@1.6.18": { + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "media-typer@0.3.0", + "mime-types": "mime-types@2.1.35" + } + }, + "unpipe@1.0.0": { + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dependencies": {} + }, + "utils-merge@1.0.1": { + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dependencies": {} + }, + "vary@1.1.2": { + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dependencies": {} + } + } + }, + "remote": { + "https://deno.land/std@0.213.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", + "https://deno.land/std@0.213.0/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840", + "https://deno.land/std@0.213.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", + "https://deno.land/std@0.213.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", + "https://deno.land/std@0.213.0/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f", + "https://deno.land/std@0.213.0/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1", + "https://deno.land/std@0.213.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e", + "https://deno.land/std@0.213.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9", + "https://deno.land/std@0.213.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769", + "https://deno.land/std@0.213.0/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c", + "https://deno.land/std@0.213.0/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219", + "https://deno.land/std@0.213.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444", + "https://deno.land/std@0.213.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2", + "https://deno.land/std@0.213.0/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005", + "https://deno.land/std@0.213.0/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0", + "https://deno.land/std@0.213.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1", + "https://deno.land/std@0.213.0/assert/assert_not_equals.ts": "f3edda73043bc2c9fae6cbfaa957d5c69bbe76f5291a5b0466ed132c8789df4c", + "https://deno.land/std@0.213.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931", + "https://deno.land/std@0.213.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f", + "https://deno.land/std@0.213.0/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be", + "https://deno.land/std@0.213.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49", + "https://deno.land/std@0.213.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54", + "https://deno.land/std@0.213.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366", + "https://deno.land/std@0.213.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7", + "https://deno.land/std@0.213.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7", + "https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", + "https://deno.land/std@0.213.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2", + "https://deno.land/std@0.213.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c", + "https://deno.land/std@0.213.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b", + "https://deno.land/std@0.213.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd", + "https://deno.land/std@0.213.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145", + "https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb" + } +} diff --git a/src/lib/email-parser.ts b/src/lib/email-parser.ts new file mode 100644 index 0000000..b3734f9 --- /dev/null +++ b/src/lib/email-parser.ts @@ -0,0 +1,180 @@ +import { Email } from './utils/email.ts'; +import { FragmentDTO } from './utils/fragment-dto.ts'; +import { Fragment } from './utils/fragment.ts'; +import { + quoteHeadersRegex, + quoteRegex, + signatureRegex, +} from './utils/regex.ts'; + +export class EmailParser { + public fragments: FragmentDTO[]; + constructor() { + this.fragments = []; + } + + stringReverse(text: string) { + let s = ''; + let i = text.length; + while (i > 0) { + s += text.substring(i - 1, i); + i--; + } + return s; + } + + stringRTrim(text: string, mask: string) { + for (let i = text.length - 1; i >= 0; i--) { + if (mask != text.charAt(i)) { + text = text.substring(0, i + 1); + break; + } + } + return text; + } + + stringLTrim(text: string) { + return text.replace(/^\s+/, ''); + } + + parse(text: string) { + text = text.replace(/\r\n/g, '\n'); + text = this.fixBrokenSignatures(text); + + let fragment: FragmentDTO | null = null; + + this.stringReverse(text) + .split('\n') + .forEach((line) => { + line = this.stringRTrim(line, '\n'); + + if (!this.isSignature(line)) { + line = this.stringLTrim(line); + } + if (fragment) { + const last = fragment.lines[fragment.lines.length - 1]; + if (this.isSignature(last)) { + fragment.isSignature = true; + this.addFragment(fragment); + fragment = null; + } else if (line === '' && this.isQuoteHeader(last)) { + fragment.isQuoted = true; + this.addFragment(fragment); + fragment = null; + } + } + + const isQuoted = this.isQuote(line); + + if ( + fragment === null || + !this.isFragmentLine(fragment, line, isQuoted) + ) { + if (fragment !== null) { + this.addFragment(fragment); + } + + fragment = new FragmentDTO(); + fragment.isQuoted = isQuoted; + } + + fragment.lines.push(line); + }); + + if (fragment !== null) { + this.addFragment(fragment); + } + + const email = this.createEmail(this.fragments); + + this.fragments = []; + + return email; + } + + fixBrokenSignatures(text: string) { + let newText = text; + + // For any other quote header lines, if we find one of them, + // remove any new lines that happen to match in the first capture group + quoteHeadersRegex.forEach((regex) => { + const matches = newText.match(regex); + if (matches) { + const [_, matchGroup] = matches; + newText = newText.replace(matchGroup, matchGroup.replace(/\n/g, ' ')); + } + }); + + return newText; + } + + getQuoteHeadersRegex() { + return quoteHeadersRegex; + } + + // setQuoteHeadersRegex(quoteHeadersRegex: RegExp) { + // quoteHeadersRegex = quoteHeadersRegex; + + // return this; + // } + + createEmail(fragmentDTOs: FragmentDTO[]) { + const fragmentList: Fragment[] = []; + + fragmentDTOs.reverse().forEach((fragment) => { + fragmentList.push( + new Fragment( + this.stringReverse(fragment.lines.join('\n')).replace(/^\n/g, ''), + fragment.isHidden, + fragment.isSignature, + fragment.isQuoted + ) + ); + }); + + return new Email(fragmentList); + } + + isQuoteHeader(line: string) { + let hasHeader = false; + + quoteHeadersRegex.forEach((regex) => { + if (regex.test(this.stringReverse(line))) { + hasHeader = true; + } + }); + + return hasHeader; + } + + isSignature(line: string) { + const text = this.stringReverse(line); + + return signatureRegex.some((regex) => { + return regex.test(text); + }); + } + + isQuote(line: string) { + return quoteRegex.test(line); + } + + isEmpty(fragment: FragmentDTO) { + return '' === fragment.lines.join(''); + } + + isFragmentLine(fragment: FragmentDTO, line: string, isQuoted: boolean) { + return ( + fragment.isQuoted === isQuoted || + (fragment.isQuoted && (this.isQuoteHeader(line) || line === '')) + ); + } + + addFragment(fragment: FragmentDTO) { + if (fragment.isQuoted || fragment.isSignature || this.isEmpty(fragment)) { + fragment.isHidden = true; + } + + this.fragments.push(fragment); + } +} diff --git a/src/lib/email-reply-parser.ts b/src/lib/email-reply-parser.ts new file mode 100644 index 0000000..e1c2ab9 --- /dev/null +++ b/src/lib/email-reply-parser.ts @@ -0,0 +1,15 @@ +import { EmailParser } from './email-parser.ts'; + +export default class EmailReplyParser { + read(text: string) { + return new EmailParser().parse(text); + } + + parseReply(text: string) { + return this.read(text).getVisibleText(); + } + + parseReplied(text: string) { + return this.read(text).getQuotedText(); + } +} diff --git a/src/lib/utils/email.ts b/src/lib/utils/email.ts new file mode 100644 index 0000000..e3a8a25 --- /dev/null +++ b/src/lib/utils/email.ts @@ -0,0 +1,27 @@ +import { Fragment } from './fragment.ts'; + +export class Email { + constructor(public fragments: Fragment[] = []) {} + + getFragments() { + return this.fragments; + } + + getVisibleText() { + return this.filterText((fragment) => { + return !fragment.isHidden; + }); + } + + getQuotedText() { + return this.filterText((fragment) => { + return fragment.isQuoted; + }); + } + + filterText(filter: (f: Fragment) => boolean) { + const filteredFragments = this.fragments.filter(filter); + + return filteredFragments.join('\n').replace(/~*$/, ''); + } +} diff --git a/src/lib/utils/fragment-dto.ts b/src/lib/utils/fragment-dto.ts new file mode 100644 index 0000000..072ab82 --- /dev/null +++ b/src/lib/utils/fragment-dto.ts @@ -0,0 +1,13 @@ +export class FragmentDTO { + public lines: string[]; + public isHidden: boolean; + public isSignature: boolean; + public isQuoted: boolean; + + constructor() { + this.lines = []; + this.isHidden = false; + this.isSignature = false; + this.isQuoted = false; + } +} diff --git a/src/lib/utils/fragment.ts b/src/lib/utils/fragment.ts new file mode 100644 index 0000000..729da7b --- /dev/null +++ b/src/lib/utils/fragment.ts @@ -0,0 +1,42 @@ +export class Fragment { + public content: string; + public isHidden: boolean; + public isSignature: boolean; + public isQuoted: boolean; + + constructor( + content: string, + isHidden: boolean, + isSignature: boolean, + isQuoted: boolean + ) { + this.content = content; + this.isHidden = isHidden; + this.isSignature = isSignature; + this.isQuoted = isQuoted; + } + + public getIsHidden(): boolean { + return this.isHidden; + } + + public getIsSignature(): boolean { + return this.isSignature; + } + + public getIsQuoted(): boolean { + return this.isQuoted; + } + + public getContent(): string { + return this.content; + } + + public isEmpty(): boolean { + return '' === this.getContent().replace(/\n/g, ''); + } + + public toString(): string { + return this.getContent(); + } +} diff --git a/src/lib/utils/regex.ts b/src/lib/utils/regex.ts new file mode 100644 index 0000000..b26cb69 --- /dev/null +++ b/src/lib/utils/regex.ts @@ -0,0 +1,54 @@ +type RegexKeys = 'quote' | 'quoteHeadersRegex' | 'signatureRegex'; + +export const quoteRegex = /(>+)$/; + +export const quoteHeadersRegex = [ + /^-*\s*(On\s.+\s.+\n?wrote:{0,1})\s{0,1}-*$/m, // On DATE, NAME wrote: + /^-*\s*(Le\s.+\s.+\n?écrit\s?:{0,1})\s{0,1}-*$/m, // Le DATE, NAME a écrit : + /^-*\s*(El\s.+\s.+\n?escribió:{0,1})\s{0,1}-*$/m, // El DATE, NAME escribió: + /^-*\s*(Il\s.+\s.+\n?scritto:{0,1})\s{0,1}-*$/m, // Il DATE, NAME ha scritto: + /^-*\s*(Em\s.+\s.+\n?escreveu:{0,1})\s{0,1}-*$/m, // Em DATE, NAME ha escreveu: + /^\s*(Am\s.+\s)\n?\n?schrieb.+\s?(\[|<).+(\]|>):$/m, // Am DATE schrieb NAME : + /^\s*(Op\s[\s\S]+?\n?schreef[\s\S]+:)$/m, // Il DATE, schreef NAME : + /^\s*((W\sdniu|Dnia)\s[\s\S]+?(pisze|napisał(\(a\))?):)$/mu, // W dniu DATE, NAME pisze|napisał: + /^\s*(Den\s.+\s\n?skrev\s.+:)$/m, // Den DATE skrev NAME : + /^\s*(pe\s.+\s.+\n?kirjoitti:)$/m, // pe DATE NAME kirjoitti: + /^\s*(Am\s.+\sum\s.+\s\n?schrieb\s.+:)$/m, // Am DATE um TIME schrieb NAME: + /^(在[\s\S]+写道:)$/m, // > 在 DATE, TIME, NAME 写道: + /^(20[0-9]{2}\..+\s작성:)$/m, // DATE TIME NAME 작성: + /^(20[0-9]{2}\/.+のメッセージ:)$/m, // DATE TIME、NAME のメッセージ: + /^(.+\s<.+>\sschrieb:)$/m, // NAME schrieb: + /^(.+\son.*at.*wrote:)$/m, // NAME on DATE wrote: + /^\s*(From\s?:.+\s?\n?\s*[\[|<].+[\]|>])/m, // "From: NAME " OR "From : NAME " OR "From : NAME"(With support whitespace before start and before <) + /^\s*(De\s?:.+\s?\n?\s*(\[|<).+(\]|>))/m, // "De: NAME " OR "De : NAME " OR "De : NAME" (With support whitespace before start and before <) + /^\s*(Van\s?:.+\s?\n?\s*(\[|<).+(\]|>))/m, // "Van: NAME " OR "Van : NAME " OR "Van : NAME" (With support whitespace before start and before <) + /^\s*(Da\s?:.+\s?\n?\s*(\[|<).+(\]|>))/m, // "Da: NAME " OR "Da : NAME " OR "Da : NAME" (With support whitespace before start and before <) + /^(20[0-9]{2})-([0-9]{2}).([0-9]{2}).([0-9]{2}):([0-9]{2})\n?(.*)>:$/m, // 20YY-MM-DD HH:II GMT+01:00 NAME : + /^\s*([a-z]{3,4}\.\s[\s\S]+\sskrev\s[\s\S]+:)$/m, // DATE skrev NAME : + /^([0-9]{2}).([0-9]{2}).(20[0-9]{2})(.*)(([0-9]{2}).([0-9]{2}))(.*)\"( *)<(.*)>( *):$/m, // DD.MM.20YY HH:II NAME + /^[0-9]{2}:[0-9]{2}(.*)[0-9]{4}(.*)\"( *)<(.*)>( *):$/, // HH:II, DATE, NAME : + /^(.*)[0-9]{4}(.*)from(.*)<(.*)>:$/, +]; + +export const signatureRegex = [ + /^\s*-{2,4}$/, // Separator + /^\s*_{2,4}$/, // Separator + /^-- $/, // Separator + /^-- \s*.+$/, // Separator + /^\+{2,4}$/, // Separator + /^\={2,4}$/, // Separator + /^________________________________$/, // Separator + /^-{1,10}Original message-{1,10}$/, + /^Sent from (?:\s*.+)$/, // en + /^Get Outlook for (?:\s*.+).*/m, // en + /^Cheers,?!?$/im, // en + /^Best wishes,?!?$/im, // en + /^\w{0,20}\s?(\sand\s)?Regards,?!?!?$/im, //en + /^Von (?:\s*.+) gesendet$/, // de + /^Envoyé depuis (?:\s*.+)$/, //fr + /^Télécharger Outlook pour (?:\s*.+).*/m, // fr + /^Bien . vous,?!?$/im, // fr + /^\w{0,20}\s?cordialement,?!?$/im, // fr + /^Bonne (journ.e|soir.e)!?$/im, // fr + /^Enviado desde (?:\s*.+)$/, // es +]; diff --git a/src/test/fixtures.ts b/src/test/fixtures.ts new file mode 100644 index 0000000..41cf343 --- /dev/null +++ b/src/test/fixtures.ts @@ -0,0 +1,113 @@ +export const fixtures: Record = { + correct_sig: 'this is an email with a correct -- signature.\n\n--\nrick', + email_1: + 'Hi folks\n\nWhat is the best way to clear a Riak bucket of all key, values after\nrunning a test?\nI am currently using the Java HTTP API.\n\n-Abhishek Kona\n\n\n__\nriak-users mailing list\nriak-users@lists.basho.com\nhttp://lists.basho.com/mailman/listinfo/riak-users_lists.basho.com', + email_10: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nDe : Company Questions\r\nEnvoyé le :jeudi 15 décembre 2016 09:35\r\nÀ : someone@hotmail.fr\r\nObjet :Curabitur dictum aliquet mollis.\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_11: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\n De : Company Questions\r\n Envoyé le :jeudi 15 décembre 2016 09:35\r\n À : someone@hotmail.fr\r\n Objet :Curabitur dictum aliquet mollis.\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_12: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nVan: Company Questions [mailto:questions@company.com]\r\nVerzonden: maandag 5 december 2016 17:00\r\nAan: someone@hotmail.fr\r\nOnderwerp: Curabitur dictum aliquet mollis.\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_13: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nDa: Company Questions\r\nInviato: martedì 3 gennaio 2017 10:35\r\nA: someone@hotmail.it\r\nOggetto: Curabitur dictum aliquet mollis.\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_14: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nW dniu 2017-01-09 11:59:39 użytkownik Company Questions napisał:\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_15: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nSent from my Wiko RIDGE FAB 4G\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_16: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nDnia 27 grudnia 2016 12:08 Company Questions napisał(a):\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_17: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nW dniu 2017-01-09 11:59:39 użytkownik Company Questions napisał:\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_18: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nFrom: John Jung \r\nDate: Thursday, July 7, 2016 at 3:10 PM\r\nTo: Lucy Corpora \r\nSubject: Re:\r\n\r\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\r\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\r\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_19: + 'On Thursday, I get proper rendering.\n\nSent from a magnificent torch of pixels\n\nOn Dec 16, 2011, at 12:47 PM, Corey Donohoe\n\nwrote:\n\n> Was this caching related or fixed already? I get proper rendering here.\n>\n> ![](https://img.skitch.com/20111216-m9munqjsy112yqap5cjee5wr6c.jpg)\n>\n> ---\n> Reply to this email directly or view it on GitHub:\n> https://github.com/github/github/issues/2278#issuecomment-3182418', + email_2: + 'Hi,\nOn Tue, 2011-03-01 at 18:02 +0530, Abhishek Kona wrote:\n> Hi folks\n> \n> What is the best way to clear a Riak bucket of all key, values after \n> running a test?\n> I am currently using the Java HTTP API.\n\nYou can list the keys for the bucket and call delete for each. Or if you\nput the keys (and kept track of them in your test) you can delete them\none at a time (without incurring the cost of calling list first.)\n\nSomething like:\n\n String bucket = "my_bucket";\n BucketResponse bucketResponse = riakClient.listBucket(bucket);\n RiakBucketInfo bucketInfo = bucketResponse.getBucketInfo();\n \n for(String key : bucketInfo.getKeys()) {\n riakClient.delete(bucket, key);\n }\n\n\nwould do it.\n\nSee also \n\nhttp://wiki.basho.com/REST-API.html#Bucket-operations\n\nwhich says \n\n"At the moment there is no straightforward way to delete an entire\nBucket. There is, however, an open ticket for the feature. To delete all\nthe keys in a bucket, you’ll need to delete them all individually."\n\n> \n> -Abhishek Kona\n> \n> \n> _______________________________________________\n> riak-users mailing list\n> riak-users@lists.basho.com\n> http://lists.basho.com/mailman/listinfo/riak-users_lists.basho.com\n\n\n\n\n__\nriak-users mailing list\nriak-users@lists.basho.com\nhttp://lists.basho.com/mailman/listinfo/riak-users_lists.basho.com', + email_20: + 'On Thursday.\n\n> On May 17, 2017, at 01:42 PM, John Doe wrote:\n>\n> When will you fix this parsing?', + email_21: + 'On Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nEl jueves:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\nOn Thursday:\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + email_22: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\n30.09.2017, 18.30, "John - Doe" :\n\nTest', + email_23: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\n2017-11-24 16:32 GMT+01:00 Baptiste - Crisp :\n\nTest', + email_24: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nOn Wed, 14 Nov 2018 08:14:43 -0200 John Doe wrote\n\nWhen are you available?', + email_25: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\n11:00 AM, November 17, 2021, "John - Acme" :\n\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_26: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nWednesday, 17 November 2021, 3:32 PM +0300 from john@mail.acme.com :\n\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_2_1: + 'Outlook with a reply\n\n\n ------------------------------\n\n*From:* Google Apps Sync Team [mailto:mail-noreply@google.com]\n*Sent:* Thursday, February 09, 2012 1:36 PM\n*To:* jow@xxxx.com\n*Subject:* Google Apps Sync was updated!\n\n\n\nDear Google Apps Sync user,\n\nGoogle Apps Sync for Microsoft Outlook® was recently updated. Your computer\nnow has the latest version (version 2.5). This release includes bug fixes\nto improve product reliability. For more information about these and other\nchanges, please see the help article here:\n\nhttp://www.google.com/support/a/bin/answer.py?answer=153463\n\nSincerely,\n\nThe Google Apps Sync Team.', + email_3: + 'Oh thanks.\n\nHaving the function would be great.\n\n-Abhishek Kona\n\nOn 01/03/11 7:07 PM, Russell Brown wrote:\n> Hi,\n> On Tue, 2011-03-01 at 18:02 +0530, Abhishek Kona wrote:\n>> Hi folks\n>>\n>> What is the best way to clear a Riak bucket of all key, values after\n>> running a test?\n>> I am currently using the Java HTTP API.\n> You can list the keys for the bucket and call delete for each. Or if you\n> put the keys (and kept track of them in your test) you can delete them\n> one at a time (without incurring the cost of calling list first.)\n>\n> Something like:\n>\n> String bucket = "my_bucket";\n> BucketResponse bucketResponse = riakClient.listBucket(bucket);\n> RiakBucketInfo bucketInfo = bucketResponse.getBucketInfo();\n>\n> for(String key : bucketInfo.getKeys()) {\n> riakClient.delete(bucket, key);\n> }\n>\n>\n> would do it.\n>\n> See also\n>\n> http://wiki.basho.com/REST-API.html#Bucket-operations\n>\n> which says\n>\n> "At the moment there is no straightforward way to delete an entire\n> Bucket. There is, however, an open ticket for the feature. To delete all\n> the keys in a bucket, you’ll need to delete them all individually."\n>\n>> -Abhishek Kona\n>>\n>>\n>> _______________________________________________\n>> riak-users mailing list\n>> riak-users@lists.basho.com\n>> http://lists.basho.com/mailman/listinfo/riak-users_lists.basho.com\n>\n\n\n__\nriak-users mailing list\nriak-users@lists.basho.com\nhttp://lists.basho.com/mailman/listinfo/riak-users_lists.basho.com', + email_4: + "Awesome! I haven't had another problem with it.\n\nOn Aug 22, 2011, at 7:37 PM, defunkt wrote:\n\n> Loader seems to be working well.", + email_5: + "One: Here's what I've got.\n\n- This would be the first bullet point that wraps to the second line\nto the next\n- This is the second bullet point and it doesn't wrap\n- This is the third bullet point and I'm having trouble coming up with enough\nto say\n- This is the fourth bullet point\n\nTwo:\n- Here is another bullet point\n- And another one\n\nThis is a paragraph that talks about a bunch of stuff. It goes on and on\nfor a while.", + email_6: + 'I get proper rendering as well.\n\nSent a magnificent torch of pixels\n\nOn Dec 16, 2011, at 12:47 PM, Corey Donohoe\n\nwrote:\n\n> Was this caching related or fixed already? I get proper rendering here.\n>\n> ![](https://img.skitch.com/20111216-m9munqjsy112yqap5cjee5wr6c.jpg)\n>\n> ---\n> Reply to this email directly or view it on GitHub:\n> https://github.com/github/github/issues/2278#issuecomment-3182418', + email_7: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nIl giovedì 8 dicembre 2016, Company Questions \r\nha scritto:\r\n> Ciao Lorem\r\n>\r\n> Dino ha risposto alla tua domanda:\r\n>\r\n> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam pharetra d\r\nignissim odio?\r\n>\r\n>\r\n> Vestibulum nec dui luctus, rhoncus tortor in\r\n>\r\n>\r\n> "Lorem\r\n>\r\n> Maecenas tempor libero nec orci scelerisque porta a quis orci.\r\nrhoncus tortor in.\r\n>\r\n\r\n-- \r\n\r\n____________________________________________________________________\r\n\r\nLe informazioni contenute in questo messaggio e negli allegati sono\r\nriservate e per uso esclusivo del destinatario.\r\n\r\nPersone diverse dal destinatario non possono copiare o consegnare il\r\nmessaggio a terzi, né trattare i dati qui contenuti.\r\n\r\nSe ricevete questo messaggio per errore, Vi preghiamo di restituircelo\r\nimmediatamente e di cancellarlo. Grazie.\r\n\r\nMyCompany - 123456 ROMA\r\ntel 0123-456789 fax 0123-456789 e-mail info@client.it\r\n_____________________________________________________________________', + email_8: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\nOp 12 december 2016 19:05 schreef Company Questions <\r\nquestions@company.com>:\r\n\r\n> Beste Praesent\r\n> Jeroen, winkel Kortrijk heeft je vraag beantwoord:\r\n> "In efficitur augue ac tristique ullamcorper. Aenean tincidunt ornare diam,\r\neget accumsan est viverra quis. Pellentesque"\r\n>', + email_9: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\r\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\r\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\r\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\r\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\r\n\r\n====\r\n\r\nMessage du : 12/12/2016 13:20\r\nDe : "Company Questions " \r\nA : maecenas@somewhere.fr\r\nCopie à : \r\nSujet :  vitae porta purus rutrum eget !\r\n\r\nProin cursus, nibh sed posuere hendrerit, dui mauris scelerisque erat, vel tempus mauris odio eu lectus.\r\nNulla facilisi. Praesent pellentesque vehicula ante. Aenean posuere placerat magna porta mollis.\r\nFusce interdum ante ac purus ultricies, sed rhoncus ligula ultricies. Ut eleifend augue at laoreet bibendum.\r\nNullam mollis euismod erat, convallis porta velit commodo eu.', + email_blackberry: 'Here is another email\n\nSent from my BlackBerry', + email_bullets: + 'test 2 this should list second\n\nand have spaces\n\nand retain this formatting\n\n\n - how about bullets\n - and another\n\n\nOn Fri, Feb 24, 2012 at 10:19 AM, wrote:\n\n> Give us an example of how you applied what they learned to achieve\n> something in your organization\n\n\n\n\n--\n\n*Joe Smith | Director, Product Management*', + email_custom_quote_header: + 'Thank you!\n\n2013.02.08. 7:31 keltezéssel, "Gyõrvári Eszter" írta:\n> http://www.imdb.com/title/tt2017109/\n>\n>\n> I really like your products!\n>\n>\n>\n>\n>\n>\n\n-- \nGyőrvári Gábor - Scr34m\nscr34m@gmail.com', + email_customer_quote_header_2: + 'Thank you very much.\n\n\n\nFrom: somedude [mailto:test@webdomain.com]\nSent: Tuesday, 14 May 2013 6:18 AM\nTo: Developer\nSubject: You have a new message', + email_customer_quote_header_3: + "bonjour,\nje n'ai pas eu de retour sur ma précision..\nmerci d'avance\n\n De : Someone Somewhere \n À : mycompany \n Envoyé le : Mercredi 30 novembre 2016 10h30\n Objet : Re: Vous avez reçu une réponse à votre question !\n\nbonjour,\nici dans la description cdt", + email_emoji: '🎉\n\n—\nJohn Doe\nCEO at Pandaland\n\n@pandaland', + email_en_multiline_2: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\n\nOn Tue, 16 Nov 2021, 12:34 pm John - Acme \nwrote:\n\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_finnish: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\npe 20. lokakuuta 2017 klo 17.50 John Coe\n kirjoitti:\n\nThanks!', + email_fr_multiline: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nLe lun. 15 nov. 2021 à 19:42, John - Acme \na écrit :\n\nEtiam non sagittis orci, non rutrum urna. Suspendisse ut sapien id dolor posuere placerat et vitae felis.\nFusce mollis condimentum nulla. Donec luctus justo eu purus placerat, non suscipit ex facilisis.\nSed risus lorem, porta eget imperdiet in, euismod eu nisl. Integer vel metus felis.', + email_german: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nAm 13.12.2017 21:11 schrieb "John Doe - Stripe :\n\nHi there!', + email_gmail_split_line_from: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nOn Mon, Aug 26, 2019 at 4:37 PM The Hiring Engine <\na-really-long-automated-email+1234556@humanresources.com> wrote:\n\n> Test\n> Respond\n> \n>', + email_ios_outlook: + "Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nGet Outlook for iOS\n________________________________\nFrom: The Hiring Engine \nSent: Thursday, September 26, 2019 11:35:12 AM\nTo: Yolanda Washington \nSubject: Chauffeur - Berlin, CT - Text from Garret Zeiter\n\n[https://d3k81ch9hvuctc.cloudfront.net/company/MiZSL5/images/467c76ff-861d-498b-92f5-b7958f3af726.png]\n[https://images.expeditiondata.com/customer/premier_limousine/premier_limousine_logo1569450818256.png]\n\nChauffeur - Berlin, CT\n\nNew Message from: Garret Zeiter on Thursday, September 26th\nWed at 10am\nPrevious Messages\nMessage from: The Hiring Engine on Thursday, September 26th\nHi Garret - This is Garret with Premier Limousine. We'd be excited to have you come interview for the Chauffeur role. Can you come in for an interview in the next week?\nYou may reply to this email to send a text message response.\nView Conversation", + email_iphone: 'Here is another email\n\nSent from my iPhone', + email_msn: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n________________________________\nFrom: The Hiring Engine Automation \nSent: Wednesday, September 25, 2019 5:45 PM\nTo: shazzwrd@msn.com \nSubject: Your application for Local CDL A Driver at Republic Transport\n\nHi Kevin - Thanks for your interest in the Local CDL A Driver role at Republic Transport! Are you currently employed?', + email_multi_word_sent_from_my_mobile_device: + 'Here is another email\n\nSent from my Verizon Wireless BlackBerry', + email_norwegian_gmail: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\ntir. 18. apr. 2017 kl. 13:09 skrev Test user :\n\n> Ok. Thanks.\n>\n> On Nov 21, 2014, at 9:26, Jim Beam wrote:\n>\n>>> On Nov 20, 2014, at 11:03 AM, John Doe wrote:\n>>>\n>>> if you take a look at a short video from attachment, why full-typed filename does not stay in CMD+T pane?\n>>> When I type last character, it is not shown anymore.\n>>\n>> We think we’ve tracked down the cause of this issue, write back if you see the issue after the next update. (Which will be out shortly.)\n>>\n>> --\n>> Jim Beam – Acme Corp\n>>\n>', + email_not_a_signature: + "Dear XXXXX:\n\nThis is a reminder that the following services in your account 'XXXXXXXXXX' are scheduled to expire soon and will be discontinued:\n\nService Expire Date Description \n-------------------------------------------------------------- \nRegistration Jun 27, 2018 github.com\nRegistration Jun 27, 2018 twitter.com \nRegistration Jun 27, 2018 facebok.com \n\nAll dates are in MMM DD, YYYY format. \n\nIf you have any questions, please reply to this e-mail. Thank you for using our domain name services.\n\nSincerely,\nSuper Domain Name Manager", + email_one_is_not_on: + "Thank, this is really helpful.\n\nOne outstanding question I had:\n\nLocally (on development), when I run...\n\nOn Oct 1, 2012, at 11:55 PM, Dave Tapley wrote:\n\n> The good news is that I've found a much better query for lastLocation.\n>", + email_outlook_split_line_from: + "Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nFrom: Human Resources \n \nSent: Monday, August 26, 2019 4:37 PM\nTo: Abhishek Kona \nSubject: A new message from applicant\n\n \n\nHere's a new person:\n\nNew Message from: Danny Laurence on Monday, August 26th\n\nYour company is really cool!\n\nRespond \n\n", + email_portuguese: + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\nNulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\nNam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\nDuis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\net mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.\n\nEm 10 de julho de 2017 às 16:32:35, John Doe - Stripe (\ncontact@stripe.com) escreveu:\n\nHi there!', + email_reply_header: + "This is the latest reply.\n\nThe thread contains two previous replies, and the most recent reply header has a line break in it.\n\nIf we don't patch the line break, the reply header ends up in THIS fragment, instead of in the quoted fragment.\n\nOn the one hand, there could be a line in the reply starting with the word 'On.'\n\nOn the other hand, it could happen TWICE!\n\nStranger\n\nOn Wed, Dec 9, Mister Example\n\nwrote:\n> Hey, Stranger,\n> It's mrmister again, and I hope you reply to me. I also hope this fragment has my reply header in it!\n>\n> -mrmister\n>\n> On Tue, 2011-03-01 at 18:02 +0530, Stranger Jones wrote:\n>> Hey, mrmister,\n>>\n>> I'm getting tired of writing fake email text.\n>>\n>> Stranger\n\n--\nMy name is Stranger", + email_sent_from: + 'Hi it can happen to any texts you type, as long as you type in between words or paragraphs.\n\nSent from TypeApp\nOn Jun 17, 2017, at 14:15, Valerian - Crisp > wrote:\nOh yes I see. Can you send this text here so that we can replicate and fix?', + email_sent_from_my_not_signature: + 'Here is another email\n\nSent from my desk, is much easier then my mobile phone.', + email_thread: + 'This is new email reply in thread from bellow.\n\nOn Nov 21, 2014,\nat 10:18,\nJohn Doe wrote:\n\n> Ok. Thanks.\n>\n> On Nov 21, 2014, at 9:26, Jim Beam wrote:\n>\n>>> On Nov 20, 2014, at 11:03 AM, John Doe wrote:\n>>>\n>>> if you take a look at a short video from attachment, why full-typed filename does not stay in CMD+T pane?\n>>> When I type last character, it is not shown anymore.\n>>\n>> We think we’ve tracked down the cause of this issue, write back if you see the issue after the next update. (Which will be out shortly.)\n>>\n>> --\n>> Jim Beam – Acme Corp\n>>\n>', + email_unquoted_reply: + 'This is my reply.\n\nOn Nov 26, 2013 you wrote:\n\nThis is my quote.', + email_with_date_headers: + 'Thank you very much.\r\n\r\n[DATE]\r\n\r\nThis is my previous mail', + email_with_from_headers: '[FROM]\r\n\r\nMy email is ', + email_with_regards: + 'Hi, \n\nI still have the same problem....\n\nCan you help?\n\nRegards,\n\nJohn Doe\nCEO @ Acme !', + email_zoho: + 'What is the best way to clear a Riak bucket of all key, values after\nrunning a test?\n\n---- On Wed, 24 Feb 2021 14:02:50 +0530 john@gmail.com wrote ----\n\nJava sucks', + sig_no_empty_line: + 'this is an email with a signature with no empty line above.\n--\nrick', +}; diff --git a/src/test/test.ts b/src/test/test.ts new file mode 100644 index 0000000..424b0c8 --- /dev/null +++ b/src/test/test.ts @@ -0,0 +1,417 @@ +import { assertEquals } from '$std/assert/assert_equals.ts'; +import EmailReplyParser from '../lib/email-reply-parser.ts'; +import { fixtures } from './fixtures.ts'; + +const COMMON_FIRST_FRAGMENT = + 'Fusce bibendum, quam hendrerit sagittis tempor, dui turpis tempus erat, pharetra sodales ante sem sit amet metus.\n\ +Nulla malesuada, orci non vulputate lobortis, massa felis pharetra ex, convallis consectetur ex libero eget ante.\n\ +Nam vel turpis posuere, rhoncus ligula in, venenatis orci. Duis interdum venenatis ex a rutrum.\n\ +Duis ut libero eu lectus consequat consequat ut vel lorem. Vestibulum convallis lectus urna,\n\ +et mollis ligula rutrum quis. Fusce sed odio id arcu varius aliquet nec nec nibh.'; + +function get_email(name: string) { + const data = fixtures[name]; + + return new EmailReplyParser().read(data); +} + +Deno.test('test_email_gmail_no', () => { + const email = get_email('email_norwegian_gmail'); + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_reads_simple_body', () => { + const reply = get_email('email_1'); + assertEquals(2, reply.fragments.length); + + assertEquals( + [false, false], + reply.fragments.map((i) => i.isQuoted) + ); + + assertEquals( + [false, true], + reply.fragments.map((i) => i.isHidden) + ); + + assertEquals( + 'Hi folks\n\nWhat is the best way to clear a Riak bucket of all key, values after\nrunning a test?\nI am currently using the Java HTTP API.\n\n-Abhishek Kona\n\n', + reply.fragments[0].toString() + ); +}); + +// Deno.test('test_reads_top_post', () => { +// const email = get_email('email_3'); + +// const fragments = email.getFragments(); + +// assertEquals( +// 'Hi folks\n\nWhat is the best way to clear a Riak bucket of all key, values after\nrunning a test?\nI am currently using the Java HTTP API.\n\n-Abhishek Kona\n\n', +// fragments[0].toString() +// ); +// }); + +Deno.test('test_reads_bottom_post', () => { + const email = get_email('email_2'); + + const fragments = email.getFragments(); + assertEquals(6, fragments.length); + + assertEquals('Hi,', fragments[0].toString()); + assertEquals(true, /^On [^\:]+\:/.test(fragments[1].toString())); + assertEquals(true, /^You can list/.test(fragments[2].toString())); + assertEquals(true, /^>/.test(fragments[3].toString())); + assertEquals(true, /^_/.test(fragments[5].toString())); +}); + +Deno.test('test_recognizes_data_string_above_quote', () => { + const email = get_email('email_4'); + + const fragments = email.getFragments(); + + assertEquals(true, /^Awesome/.test(fragments[0].toString())); + assertEquals(true, /^On/.test(fragments[1].toString())); + assertEquals(true, /Loader/.test(fragments[1].toString())); +}); + +Deno.test('test_complex_body_with_only_one_fragment', () => { + const email = get_email('email_5'); + + const fragments = email.getFragments(); + + assertEquals(1, fragments.length); +}); + +Deno.test('test_deals_with_multiline_reply_headers', () => { + const email = get_email('email_6'); + + const fragments = email.getFragments(); + + assertEquals(true, /^I get/.test(fragments[0].toString())); + assertEquals(true, /^On/.test(fragments[1].toString())); + assertEquals(true, /Was this/.test(fragments[1].toString())); +}); + +Deno.test('test_email_with_italian', () => { + const email = get_email('email_7'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_with_dutch', () => { + const email = get_email('email_8'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_with_signature', () => { + const email = get_email('email_9'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_with_hotmail', () => { + const email = get_email('email_10'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_whitespace_before_header', () => { + const email = get_email('email_11'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_square_brackets', () => { + const email = get_email('email_12'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_da_into_italian', () => { + const email = get_email('email_13'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_header_polish', () => { + const email = get_email('email_14'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_sent_from_my', () => { + const email = get_email('email_15'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_header_polish_with_dnia_and_napisala', () => { + const email = get_email('email_16'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_header_polish_with_date_in_iso8601', () => { + const email = get_email('email_17'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_outlook_en', () => { + const email = get_email('email_18'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_22', () => { + const email = get_email('email_22'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_23', () => { + const email = get_email('email_23'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_25', () => { + const email = get_email('email_25'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_26', () => { + const email = get_email('email_26'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_portuguese', () => { + const email = get_email('email_portuguese'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_german', () => { + const email = get_email('email_german'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_gmail_no', () => { + const email = get_email('email_norwegian_gmail'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_finnish', () => { + const email = get_email('email_finnish'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_with_correct_signature', () => { + const email = get_email('correct_sig'); + + const fragments = email.getFragments(); + + assertEquals(2, fragments.length); + assertEquals(false, fragments[1].isQuoted); + assertEquals(false, fragments[0].isSignature); + assertEquals(true, fragments[1].isSignature); + assertEquals(false, fragments[0].isHidden); + assertEquals(true, fragments[1].isHidden); + + assertEquals(true, /^--\nrick/.test(fragments[1].toString())); +}); + +Deno.test('test_reads_email_with_signature_with_no_empty_line_above', () => { + const email = get_email('sig_no_empty_line'); + + const fragments = email.getFragments(); + + assertEquals(2, fragments.length); + assertEquals(false, fragments[0].isQuoted); + assertEquals(false, fragments[1].isQuoted); + + assertEquals(false, fragments[0].isSignature); + assertEquals(true, fragments[1].isSignature); + + assertEquals(false, fragments[0].isHidden); + assertEquals(true, fragments[1].isHidden); + + assertEquals(true, /^--\nrick/.test(fragments[1].toString())); +}); + +Deno.test('test_one_is_not_one', () => { + const email = get_email('email_one_is_not_on'); + + const fragments = email.getFragments(); + + assertEquals(true, /One outstanding question/.test(fragments[0].toString())); + assertEquals(true, /^On Oct 1, 2012/.test(fragments[1].toString())); +}); + +Deno.test('test_sent_from', () => { + const email = get_email('email_sent_from'); + + assertEquals( + email.getVisibleText(), + 'Hi it can happen to any texts you type, as long as you type in between words or paragraphs.\n' + ); +}); + +Deno.test('test_email_emoji', () => { + const email = get_email('email_emoji'); + + assertEquals( + email.getVisibleText(), + '🎉\n\n—\nJohn Doe\nCEO at Pandaland\n\n@pandaland' + ); +}); + +// Deno.test('test_email_not_a_signature', () => { +// const email = get_email('email_not_a_signature'); + +// const fragments = email.getFragments(); + +// ; +// }); + +Deno.test('test_email_24', () => { + const email = get_email('email_24'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); +}); + +Deno.test('test_email_outlook', () => { + const email = get_email('email_outlook_split_line_from'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); + assertEquals(2, fragments.length); +}); + +Deno.test('test_email_gmail', () => { + const email = get_email('email_gmail_split_line_from'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); + assertEquals(2, fragments.length); +}); + +Deno.test('text_email_reply_header', () => { + const email = get_email('email_reply_header'); + + const fragments = email.getFragments(); + + const firstFragmentRegex = /^On the other hand/m; + const secondFragmentRegex = /^On Wed, Dec 9/m; + + assertEquals(firstFragmentRegex.test(fragments[0].toString().trim()), true); + assertEquals(secondFragmentRegex.test(fragments[1].toString().trim()), true); +}); + +Deno.test('text_email_ios_outlook', () => { + const email = get_email('email_ios_outlook'); + + const fragments = email.getFragments(); + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); + assertEquals(3, fragments.length); +}); + +Deno.test('text_email_msn', () => { + const email = get_email('email_msn'); + + const fragments = email.getFragments(); + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); + assertEquals(2, fragments.length); +}); + +Deno.test('text_email_zoho', () => { + const email = get_email('email_zoho'); + + const fragments = email.getFragments(); + + assertEquals( + 'What is the best way to clear a Riak bucket of all key, values after\nrunning a test?\n', + fragments[0].toString() + ); +}); + +Deno.test('text_email_regards', () => { + const email = get_email('email_with_regards'); + + const fragments = email.getFragments(); + + assertEquals( + 'Hi,\n\nI still have the same problem....\n\nCan you help?\n', + fragments[0].toString() + ); +}); + +Deno.test('test_email_fr_multiline', () => { + const email = get_email('email_fr_multiline'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); + assertEquals(2, fragments.length); +}); + +Deno.test('test_email_en_multiline_2', () => { + const email = get_email('email_en_multiline_2'); + + const fragments = email.getFragments(); + + assertEquals(COMMON_FIRST_FRAGMENT, fragments[0].toString().trim()); + assertEquals(2, fragments.length); +});