epstein-files 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- epstein_files/__init__.py +63 -131
- epstein_files/documents/document.py +5 -1
- epstein_files/epstein_files.py +37 -35
- epstein_files/util/constant/names.py +2 -1
- epstein_files/util/constant/output_files.py +29 -0
- epstein_files/util/constant/urls.py +10 -7
- epstein_files/util/constants.py +140 -120
- epstein_files/util/data.py +12 -33
- epstein_files/util/doc_cfg.py +2 -10
- epstein_files/util/env.py +3 -2
- epstein_files/util/file_helper.py +0 -22
- epstein_files/util/highlighted_group.py +2 -2
- epstein_files/util/logging.py +6 -0
- epstein_files/util/output.py +180 -0
- epstein_files/util/rich.py +16 -9
- {epstein_files-1.0.1.dist-info → epstein_files-1.0.2.dist-info}/METADATA +19 -4
- epstein_files-1.0.2.dist-info/RECORD +33 -0
- epstein_files-1.0.2.dist-info/entry_points.txt +7 -0
- epstein_files-1.0.1.dist-info/RECORD +0 -30
- {epstein_files-1.0.1.dist-info → epstein_files-1.0.2.dist-info}/LICENSE +0 -0
- {epstein_files-1.0.1.dist-info → epstein_files-1.0.2.dist-info}/WHEEL +0 -0
epstein_files/util/data.py
CHANGED
|
@@ -3,15 +3,10 @@ Helpers for dealing with various kinds of data.
|
|
|
3
3
|
"""
|
|
4
4
|
import itertools
|
|
5
5
|
import re
|
|
6
|
-
import time
|
|
7
|
-
from dataclasses import dataclass, field
|
|
8
6
|
from datetime import datetime, timezone
|
|
9
7
|
from dateutil import tz
|
|
10
8
|
from typing import TypeVar
|
|
11
9
|
|
|
12
|
-
from dateutil.parser import parse
|
|
13
|
-
from rich.text import Text
|
|
14
|
-
|
|
15
10
|
from epstein_files.util.constant import names
|
|
16
11
|
from epstein_files.util.env import args
|
|
17
12
|
from epstein_files.util.logging import logger
|
|
@@ -24,27 +19,20 @@ CONSTANT_VAR_REGEX = re.compile(r"^[A-Z_]+$")
|
|
|
24
19
|
ALL_NAMES = [v for k, v in vars(names).items() if isinstance(v, str) and CONSTANT_VAR_REGEX.match(k)]
|
|
25
20
|
|
|
26
21
|
PACIFIC_TZ = tz.gettz("America/Los_Angeles")
|
|
27
|
-
TIMEZONE_INFO = {"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def dict_sets_to_lists(d: dict[str, set]) -> dict[str, list]:
|
|
31
|
-
return {k: sorted(list(v)) for k, v in d.items()}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def extract_datetime(s: str) -> datetime | None:
|
|
35
|
-
match = ISO_DATE_REGEX.search(s)
|
|
22
|
+
TIMEZONE_INFO = {"PDT": PACIFIC_TZ, "PST": PACIFIC_TZ} # Suppresses annoying warnings from parse() calls
|
|
36
23
|
|
|
37
|
-
if not match:
|
|
38
|
-
return None
|
|
39
24
|
|
|
40
|
-
|
|
25
|
+
collapse_newlines = lambda text: MULTINEWLINE_REGEX.sub('\n\n', text)
|
|
26
|
+
date_str = lambda dt: dt.isoformat()[0:10] if dt else None
|
|
27
|
+
escape_double_quotes = lambda text: text.replace('"', r'\"')
|
|
28
|
+
escape_single_quotes = lambda text: text.replace("'", r"\'")
|
|
29
|
+
iso_timestamp = lambda dt: dt.isoformat().replace('T', ' ')
|
|
30
|
+
uniquify = lambda _list: list(set(_list))
|
|
31
|
+
without_nones = lambda _list: [e for e in _list if e]
|
|
41
32
|
|
|
42
|
-
if len(date_str) == 4:
|
|
43
|
-
date_str += '-01-01'
|
|
44
|
-
elif len(date_str) == 7:
|
|
45
|
-
date_str += '-01'
|
|
46
33
|
|
|
47
|
-
|
|
34
|
+
def dict_sets_to_lists(d: dict[str, set]) -> dict[str, list]:
|
|
35
|
+
return {k: sorted(list(v)) for k, v in d.items()}
|
|
48
36
|
|
|
49
37
|
|
|
50
38
|
def extract_last_name(name: str) -> str:
|
|
@@ -91,8 +79,8 @@ def ordinal_str(n: int) -> str:
|
|
|
91
79
|
return str(n) + suffix
|
|
92
80
|
|
|
93
81
|
|
|
94
|
-
def patternize(_pattern: str | re.Pattern):
|
|
95
|
-
return _pattern if isinstance(_pattern, re.Pattern) else re.compile(
|
|
82
|
+
def patternize(_pattern: str | re.Pattern) -> re.Pattern:
|
|
83
|
+
return _pattern if isinstance(_pattern, re.Pattern) else re.compile(fr"({_pattern})", re.IGNORECASE)
|
|
96
84
|
|
|
97
85
|
|
|
98
86
|
def remove_timezone(timestamp: datetime) -> datetime:
|
|
@@ -106,12 +94,3 @@ def remove_timezone(timestamp: datetime) -> datetime:
|
|
|
106
94
|
def sort_dict(d: dict[str | None, int] | dict[str, int]) -> list[tuple[str | None, int]]:
|
|
107
95
|
sort_key = lambda e: (e[0] or '').lower() if args.sort_alphabetical else [-e[1], (e[0] or '').lower()]
|
|
108
96
|
return sorted(d.items(), key=sort_key)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
collapse_newlines = lambda text: MULTINEWLINE_REGEX.sub('\n\n', text)
|
|
112
|
-
date_str = lambda dt: dt.isoformat()[0:10] if dt else None
|
|
113
|
-
escape_double_quotes = lambda text: text.replace('"', r'\"')
|
|
114
|
-
escape_single_quotes = lambda text: text.replace("'", r"\'")
|
|
115
|
-
iso_timestamp = lambda dt: dt.isoformat().replace('T', ' ')
|
|
116
|
-
uniquify = lambda _list: list(set(_list))
|
|
117
|
-
without_nones = lambda _list: [e for e in _list if e]
|
epstein_files/util/doc_cfg.py
CHANGED
|
@@ -116,6 +116,8 @@ class DocCfg:
|
|
|
116
116
|
return self.title_by_author()
|
|
117
117
|
elif self.category == FINANCE and self.author in FINANCIAL_REPORTS_AUTHORS:
|
|
118
118
|
return f"{self.author} report: '{self.description}'"
|
|
119
|
+
elif self.category == LEGAL and 'v.' in self.author:
|
|
120
|
+
return f"{self.author}: '{self.description}'"
|
|
119
121
|
elif self.category and self.author is None and self.description is None:
|
|
120
122
|
return self.category
|
|
121
123
|
|
|
@@ -176,16 +178,6 @@ class DocCfg:
|
|
|
176
178
|
|
|
177
179
|
return props
|
|
178
180
|
|
|
179
|
-
def __eq__(self, other: 'DocCfg') -> bool:
|
|
180
|
-
"""Return True if everything matches other than the two 'dupe_' fields ('duplicate_ids' is compared)."""
|
|
181
|
-
for _field in self.sorted_fields():
|
|
182
|
-
if _field.name == 'id' or _field.name.startswith('dupe'):
|
|
183
|
-
continue
|
|
184
|
-
elif getattr(self, _field.name) != getattr(other, _field.name):
|
|
185
|
-
return False
|
|
186
|
-
|
|
187
|
-
return True
|
|
188
|
-
|
|
189
181
|
def __repr__(self) -> str:
|
|
190
182
|
props = self._props_strs()
|
|
191
183
|
type_str = f"{type(self).__name__}("
|
epstein_files/util/env.py
CHANGED
|
@@ -7,15 +7,16 @@ from sys import argv
|
|
|
7
7
|
from epstein_files.util.logging import datefinder_logger, env_log_level, logger
|
|
8
8
|
|
|
9
9
|
DEFAULT_WIDTH = 154
|
|
10
|
-
HTML_SCRIPTS = ['generate_html.py', 'count_words.py']
|
|
10
|
+
HTML_SCRIPTS = ['epstein_generate', 'generate_html.py', 'count_words.py']
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
parser = ArgumentParser(description="Parse epstein OCR docs and generate HTML page.")
|
|
14
|
-
parser.add_argument('--build', '-b', action='store_true', help='write
|
|
14
|
+
parser.add_argument('--build', '-b', action='store_true', help='write output to file')
|
|
15
15
|
parser.add_argument('--all-emails', '-ae', action='store_true', help='all the emails instead of just the interesting ones')
|
|
16
16
|
parser.add_argument('--all-other-files', '-ao', action='store_true', help='all the non-email, non-text msg files instead of just interesting ones')
|
|
17
17
|
parser.add_argument('--colors-only', '-c', action='store_true', help='print header with color key table and links and exit')
|
|
18
18
|
parser.add_argument('--name', '-n', action='append', dest='names', help='specify the name(s) whose communications should be output')
|
|
19
|
+
parser.add_argument('--output-file', '-out', metavar='FILE', default='index.html', help='write output to FILE in docs/ (default=index.html)')
|
|
19
20
|
parser.add_argument('--output-emails', '-oe', action='store_true', help='generate other files section')
|
|
20
21
|
parser.add_argument('--output-other-files', '-oo', action='store_true', help='generate other files section')
|
|
21
22
|
parser.add_argument('--output-texts', '-ot', action='store_true', help='generate other files section')
|
|
@@ -8,7 +8,6 @@ from epstein_files.util.constant.strings import FILE_NAME_REGEX, FILE_STEM_REGEX
|
|
|
8
8
|
EPSTEIN_DOCS_DIR_ENV_VAR_NAME = 'EPSTEIN_DOCS_DIR'
|
|
9
9
|
DOCS_DIR_ENV = environ[EPSTEIN_DOCS_DIR_ENV_VAR_NAME]
|
|
10
10
|
DOCS_DIR = Path(DOCS_DIR_ENV or '').resolve()
|
|
11
|
-
PICKLED_PATH = Path("the_epstein_files.pkl.gz")
|
|
12
11
|
|
|
13
12
|
if not DOCS_DIR_ENV:
|
|
14
13
|
print(f"ERROR: {EPSTEIN_DOCS_DIR_ENV_VAR_NAME} env var not set!")
|
|
@@ -17,20 +16,7 @@ elif not DOCS_DIR.exists():
|
|
|
17
16
|
print(f"ERROR: {EPSTEIN_DOCS_DIR_ENV_VAR_NAME}='{DOCS_DIR}' does not exist!")
|
|
18
17
|
exit(1)
|
|
19
18
|
|
|
20
|
-
HTML_DIR = Path('docs')
|
|
21
19
|
EXTRACTED_EMAILS_DIR = Path('emails_extracted_from_legal_filings')
|
|
22
|
-
EPSTEIN_WORD_COUNT_HTML_PATH = HTML_DIR.joinpath('epstein_texts_and_emails_word_count.html')
|
|
23
|
-
GH_PAGES_HTML_PATH = HTML_DIR.joinpath('index.html')
|
|
24
|
-
JSON_METADATA_PATH = HTML_DIR.joinpath('epstein_files_nov_2025_cryptadamus_metadata.json')
|
|
25
|
-
WORD_COUNT_HTML_PATH = HTML_DIR.joinpath('epstein_emails_word_count.html')
|
|
26
|
-
|
|
27
|
-
BUILD_ARTIFACTS = [
|
|
28
|
-
EPSTEIN_WORD_COUNT_HTML_PATH,
|
|
29
|
-
GH_PAGES_HTML_PATH,
|
|
30
|
-
JSON_METADATA_PATH,
|
|
31
|
-
WORD_COUNT_HTML_PATH,
|
|
32
|
-
]
|
|
33
|
-
|
|
34
20
|
FILE_ID_REGEX = re.compile(fr".*{FILE_NAME_REGEX.pattern}")
|
|
35
21
|
FILENAME_LENGTH = len(HOUSE_OVERSIGHT_PREFIX) + 6
|
|
36
22
|
KB = 1024
|
|
@@ -110,11 +96,3 @@ def is_local_extract_file(filename) -> bool:
|
|
|
110
96
|
"""Return true if filename is of form 'HOUSE_OVERSIGHT_029835_1.txt'."""
|
|
111
97
|
file_match = FILE_ID_REGEX.match(str(filename))
|
|
112
98
|
return True if file_match and file_match.group(2) else False
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def make_clean() -> None:
|
|
116
|
-
"""Delete all build artifacts."""
|
|
117
|
-
for build_file in BUILD_ARTIFACTS:
|
|
118
|
-
if build_file.exists():
|
|
119
|
-
print(f"Removing build file '{build_file}'...")
|
|
120
|
-
build_file.unlink()
|
|
@@ -272,7 +272,7 @@ HIGHLIGHTED_NAMES = [
|
|
|
272
272
|
HighlightedNames(
|
|
273
273
|
label='europe',
|
|
274
274
|
style='light_sky_blue3',
|
|
275
|
-
pattern=r'(Angela )?Merk(el|le)|Austria|(Benjamin\s*)?Harnwell|Berlin|Brexit(eers?)?|Brit(ain|ish)|Brussels|Cannes|(Caroline|Jack)?\s*Lang(, Caroline)?|Cypr(iot|us)|Davos|ECB|EU|Europe(an)?(\s*Union)?|France|Geneva|Germany?|Gillard|Gree(ce|k)|Ital(ian|y)|Jacques|(Kevin\s*)?Rudd|Le\s*Pen|London|Macron|Melusine|Munich|(Natalia\s*)?Veselnitskaya|(Nicholas\s*)?Sarkozy|Nigel(\s*Farage)?|Oslo|Paris|Polish|(Sebastian )?Kurz|(Vi(c|k)tor\s+)?Orbah?n|Edward Rod Larsen|Strasbourg|Strauss[- ]?Kahn|Swed(en|ish)(?![-\s]+America)|Switzerland|(Tony\s)?Blair|Ukrain(e|ian)|Vienna|(Vitaly\s*)?Churkin|Zug',
|
|
275
|
+
pattern=r'(Angela )?Merk(el|le)|Austria|(Benjamin\s*)?Harnwell|Berlin|Borge|Brexit(eers?)?|Brit(ain|ish)|Brussels|Cannes|(Caroline|Jack)?\s*Lang(, Caroline)?|Cypr(iot|us)|Davos|ECB|EU|Europe(an)?(\s*Union)?|France|Geneva|Germany?|Gillard|Gree(ce|k)|Ital(ian|y)|Jacques|(Kevin\s*)?Rudd|Le\s*Pen|London|Macron|Melusine|Munich|(Natalia\s*)?Veselnitskaya|(Nicholas\s*)?Sarkozy|Nigel(\s*Farage)?|Oslo|Paris|Polish|(Sebastian )?Kurz|(Vi(c|k)tor\s+)?Orbah?n|Edward Rod Larsen|Strasbourg|Strauss[- ]?Kahn|Swed(en|ish)(?![-\s]+America)|Switzerland|(Tony\s)?Blair|Ukrain(e|ian)|Vienna|(Vitaly\s*)?Churkin|Zug',
|
|
276
276
|
emailers = {
|
|
277
277
|
ANDRZEJ_DUDA: 'former president of Poland',
|
|
278
278
|
MIROSLAV_LAJCAK: 'Russia-friendly Slovakian politician, friend of Steve Bannon',
|
|
@@ -519,7 +519,7 @@ HIGHLIGHTED_NAMES = [
|
|
|
519
519
|
HighlightedNames(
|
|
520
520
|
label='trump',
|
|
521
521
|
style='red3 bold',
|
|
522
|
-
pattern=r"@?realDonaldTrump|(Alan\s*)?Weiss?elberg|\bDJ?T\b|Donald J. Tramp|(Donald\s+(J\.\s+)?)?Trump(ism|\s*Properties)?|Don(ald| *Jr)(?! Rubin)|Ivana|(Madeleine\s*)?Westerhout|Mar[-\s]*a[-\s]*Lago|(Marla\s*)?Maples|(Matt(hew)? )?Calamari|\bMatt C\b|Melania|(Michael (J.? )?)?Boccio|Roger\s+Stone|rona|(The\s*)?Art\s*of\s*the\s*Deal",
|
|
522
|
+
pattern=r"@?realDonaldTrump|(Alan\s*)?Weiss?elberg|\bDJ?T\b|Donald J. Tramp|(Donald\s+(J\.\s+)?)?Trump(ism|\s*Properties)?|Don(ald| *Jr)(?! Rubin)|Ivana|(Madeleine\s*)?Westerhout|Mar[-\s]*a[-\s]*Lago|(Marla\s*)?Maples|(Matt(hew)? )?Calamari|\bMatt C\b|Melania|(Michael (J.? )?)?Boccio|Rebekah\s*Mercer|Roger\s+Stone|rona|(The\s*)?Art\s*of\s*the\s*Deal",
|
|
523
523
|
emailers = {
|
|
524
524
|
'Bruce Moskowitz': "'Trump's health guy' according to Epstein",
|
|
525
525
|
},
|
epstein_files/util/logging.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from os import environ
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
|
|
4
5
|
from rich.console import Console
|
|
5
6
|
from rich.highlighter import ReprHighlighter
|
|
@@ -7,6 +8,7 @@ from rich.logging import RichHandler
|
|
|
7
8
|
from rich.theme import Theme
|
|
8
9
|
|
|
9
10
|
from epstein_files.util.constant.strings import *
|
|
11
|
+
from epstein_files.util.file_helper import file_size_str
|
|
10
12
|
|
|
11
13
|
FILENAME_STYLE = 'gray27'
|
|
12
14
|
|
|
@@ -55,3 +57,7 @@ if env_log_level_str:
|
|
|
55
57
|
logger.warning(f"Setting log level to {env_log_level} based on {LOG_LEVEL_ENV_VAR} env var...")
|
|
56
58
|
logger.setLevel(env_log_level)
|
|
57
59
|
datefinder_logger.setLevel(env_log_level)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def log_file_write(file_path: str | Path) -> None:
|
|
63
|
+
logger.warning(f"Wrote {file_size_str(file_path)} to '{file_path}'")
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from rich.padding import Padding
|
|
2
|
+
|
|
3
|
+
from epstein_files.documents.email import Email
|
|
4
|
+
from epstein_files.documents.messenger_log import MessengerLog
|
|
5
|
+
from epstein_files.epstein_files import EpsteinFiles, count_by_month
|
|
6
|
+
from epstein_files.util.constant.output_files import JSON_METADATA_PATH
|
|
7
|
+
from epstein_files.util.constant import urls
|
|
8
|
+
from epstein_files.util.constant.html import *
|
|
9
|
+
from epstein_files.util.constant.names import *
|
|
10
|
+
from epstein_files.util.constant.strings import EMAIL_CLASS, MESSENGER_LOG_CLASS
|
|
11
|
+
from epstein_files.util.data import dict_sets_to_lists
|
|
12
|
+
from epstein_files.util.env import args, specified_names
|
|
13
|
+
from epstein_files.util.logging import log_file_write, logger
|
|
14
|
+
from epstein_files.util.rich import *
|
|
15
|
+
|
|
16
|
+
PRINT_COLOR_KEY_EVERY_N_EMAILS = 150
|
|
17
|
+
|
|
18
|
+
# Order matters. Default names to print emails for.
|
|
19
|
+
DEFAULT_EMAILERS = [
|
|
20
|
+
JEREMY_RUBIN,
|
|
21
|
+
AL_SECKEL,
|
|
22
|
+
JOI_ITO,
|
|
23
|
+
JABOR_Y,
|
|
24
|
+
STEVEN_SINOFSKY,
|
|
25
|
+
DANIEL_SIAD,
|
|
26
|
+
JEAN_LUC_BRUNEL,
|
|
27
|
+
STEVEN_HOFFENBERG,
|
|
28
|
+
EHUD_BARAK,
|
|
29
|
+
MARTIN_NOWAK,
|
|
30
|
+
MASHA_DROKOVA,
|
|
31
|
+
RENATA_BOLOTOVA,
|
|
32
|
+
STEVE_BANNON,
|
|
33
|
+
OLIVIER_COLOM,
|
|
34
|
+
BORIS_NIKOLIC,
|
|
35
|
+
PRINCE_ANDREW,
|
|
36
|
+
JIDE_ZEITLIN,
|
|
37
|
+
DAVID_STERN,
|
|
38
|
+
MOHAMED_WAHEED_HASSAN,
|
|
39
|
+
JENNIFER_JACQUET,
|
|
40
|
+
TYLER_SHEARS,
|
|
41
|
+
CHRISTINA_GALBRAITH,
|
|
42
|
+
None,
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
# Order matters. Default names to print tables w/email subject, timestamp, etc for. # TODO: get rid of this ?
|
|
46
|
+
DEFAULT_EMAILER_TABLES: list[str | None] = [
|
|
47
|
+
GHISLAINE_MAXWELL,
|
|
48
|
+
LEON_BLACK,
|
|
49
|
+
SULTAN_BIN_SULAYEM,
|
|
50
|
+
DEEPAK_CHOPRA,
|
|
51
|
+
ARIANE_DE_ROTHSCHILD,
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
if len(set(DEFAULT_EMAILERS).intersection(set(DEFAULT_EMAILER_TABLES))) > 0:
|
|
55
|
+
raise RuntimeError(f"Some names appear in both DEFAULT_EMAILERS and DEFAULT_EMAILER_TABLES")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def print_emails(epstein_files: EpsteinFiles) -> int:
|
|
59
|
+
"""Returns number of emails printed."""
|
|
60
|
+
print_section_header(('Selections from ' if not args.all_emails else '') + 'His Emails')
|
|
61
|
+
print_other_site_link(is_header=False)
|
|
62
|
+
|
|
63
|
+
emailers_to_print: list[str | None]
|
|
64
|
+
emailer_tables: list[str | None] = []
|
|
65
|
+
already_printed_emails: list[Email] = []
|
|
66
|
+
num_emails_printed_since_last_color_key = 0
|
|
67
|
+
|
|
68
|
+
if specified_names:
|
|
69
|
+
emailers_to_print = specified_names
|
|
70
|
+
else:
|
|
71
|
+
epstein_files.print_emailer_counts_table()
|
|
72
|
+
|
|
73
|
+
if args.all_emails:
|
|
74
|
+
emailers_to_print = sorted(epstein_files.all_emailers(), key=lambda e: epstein_files.earliest_email_at(e))
|
|
75
|
+
console.print('Email conversations are sorted chronologically based on time of the first email.')
|
|
76
|
+
print_numbered_list_of_emailers(emailers_to_print, epstein_files)
|
|
77
|
+
else:
|
|
78
|
+
emailers_to_print = DEFAULT_EMAILERS
|
|
79
|
+
emailer_tables = DEFAULT_EMAILER_TABLES
|
|
80
|
+
console.print('Email conversations grouped by counterparty can be found in the order listed below.')
|
|
81
|
+
print_numbered_list_of_emailers(emailers_to_print)
|
|
82
|
+
console.print("\nAfter that there's tables linking to (but not displaying) all known emails for each of these people:")
|
|
83
|
+
print_numbered_list_of_emailers(emailer_tables)
|
|
84
|
+
|
|
85
|
+
for author in emailers_to_print:
|
|
86
|
+
author_emails = epstein_files.print_emails_for(author)
|
|
87
|
+
already_printed_emails.extend(author_emails)
|
|
88
|
+
num_emails_printed_since_last_color_key += len(author_emails)
|
|
89
|
+
|
|
90
|
+
# Print color key every once in a while
|
|
91
|
+
if num_emails_printed_since_last_color_key > PRINT_COLOR_KEY_EVERY_N_EMAILS:
|
|
92
|
+
print_color_key()
|
|
93
|
+
num_emails_printed_since_last_color_key = 0
|
|
94
|
+
|
|
95
|
+
if emailer_tables:
|
|
96
|
+
print_author_header(f"Email Tables for {len(emailer_tables)} Other People", 'white')
|
|
97
|
+
|
|
98
|
+
for name in DEFAULT_EMAILER_TABLES:
|
|
99
|
+
epstein_files.print_emails_table_for(name)
|
|
100
|
+
|
|
101
|
+
if not specified_names:
|
|
102
|
+
epstein_files.print_email_device_info()
|
|
103
|
+
|
|
104
|
+
if args.all_emails:
|
|
105
|
+
_verify_all_emails_printed(epstein_files, already_printed_emails)
|
|
106
|
+
|
|
107
|
+
logger.warning(f"Rewrote {len(Email.rewritten_header_ids)} headers of {len(epstein_files.emails)} emails")
|
|
108
|
+
return len(already_printed_emails)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def print_json_metadata(epstein_files: EpsteinFiles) -> None:
|
|
112
|
+
json_str = epstein_files.json_metadata()
|
|
113
|
+
|
|
114
|
+
if args.build:
|
|
115
|
+
with open(JSON_METADATA_PATH, 'w') as f:
|
|
116
|
+
f.write(json_str)
|
|
117
|
+
log_file_write(JSON_METADATA_PATH)
|
|
118
|
+
else:
|
|
119
|
+
console.print_json(json_str, indent=4, sort_keys=True)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def print_json_stats(epstein_files: EpsteinFiles) -> None:
|
|
123
|
+
console.line(5)
|
|
124
|
+
console.print(Panel('JSON Stats Dump', expand=True, style='reverse bold'), '\n')
|
|
125
|
+
print_json(f"{MESSENGER_LOG_CLASS} Sender Counts", MessengerLog.count_authors(epstein_files.imessage_logs), skip_falsey=True)
|
|
126
|
+
print_json(f"{EMAIL_CLASS} Author Counts", epstein_files.email_author_counts, skip_falsey=True)
|
|
127
|
+
print_json(f"{EMAIL_CLASS} Recipient Counts", epstein_files.email_recipient_counts, skip_falsey=True)
|
|
128
|
+
print_json("Email signature_substitution_countss", epstein_files.email_signature_substitution_counts(), skip_falsey=True)
|
|
129
|
+
print_json("email_author_device_signatures", dict_sets_to_lists(epstein_files.email_authors_to_device_signatures))
|
|
130
|
+
print_json("email_sent_from_devices", dict_sets_to_lists(epstein_files.email_device_signatures_to_authors))
|
|
131
|
+
print_json("email_unknown_recipient_file_ids", epstein_files.email_unknown_recipient_file_ids())
|
|
132
|
+
print_json("count_by_month", count_by_month(epstein_files.all_documents()))
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def print_text_messages(epstein_files: EpsteinFiles) -> None:
|
|
136
|
+
print_section_header('Text Messages')
|
|
137
|
+
print_centered("(conversations are sorted chronologically based on timestamp of first message)\n", style='gray30')
|
|
138
|
+
authors: list[str | None] = specified_names if specified_names else [JEFFREY_EPSTEIN]
|
|
139
|
+
log_files = epstein_files.imessage_logs_for(authors)
|
|
140
|
+
|
|
141
|
+
for log_file in log_files:
|
|
142
|
+
console.print(Padding(log_file))
|
|
143
|
+
console.line(2)
|
|
144
|
+
|
|
145
|
+
epstein_files.print_imessage_summary()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def write_urls() -> None:
|
|
149
|
+
if args.output_file == 'index.html':
|
|
150
|
+
logger.warning(f"Can't write env vars to '{args.output_file}', writing to '{URLS_ENV}' instead.\n")
|
|
151
|
+
args.output_file = URLS_ENV
|
|
152
|
+
|
|
153
|
+
url_vars = {
|
|
154
|
+
k: v for k, v in vars(urls).items()
|
|
155
|
+
if isinstance(v, str) and \
|
|
156
|
+
k.split('_')[-1] in ['URL'] and \
|
|
157
|
+
'michelcrypt4d4mus' in v and \
|
|
158
|
+
'github.com' not in v and \
|
|
159
|
+
'BASE' not in v
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
with open(args.output_file, 'w') as f:
|
|
163
|
+
for var_name, url in url_vars.items():
|
|
164
|
+
key_value = f"{var_name}='{url}'"
|
|
165
|
+
console.print(key_value, style='dim')
|
|
166
|
+
f.write(f"{key_value}\n")
|
|
167
|
+
|
|
168
|
+
console.line()
|
|
169
|
+
logger.warning(f"Wrote {len(url_vars)} URL variables to '{args.output_file}'\n")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _verify_all_emails_printed(epstein_files: EpsteinFiles, already_printed_emails: list[Email]) -> None:
|
|
174
|
+
"""Log warnings if some emails were never printed."""
|
|
175
|
+
email_ids_that_were_printed = set([email.file_id for email in already_printed_emails])
|
|
176
|
+
logger.warning(f"Printed {len(already_printed_emails)} emails of {len(email_ids_that_were_printed)} unique file IDs.")
|
|
177
|
+
|
|
178
|
+
for email in epstein_files.emails:
|
|
179
|
+
if email.file_id not in email_ids_that_were_printed and not email.is_duplicate:
|
|
180
|
+
logger.warning(f"Failed to print {email.summary()}")
|
epstein_files/util/rich.py
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import json
|
|
3
3
|
from os import devnull
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Literal
|
|
6
5
|
|
|
7
6
|
from rich.align import Align
|
|
8
7
|
from rich.console import Console, RenderableType
|
|
@@ -20,9 +19,8 @@ from epstein_files.util.constant.urls import *
|
|
|
20
19
|
from epstein_files.util.constants import FALLBACK_TIMESTAMP, HEADER_ABBREVIATIONS
|
|
21
20
|
from epstein_files.util.data import json_safe
|
|
22
21
|
from epstein_files.util.env import args
|
|
23
|
-
from epstein_files.util.file_helper import file_size_str
|
|
24
22
|
from epstein_files.util.highlighted_group import ALL_HIGHLIGHTS, HIGHLIGHTED_NAMES, EpsteinHighlighter
|
|
25
|
-
from epstein_files.util.logging import logger
|
|
23
|
+
from epstein_files.util.logging import log_file_write, logger
|
|
26
24
|
|
|
27
25
|
TITLE_WIDTH = 50
|
|
28
26
|
NUM_COLOR_KEY_COLS = 4
|
|
@@ -73,6 +71,14 @@ def add_cols_to_table(table: Table, col_names: list[str]) -> None:
|
|
|
73
71
|
table.add_column(col, justify='left' if i == 0 else 'center')
|
|
74
72
|
|
|
75
73
|
|
|
74
|
+
def build_highlighter(pattern: str) -> EpsteinHighlighter:
|
|
75
|
+
class TempHighlighter(EpsteinHighlighter):
|
|
76
|
+
"""rich.highlighter that finds and colors interesting keywords based on the above config."""
|
|
77
|
+
highlights = EpsteinHighlighter.highlights + [re.compile(fr"(?P<trump>{pattern})", re.IGNORECASE)]
|
|
78
|
+
|
|
79
|
+
return TempHighlighter()
|
|
80
|
+
|
|
81
|
+
|
|
76
82
|
def join_texts(txts: list[Text], join: str = ' ', encloser: str = '') -> Text:
|
|
77
83
|
"""Join rich.Text objs into one."""
|
|
78
84
|
if encloser:
|
|
@@ -91,8 +97,11 @@ def join_texts(txts: list[Text], join: str = ' ', encloser: str = '') -> Text:
|
|
|
91
97
|
return txt
|
|
92
98
|
|
|
93
99
|
|
|
94
|
-
def key_value_txt(key: str, value: Text | str) -> Text:
|
|
100
|
+
def key_value_txt(key: str, value: Text | int | str) -> Text:
|
|
95
101
|
"""Generate a Text obj for 'key=value'."""
|
|
102
|
+
if isinstance(value, int):
|
|
103
|
+
value = Text(f"{value}", style='cyan')
|
|
104
|
+
|
|
96
105
|
return Text('').append(key, style=KEY_STYLE).append('=', style=SYMBOL_STYLE).append(value)
|
|
97
106
|
|
|
98
107
|
|
|
@@ -219,10 +228,8 @@ def print_other_site_link(is_header: bool = True) -> None:
|
|
|
219
228
|
print_centered(parenthesize(Text.from_markup(markup_msg)), style='bold')
|
|
220
229
|
word_count_link = link_text_obj(WORD_COUNT_URL, 'site showing the most frequently used words in these communiques', OTHER_SITE_LINK_STYLE)
|
|
221
230
|
print_centered(parenthesize(word_count_link))
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
metadata_link = link_text_obj(JSON_METADATA_URL, 'file metadata containing author attribution explanations', OTHER_SITE_LINK_STYLE)
|
|
225
|
-
print_centered(parenthesize(metadata_link))
|
|
231
|
+
metadata_link = link_text_obj(JSON_METADATA_URL, 'metadata with author attribution explanations', OTHER_SITE_LINK_STYLE)
|
|
232
|
+
print_centered(parenthesize(metadata_link))
|
|
226
233
|
|
|
227
234
|
|
|
228
235
|
def print_page_title(expand: bool = True, width: int | None = None) -> None:
|
|
@@ -298,7 +305,7 @@ def write_html(output_path: Path) -> None:
|
|
|
298
305
|
return
|
|
299
306
|
|
|
300
307
|
console.save_html(str(output_path), code_format=CONSOLE_HTML_FORMAT, theme=HTML_TERMINAL_THEME)
|
|
301
|
-
|
|
308
|
+
log_file_write(output_path)
|
|
302
309
|
|
|
303
310
|
|
|
304
311
|
def _print_abbreviations_table() -> None:
|
|
@@ -1,26 +1,41 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: epstein-files
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: Tools for working with the Jeffrey Epstein documents released in November 2025.
|
|
5
|
+
Home-page: https://michelcrypt4d4mus.github.io/epstein_text_messages/
|
|
6
|
+
License: GPL-3.0-or-later
|
|
7
|
+
Keywords: Epstein,Jeffrey Epstein
|
|
5
8
|
Author: Michel de Cryptadamus
|
|
6
9
|
Requires-Python: >=3.11,<4.0
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Information Technology
|
|
13
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
7
15
|
Classifier: Programming Language :: Python :: 3
|
|
8
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
9
20
|
Requires-Dist: datefinder (>=0.7.3,<0.8.0)
|
|
10
21
|
Requires-Dist: inflection (>=0.5.1,<0.6.0)
|
|
11
22
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
12
23
|
Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
|
|
13
24
|
Requires-Dist: requests (>=2.32.5,<3.0.0)
|
|
14
25
|
Requires-Dist: rich (>=14.2.0,<15.0.0)
|
|
26
|
+
Project-URL: Emails, https://michelcrypt4d4mus.github.io/epstein_text_messages/all_emails_epstein_files_nov_2025.html
|
|
27
|
+
Project-URL: Metadata, https://michelcrypt4d4mus.github.io/epstein_text_messages/file_metadata_epstein_files_nov_2025.json
|
|
28
|
+
Project-URL: TextMessages, https://michelcrypt4d4mus.github.io/epstein_text_messages
|
|
29
|
+
Project-URL: WordCounts, https://michelcrypt4d4mus.github.io/epstein_text_messages/communication_word_count_epstein_files_nov_2025.html
|
|
15
30
|
Description-Content-Type: text/markdown
|
|
16
31
|
|
|
17
32
|
# I Made Epstein's Text Messages Great Again
|
|
18
33
|
|
|
19
34
|
* [I Made Epstein's Text Messages Great Again (And You Should Read Them)](https://cryptadamus.substack.com/p/i-made-epsteins-text-messages-great) post on [Substack](https://cryptadamus.substack.com/p/i-made-epsteins-text-messages-great)
|
|
20
35
|
* The Epstein text messages (and some of the emails along with summary counts of sent emails to/from Epstein) generated by this code can be viewed [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/).
|
|
21
|
-
* All of His Emails can be read at another page also generated by this code [here](https://michelcrypt4d4mus.github.io/
|
|
22
|
-
* Word counts for the emails and text messages are [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/
|
|
23
|
-
* Metadata containing what I have figured out about who sent or received the communications in a given file (and a brief explanation for how I figured it out for each file) is deployed [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/
|
|
36
|
+
* All of His Emails can be read at another page also generated by this code [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/all_emails_epstein_files_nov_2025.html).
|
|
37
|
+
* Word counts for the emails and text messages are [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/communication_word_count_epstein_files_nov_2025.html).
|
|
38
|
+
* Metadata containing what I have figured out about who sent or received the communications in a given file (and a brief explanation for how I figured it out for each file) is deployed [here](https://michelcrypt4d4mus.github.io/epstein_text_messages/file_metadata_epstein_files_nov_2025.json)
|
|
24
39
|
* Configuration variables assigning specific `HOUSE_OVERSIGHT_XXXXXX.txt` file IDs (the `111111` part) as being emails to or from particular people based on various research and contributions can be found in [constants.py](./epstein_files/util/constants.py). Everything in `constants.py` should also appear in the JSON metadata.
|
|
25
40
|
|
|
26
41
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
epstein_files/__init__.py,sha256=N4-A81KlSNWXyliBsjooi6GZr9_2qIB08qTG5RE9GzA,4725
|
|
2
|
+
epstein_files/documents/communication.py,sha256=SunZdjMhR9v6y8LlQ6jhIu8vYjSndaBK0Su1mKnhfj0,2060
|
|
3
|
+
epstein_files/documents/document.py,sha256=MOTS6AZFNOqnzpvYLXvoJC05ZVL9lTZnsRc-qjAjcJ4,16515
|
|
4
|
+
epstein_files/documents/email.py,sha256=IpKeOuLTmHWowBvUUEp-tyTC8pwEmXg3XgLJkplQZWg,37717
|
|
5
|
+
epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
|
|
6
|
+
epstein_files/documents/imessage/text_message.py,sha256=DMdd__L7UPad0YS49MJf_3bTVyE1BLfWafQbDQierC8,3272
|
|
7
|
+
epstein_files/documents/json_file.py,sha256=Vf9iHiEhUqk-hEh6lGZX_mJNWZUUQWeT-UI3FhKW0hw,1101
|
|
8
|
+
epstein_files/documents/messenger_log.py,sha256=-hSMFH_dyrjGLdph4SU2xQK4RpXOhkR3R_nqRrz3e1w,5620
|
|
9
|
+
epstein_files/documents/other_file.py,sha256=JbKDtNrQ1Ua5vGPlZayON5Kgy0oJ-gHcdO9l9Iv9wRo,8930
|
|
10
|
+
epstein_files/epstein_files.py,sha256=NpgQaxM3cC8CsAbzCyysakMbPdASWAt-wOhPZ879ZyQ,18018
|
|
11
|
+
epstein_files/util/constant/common_words.py,sha256=aR0UjoWmxyR49XS-DtHECQ1CiA_bK8hNP6CQ1TS9yZA,3696
|
|
12
|
+
epstein_files/util/constant/html.py,sha256=9U098TGzlghGg4WfxLYHyub5JGR17Dv7VP5i2MSu8Kk,1415
|
|
13
|
+
epstein_files/util/constant/names.py,sha256=g0s9NA4zIexDGG7u5x0KDpLB9fyrYaYatsBhf_lH688,10253
|
|
14
|
+
epstein_files/util/constant/output_files.py,sha256=B2qEXfNI_gT2Vp5HGSld2xM0PfeZ27j65HNymSmyzX4,974
|
|
15
|
+
epstein_files/util/constant/strings.py,sha256=3JTqD0luJrC3NbGXn4q6P-gIaaNVx36P1oCmp92gAoM,1750
|
|
16
|
+
epstein_files/util/constant/urls.py,sha256=x7Lv8yNNNLGU3GCvG4YbJ4qX3s_hiXffYuYUCjXyfbg,5526
|
|
17
|
+
epstein_files/util/constants.py,sha256=xME94iH9a4b95N4yABs20Gn3Tu3cwmx5kNE_fPhsJEM,103420
|
|
18
|
+
epstein_files/util/data.py,sha256=P4D_ggNNyScpTnu9wow8-67BlZtAXFKulJ5zbGtBR9A,2907
|
|
19
|
+
epstein_files/util/doc_cfg.py,sha256=6H5EFLxG0ABG4BJHIEL7PSMBVwkcyjH1vvmitSQRa48,9615
|
|
20
|
+
epstein_files/util/env.py,sha256=A2hEVg1HYymGd2odrLLo6k7yIvu0hh1XZniUW2u21dM,4734
|
|
21
|
+
epstein_files/util/file_helper.py,sha256=v_bE10MHEcXti9DVJo4WqyOsG83Xrv05S3Vc70cYJkk,3082
|
|
22
|
+
epstein_files/util/highlighted_group.py,sha256=7MfES52q10eq35L93iTIr_v5v0bamdQKCf7hlDIy7O8,35196
|
|
23
|
+
epstein_files/util/logging.py,sha256=GjmOYiWAF1R_0Dvb5kXHAgPH5UJs-_gGcRig7LEDDL0,2066
|
|
24
|
+
epstein_files/util/output.py,sha256=YH_-1YyNxiO29N88jvSAePbK5n25tgEIDFyP3sNNnnI,7309
|
|
25
|
+
epstein_files/util/rich.py,sha256=gvSbWc-PQC5cAUg8zn02yZQkU57ExG1ArRLMIPrVxOc,13597
|
|
26
|
+
epstein_files/util/search_result.py,sha256=1fxe0KPBQXBk4dLfu6m0QXIzYfZCzvaSkWqvghJGzxY,567
|
|
27
|
+
epstein_files/util/timer.py,sha256=8hxW4Y1JcTUfnBrHh7sL2pM9xu1sL4HFQM4CmmzTarU,837
|
|
28
|
+
epstein_files/util/word_count.py,sha256=XTINgLm01jFQlNgdiLCcVFCodXAIb1dNbaAvznoRb1o,6757
|
|
29
|
+
epstein_files-1.0.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
30
|
+
epstein_files-1.0.2.dist-info/METADATA,sha256=Wf4rPDzdGRxogbs0H8cZoFb7HsRTrkPvkYHdClbg74c,4653
|
|
31
|
+
epstein_files-1.0.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
|
32
|
+
epstein_files-1.0.2.dist-info/entry_points.txt,sha256=EV9qTh_n9X_1MOiQnxG5hM6R5v0rfi8W4QE-bsZkw3o,238
|
|
33
|
+
epstein_files-1.0.2.dist-info/RECORD,,
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
epstein_files/__init__.py,sha256=HKOGWVzyiEl0II8s7qnO33wcTZPw8dr3HDfT7_VnY2U,7831
|
|
2
|
-
epstein_files/documents/communication.py,sha256=SunZdjMhR9v6y8LlQ6jhIu8vYjSndaBK0Su1mKnhfj0,2060
|
|
3
|
-
epstein_files/documents/document.py,sha256=E2VUuHSoam8r8pyRbWy68_cVFU9DJ0irbtYULaDBYzE,16378
|
|
4
|
-
epstein_files/documents/email.py,sha256=IpKeOuLTmHWowBvUUEp-tyTC8pwEmXg3XgLJkplQZWg,37717
|
|
5
|
-
epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
|
|
6
|
-
epstein_files/documents/imessage/text_message.py,sha256=DMdd__L7UPad0YS49MJf_3bTVyE1BLfWafQbDQierC8,3272
|
|
7
|
-
epstein_files/documents/json_file.py,sha256=Vf9iHiEhUqk-hEh6lGZX_mJNWZUUQWeT-UI3FhKW0hw,1101
|
|
8
|
-
epstein_files/documents/messenger_log.py,sha256=-hSMFH_dyrjGLdph4SU2xQK4RpXOhkR3R_nqRrz3e1w,5620
|
|
9
|
-
epstein_files/documents/other_file.py,sha256=JbKDtNrQ1Ua5vGPlZayON5Kgy0oJ-gHcdO9l9Iv9wRo,8930
|
|
10
|
-
epstein_files/epstein_files.py,sha256=ruhl24FgOpEdcqbMcIpgyYlqEBi1ZeztQ7QmZMYANp0,17856
|
|
11
|
-
epstein_files/util/constant/common_words.py,sha256=aR0UjoWmxyR49XS-DtHECQ1CiA_bK8hNP6CQ1TS9yZA,3696
|
|
12
|
-
epstein_files/util/constant/html.py,sha256=9U098TGzlghGg4WfxLYHyub5JGR17Dv7VP5i2MSu8Kk,1415
|
|
13
|
-
epstein_files/util/constant/names.py,sha256=eSgHnOqMAy7Czfw1vJ3lvniDST7QpfuQ8XgzttXpAi8,10191
|
|
14
|
-
epstein_files/util/constant/strings.py,sha256=3JTqD0luJrC3NbGXn4q6P-gIaaNVx36P1oCmp92gAoM,1750
|
|
15
|
-
epstein_files/util/constant/urls.py,sha256=P_nnb5cIrJ2NCbd4CoRfilZ5jrOzFs30jNK50F7IjZw,5483
|
|
16
|
-
epstein_files/util/constants.py,sha256=l0TrpncCJcecar5geggLVfOJVhicWcu3zws-62Cslzg,102472
|
|
17
|
-
epstein_files/util/data.py,sha256=s7EgmQ6SC6MoUMhP8GaxglJOJpU_nRmwI-T2inLl8hs,3329
|
|
18
|
-
epstein_files/util/doc_cfg.py,sha256=AFLBp9PO2tBUYhTeNztpkWs69VPr41fCuA22IesM59g,9914
|
|
19
|
-
epstein_files/util/env.py,sha256=9wM4mKPZoJO9J5VKLP67ZR1IEMkH2UaGdIaYm2tptMQ,4581
|
|
20
|
-
epstein_files/util/file_helper.py,sha256=ea428og2gyUsMWd2GFldmAGvuqGNNHaTc7gGGSM_0aI,3827
|
|
21
|
-
epstein_files/util/highlighted_group.py,sha256=UO0pqQH29JHiOMK2psIozIeA0zinDkql-NYDGRmFUzA,35173
|
|
22
|
-
epstein_files/util/logging.py,sha256=0mABrI5TvodLDe-9svHv3YaIdSyr8PXFcu4nntW1WsI,1858
|
|
23
|
-
epstein_files/util/rich.py,sha256=cLkiSg3f68bUxobzRiBRfrgS7Ya-FK7ltpQcZXNHMX4,13317
|
|
24
|
-
epstein_files/util/search_result.py,sha256=1fxe0KPBQXBk4dLfu6m0QXIzYfZCzvaSkWqvghJGzxY,567
|
|
25
|
-
epstein_files/util/timer.py,sha256=8hxW4Y1JcTUfnBrHh7sL2pM9xu1sL4HFQM4CmmzTarU,837
|
|
26
|
-
epstein_files/util/word_count.py,sha256=XTINgLm01jFQlNgdiLCcVFCodXAIb1dNbaAvznoRb1o,6757
|
|
27
|
-
epstein_files-1.0.1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
28
|
-
epstein_files-1.0.1.dist-info/METADATA,sha256=IK5B-ltx_L0-EK2Oq2Q2gVXWlhYqKoYw6HCFisqitvQ,3587
|
|
29
|
-
epstein_files-1.0.1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
|
30
|
-
epstein_files-1.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|