epstein-files 1.0.13__py3-none-any.whl → 1.0.15__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/util/env.py CHANGED
@@ -8,10 +8,8 @@ from rich_argparse_plus import RichHelpFormatterPlus
8
8
 
9
9
  from epstein_files.util.logging import env_log_level, logger
10
10
 
11
- COUNT_WORDS_SCRIPT = 'epstein_word_count'
12
11
  DEFAULT_WIDTH = 145
13
- HTML_SCRIPTS = ['epstein_generate', COUNT_WORDS_SCRIPT]
14
- EPSTEIN_DOCS_DIR_ENV_VAR_NAME = 'EPSTEIN_DOCS_DIR'
12
+ HTML_SCRIPTS = ['epstein_generate', 'epstein_word_count']
15
13
 
16
14
 
17
15
  RichHelpFormatterPlus.choose_theme('morning_glory')
@@ -31,8 +29,8 @@ output.add_argument('--output-other', '-oo', action='store_true', help='generate
31
29
  output.add_argument('--output-texts', '-ot', action='store_true', help='generate text messages section')
32
30
  output.add_argument('--sort-alphabetical', action='store_true', help='sort emailers alphabetically intead of by email count')
33
31
  output.add_argument('--suppress-output', action='store_true', help='no output to terminal (use with --build)')
32
+ output.add_argument('--uninteresting', action='store_true', help='only output uninteresting other files')
34
33
  output.add_argument('--width', '-w', type=int, default=DEFAULT_WIDTH, help='screen width to use (in characters)')
35
- output.add_argument('--use-epstein-web', action='store_true', help='use epsteinweb.org links instead of epstein.media')
36
34
 
37
35
  scripts = parser.add_argument_group('SCRIPTS', 'Options used by epstein_search, epstein_show, and epstein_diff.')
38
36
  scripts.add_argument('positional_args', nargs='*', help='strings to searchs for, file IDs to show or diff, etc.')
@@ -50,6 +48,7 @@ args = parser.parse_args()
50
48
 
51
49
 
52
50
  # Verify Epstein docs can be found
51
+ EPSTEIN_DOCS_DIR_ENV_VAR_NAME = 'EPSTEIN_DOCS_DIR'
53
52
  DOCS_DIR_ENV = environ.get(EPSTEIN_DOCS_DIR_ENV_VAR_NAME)
54
53
  DOCS_DIR = Path(DOCS_DIR_ENV or '').resolve()
55
54
 
@@ -65,13 +64,13 @@ is_env_var_set = lambda s: len(environ.get(s) or '') > 0
65
64
  is_html_script = current_script in HTML_SCRIPTS
66
65
 
67
66
  args.debug = args.deep_debug or args.debug or is_env_var_set('DEBUG')
67
+ args.names = [None if n == 'None' else n for n in (args.names or [])]
68
68
  args.output_emails = args.output_emails or args.all_emails
69
- args.output_other = args.output_other or args.all_other_files
69
+ args.output_other = args.output_other or args.all_other_files or args.uninteresting
70
70
  args.overwrite_pickle = args.overwrite_pickle or (is_env_var_set('OVERWRITE_PICKLE') and not is_env_var_set('PICKLED'))
71
71
  args.width = args.width if is_html_script else None
72
- is_output_selected = any([arg.startswith('output_') and value for arg, value in vars(args).items()])
73
- is_output_selected = is_output_selected or args.json_metadata or args.colors_only
74
- specified_names: list[str | None] = [None if n == 'None' else n for n in (args.names or [])]
72
+ is_any_output_selected = any([arg.startswith('output_') and value for arg, value in vars(args).items()])
73
+ is_any_output_selected = is_any_output_selected or args.json_metadata or args.colors_only
75
74
 
76
75
  # Log level args
77
76
  if args.deep_debug:
@@ -86,12 +85,12 @@ elif not env_log_level:
86
85
  logger.info(f'Log level set to {logger.level}...')
87
86
 
88
87
  # Massage args that depend on other args to the appropriate state
89
- if current_script == 'epstein_generate' and not (is_output_selected or args.make_clean):
88
+ if current_script == 'epstein_generate' and not (is_any_output_selected or args.make_clean):
90
89
  logger.warning(f"No output section chosen; outputting default selection of texts, selected emails, and other files...")
91
90
  args.output_texts = args.output_emails = args.output_other = True
92
91
 
93
- if args.use_epstein_web:
94
- logger.warning(f"Using links to epsteinweb.org links instead of epsteinify.com...")
95
-
96
92
  if args.debug:
97
- logger.warning(f"Invocation args:\ncurrent_script={current_script}\nis_html_script={is_html_script},\nis_output_selected={is_output_selected}\nspecified_names={specified_names},\nargs={args}")
93
+ logger.warning(f"Invocation args:\ncurrent_script={current_script}\nis_html_script={is_html_script},\nis_output_selected={is_any_output_selected},\nargs={args}")
94
+
95
+ if args.names:
96
+ logger.warning(f"Output restricted to {args.names}")
@@ -12,7 +12,6 @@ KB = 1024
12
12
  MB = KB * KB
13
13
 
14
14
  file_size = lambda file_path: Path(file_path).stat().st_size
15
- file_size_str = lambda file_path: file_size_to_str(file_size(file_path))
16
15
 
17
16
  # Coerce methods handle both string and int arguments.
18
17
  coerce_file_name = lambda filename_or_id: coerce_file_stem(filename_or_id) + '.txt'
@@ -46,8 +45,12 @@ def extract_file_id(filename_or_id: int | str | Path) -> str:
46
45
  return file_match.group(1)
47
46
 
48
47
 
49
- def file_size_to_str(size: int) -> str:
50
- digits = 2
48
+ def file_size_str(file_path, digits: int | None = None):
49
+ return file_size_to_str(file_size(file_path), digits)
50
+
51
+
52
+ def file_size_to_str(size: int, digits: int | None = None) -> str:
53
+ _digits = 2
51
54
 
52
55
  if size > MB:
53
56
  size_num = float(size) / MB
@@ -55,10 +58,11 @@ def file_size_to_str(size: int) -> str:
55
58
  elif size > KB:
56
59
  size_num = float(size) / KB
57
60
  size_str = 'kb'
58
- digits = 1
61
+ _digits = 1
59
62
  else:
60
63
  return f"{size} b"
61
64
 
65
+ digits = _digits if digits is None else digits
62
66
  return f"{size_num:,.{digits}f} {size_str}"
63
67
 
64
68
 
@@ -302,7 +302,7 @@ HIGHLIGHTED_NAMES = [
302
302
  HighlightedNames(
303
303
  label=FINANCE,
304
304
  style='green',
305
- pattern=r'Apollo|Ari\s*Glass|Bank|(Bernie\s*)?Madoff|Black(rock|stone)|B\s*of\s*A|Boothbay(\sFund\sManagement)?|Chase\s*Bank|Credit\s*Suisse|DB|Deutsche\s*(Asset|Bank)|Electron\s*Capital\s*(Partners)?|Fenner|FRBNY|Goldman(\s*Sachs)|HSBC|Invesco|(Janet\s*)?Yellen|(Jerome\s*)?Powell(?!M\. Cabot)|(Jimmy\s*)?Cayne|JPMC?|j\.?p\.?\s*morgan(\.?com|\s*Chase)?|Madoff|Merrill(\s*Lynch)?|(Michael\s*)?(Cembalest|Milken)|Mizrahi\s*Bank|MLPF&S|((anti.?)?money\s+)?launder(s?|ers?|ing)?(\s+money)?|Morgan Stanley|(Peter L. )?Scher|(Ray\s*)?Dalio|(Richard\s*)?LeFrak|Schwartz?man|Serageldin|UBS|us.gio@jpmorgan.com',
305
+ pattern=r'Apollo|Ari\s*Glass|Bank|(Bernie\s*)?Madoff|Black(rock|stone)|B\s*of\s*A|Boothbay(\sFund\sManagement)?|Chase\s*Bank|Credit\s*Suisse|DB|Deutsche?\s*(Asset|Bank)|Electron\s*Capital\s*(Partners)?|Fenner|FRBNY|Goldman(\s*Sachs)|HSBC|Invesco|(Janet\s*)?Yellen|(Jerome\s*)?Powell(?!M\. Cabot)|(Jimmy\s*)?Cayne|JPMC?|j\.?p\.?\s*morgan(\.?com|\s*Chase)?|Madoff|Merrill(\s*Lynch)?|(Michael\s*)?(Cembalest|Milken)|Mizrahi\s*Bank|MLPF&S|((anti.?)?money\s+)?launder(s?|ers?|ing)?(\s+money)?|Morgan Stanley|(Peter L. )?Scher|(Ray\s*)?Dalio|(Richard\s*)?LeFrak|Schwartz?man|Serageldin|UBS|us.gio@jpmorgan.com',
306
306
  emailers={
307
307
  AMANDA_ENS: 'Citigroup',
308
308
  BRAD_WECHSLER: f"head of {LEON_BLACK}'s personal investment vehicle according to FT",
@@ -373,14 +373,6 @@ HIGHLIGHTED_NAMES = [
373
373
  style='color(168)',
374
374
  pattern=r'BOJ|(Bank\s+of\s+)?Japan(ese)?|jpy?(?! Morgan)|SG|Singapore|Toky[op]',
375
375
  ),
376
- HighlightedNames(
377
- label='javanka',
378
- style='medium_violet_red',
379
- emailers = {
380
- IVANKA: None,
381
- JARED_KUSHNER: None,
382
- }
383
- ),
384
376
  HighlightedNames(
385
377
  label=JOURNALIST,
386
378
  style='bright_yellow',
@@ -404,7 +396,7 @@ HIGHLIGHTED_NAMES = [
404
396
  HighlightedNames(
405
397
  label='law enforcement',
406
398
  style='color(24) bold',
407
- pattern=r'ag|(Alicia\s*)?Valle|AML|(Andrew\s*)?McCabe|attorney|((Bob|Robert)\s*)?Mueller|(Byung\s)?Pak|CFTC?|CIA|CIS|CVRA|Dep(artmen)?t\.?\s*of\s*(the\s*)?(Justice|Treasury)|DHS|DOJ|FBI|FCPA|FDIC|Federal\s*Bureau\s*of\s*Investigation|FinCEN|FINRA|FOIA|FTC|IRS|(James\s*)?Comey|(Jennifer\s*Shasky\s*)?Calvery|((Judge|Mark)\s*)?(Carney|Filip)|(Kirk )?Blouin|KYC|NIH|NS(A|C)|OCC|OFAC|(Lann?a\s*)?Belohlavek|lawyer|(Michael\s*)?Reiter|OGE|Office\s*of\s*Government\s*Ethics|Police Code Enforcement|(Preet\s*)?Bharara|SCOTUS|SD(FL|NY)|Southern\s*District\s*of\s*(Florida|New\s*York)|SEC|Secret\s*Service|Securities\s*and\s*Exchange\s*Commission|State\s*Dep(artmen)?t|Strzok|Supreme\s*Court|Treasury\s*(Dep(artmen)?t|Secretary)|TSA|USAID|(William\s*J\.?\s*)?Zloch',
399
+ pattern=r'ag|(Alicia\s*)?Valle|AML|(Andrew\s*)?McCabe|((Bob|Robert)\s*)?Mueller|(Byung\s)?Pak|CFTC?|CIA|CIS|CVRA|Dep(artmen)?t\.?\s*of\s*(the\s*)?(Justice|Treasury)|DHS|DOJ|FBI|FCPA|FDIC|Federal\s*Bureau\s*of\s*Investigation|FinCEN|FINRA|FOIA|FTC|IRS|(James\s*)?Comey|(Jennifer\s*Shasky\s*)?Calvery|((Judge|Mark)\s*)?(Carney|Filip)|(Kirk )?Blouin|KYC|NIH|NS(A|C)|OCC|OFAC|(Lann?a\s*)?Belohlavek|(Michael\s*)?Reiter|OGE|Office\s*of\s*Government\s*Ethics|Police Code Enforcement|(Preet\s*)?Bharara|SCOTUS|SD(FL|NY)|SEC|Secret\s*Service|Securities\s*and\s*Exchange\s*Commission|Southern\s*District\s*of\s*(Florida|New\s*York)|State\s*Dep(artmen)?t|Strzok|Supreme\s*Court|Treasury\s*(Dep(artmen)?t|Secretary)|TSA|USAID|(William\s*J\.?\s*)?Zloch',
408
400
  emailers = {
409
401
  ANN_MARIE_VILLAFANA: 'southern district of Florida U.S. Attorney',
410
402
  DANNY_FROST: 'Director of Communications at Manhattan DA',
@@ -476,7 +468,7 @@ HIGHLIGHTED_NAMES = [
476
468
  pattern=r'Alberto\sGonzale[sz]|(Alex\s*)?Acosta|(Bill\s*)?Barr|Bill\s*Shine|(Bob\s*)?Corker|(John\s*(R.?\s*)?)Bolton|Broidy|(Chris\s)?Christie|Devin\s*Nunes|(Don\s*)?McGa[hn]n|McMaster|(George\s*)?Nader|GOP|(Brett\s*)?Kavanaugh|Kissinger|Kobach|Koch\s*Brothers|Kolfage|Kudlow|Lewandowski|(Marco\s)?Rubio|(Mark\s*)Meadows|Mattis|McCain|(?<!Merwin Dela )Cruz|(Michael\s)?Hayden|((General|Mike)\s*)?(Flynn|Pence)|(Mitt\s*)?Romney|Mnuchin|Nikki|Haley|(Paul\s+)?(Manafort|Volcker)|(Peter\s)?Navarro|Pompeo|Reagan|Reince|Priebus|Republican|(Rex\s*)?Tillerson|(?<!Cynthia )(Richard\s*)?Nixon|Sasse|Tea\s*Party',
477
469
  # There's no emails from these people, they're just here to automate the regex creation for both first + last names
478
470
  emailers = {
479
- RUDY_GIULIANI: 'disbarred formed mayor of New York City',
471
+ RUDY_GIULIANI: None,
480
472
  TULSI_GABBARD: None,
481
473
  },
482
474
  ),
@@ -484,7 +476,7 @@ HIGHLIGHTED_NAMES = [
484
476
  label='Rothschild family',
485
477
  style='indian_red',
486
478
  emailers={
487
- ARIANE_DE_ROTHSCHILD: None,
479
+ ARIANE_DE_ROTHSCHILD: 'heiress',
488
480
  JOHNNY_EL_HACHEM: f'Works with {ARIANE_DE_ROTHSCHILD}',
489
481
  },
490
482
  ),
@@ -504,7 +496,7 @@ HIGHLIGHTED_NAMES = [
504
496
  style='light_goldenrod2',
505
497
  pattern=r'Alain Forget|Brotherton|Carl\s*Sagan|Columbia|David Grosof|J(ames|im)\s*Watson|(Lord\s*)?Martin\s*Rees|Massachusetts\s*Institute\s*of\s*Technology|MIT(\s*Media\s*Lab)?|Media\s*Lab|Minsky|((Noam|Valeria)\s*)?Chomsky|Norman\s*Finkelstein|Praluent|Regeneron|(Richard\s*)?Dawkins|Sanofi|Stanford|(Stephen\s*)?Hawking|(Steven?\s*)?Pinker|UCLA',
506
498
  emailers = {
507
- DAVID_HAIG: None,
499
+ DAVID_HAIG: 'evolutionary geneticist?',
508
500
  JOSCHA_BACH: 'cognitive science / AI research',
509
501
  'Daniel Kahneman': 'Nobel economic sciences laureate and cognitivie psychologist (?)',
510
502
  'Ed Boyden': 'Associate Professor, MIT Media Lab neurobiology',
@@ -538,7 +530,7 @@ HIGHLIGHTED_NAMES = [
538
530
  HighlightedNames(
539
531
  label='trump',
540
532
  style='red3 bold',
541
- 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",
533
+ 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)|Ivank?a|Jared|Kushner|(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",
542
534
  emailers = {
543
535
  'Bruce Moskowitz': "'Trump's health guy' according to Epstein",
544
536
  },
@@ -560,7 +552,7 @@ HIGHLIGHTED_NAMES = [
560
552
  HighlightedNames(
561
553
  label=VIRGIN_ISLANDS,
562
554
  style='sea_green1',
563
- pattern=r'Antigua|Bahamas|Caribb?ean|Dominican\s*Republic|(Great|Little)\s*St.?\s*James|Haiti(an)?|(John\s*)deJongh(\s*Jr\.?)|(Kenneth E\. )?Mapp|Palm\s*Beach(?!\s*Post)|PBI|S(ain)?t.?\s*Thomas|USVI|VI|(The\s*)?Virgin\s*Islands(\s*Daily\s*News)?', # TODO: VI Daily News should be yellow but it's hard bc Daily News xists
555
+ pattern=r'Antigua|Bahamas|Caribb?ean|Dominican\s*Republic|(Great|Little)\s*St.?\s*James|Haiti(an)?|(John\s*)deJongh(\s*Jr\.?)|(Kenneth E\. )?Mapp|Palm\s*Beach(?!\s*Post)|PBI|S(ain)?t.?\s*Thomas|USVI|(?<!Epstein )VI|(The\s*)?Virgin\s*Islands(\s*Daily\s*News)?', # TODO: VI Daily News should be yellow but it's hard bc Daily News xists
564
556
  emailers = {
565
557
  CECILE_DE_JONGH: f'First lady 2007-2015',
566
558
  STACEY_PLASKETT: 'non-voting member of Congress',
@@ -669,7 +661,7 @@ def get_info_for_name(name: str) -> str | None:
669
661
  def get_style_for_category(category: str) -> str | None:
670
662
  if category in CATEGORY_STYLES:
671
663
  return CATEGORY_STYLES[category]
672
- elif category in [CONFERENCE, SPEECH]:
664
+ elif category == CONFERENCE:
673
665
  return f"{get_style_for_category(ACADEMIA)} dim"
674
666
  elif category == SOCIAL:
675
667
  return get_style_for_category(PUBLICIST)
@@ -4,13 +4,14 @@ from rich.padding import Padding
4
4
 
5
5
  from epstein_files.documents.email import Email
6
6
  from epstein_files.documents.messenger_log import MessengerLog
7
+ from epstein_files.documents.other_file import FIRST_FEW_LINES, OtherFile
7
8
  from epstein_files.epstein_files import EpsteinFiles, count_by_month
8
9
  from epstein_files.util.constant import output_files
9
10
  from epstein_files.util.constant.html import *
10
11
  from epstein_files.util.constant.names import *
11
12
  from epstein_files.util.constant.output_files import JSON_FILES_JSON_PATH, JSON_METADATA_PATH
12
13
  from epstein_files.util.data import dict_sets_to_lists
13
- from epstein_files.util.env import args, specified_names
14
+ from epstein_files.util.env import args
14
15
  from epstein_files.util.file_helper import log_file_write
15
16
  from epstein_files.util.logging import logger
16
17
  from epstein_files.util.rich import *
@@ -20,20 +21,18 @@ PRINT_COLOR_KEY_EVERY_N_EMAILS = 150
20
21
  # Order matters. Default names to print emails for.
21
22
  DEFAULT_EMAILERS = [
22
23
  JEREMY_RUBIN,
23
- AL_SECKEL,
24
24
  JOI_ITO,
25
25
  JABOR_Y,
26
26
  STEVEN_SINOFSKY,
27
+ AL_SECKEL,
27
28
  DANIEL_SIAD,
28
29
  JEAN_LUC_BRUNEL,
29
30
  STEVEN_HOFFENBERG,
31
+ RENATA_BOLOTOVA,
32
+ MASHA_DROKOVA,
30
33
  EHUD_BARAK,
31
34
  MARTIN_NOWAK,
32
- MASHA_DROKOVA,
33
- RENATA_BOLOTOVA,
34
35
  STEVE_BANNON,
35
- OLIVIER_COLOM,
36
- BORIS_NIKOLIC,
37
36
  PRINCE_ANDREW,
38
37
  JIDE_ZEITLIN,
39
38
  DAVID_STERN,
@@ -41,6 +40,7 @@ DEFAULT_EMAILERS = [
41
40
  JENNIFER_JACQUET,
42
41
  TYLER_SHEARS,
43
42
  CHRISTINA_GALBRAITH,
43
+ ZUBAIR_KHAN,
44
44
  None,
45
45
  ]
46
46
 
@@ -57,19 +57,19 @@ if len(set(DEFAULT_EMAILERS).intersection(set(DEFAULT_EMAILER_TABLES))) > 0:
57
57
  raise RuntimeError(f"Some names appear in both DEFAULT_EMAILERS and DEFAULT_EMAILER_TABLES")
58
58
 
59
59
 
60
- def print_emails(epstein_files: EpsteinFiles) -> int:
61
- """Returns number of emails printed."""
60
+ def print_emails_section(epstein_files: EpsteinFiles) -> list[Email]:
61
+ """Returns emails that were printed (may contain dupes if printed for both author and recipient)."""
62
62
  print_section_header(('Selections from ' if not args.all_emails else '') + 'His Emails')
63
- print_other_site_link(is_header=False)
63
+ print_all_files_page_link(epstein_files)
64
64
  emailers_to_print: list[str | None]
65
65
  emailer_tables: list[str | None] = []
66
66
  already_printed_emails: list[Email] = []
67
67
  num_emails_printed_since_last_color_key = 0
68
68
 
69
- if specified_names:
70
- emailers_to_print = specified_names
69
+ if args.names:
70
+ emailers_to_print = args.names
71
71
  else:
72
- epstein_files.print_emailer_counts_table()
72
+ print_centered(Padding(epstein_files.table_of_emailers(), (2, 0)))
73
73
 
74
74
  if args.all_emails:
75
75
  emailers_to_print = sorted(epstein_files.all_emailers(), key=lambda e: epstein_files.earliest_email_at(e))
@@ -99,16 +99,16 @@ def print_emails(epstein_files: EpsteinFiles) -> int:
99
99
  for name in DEFAULT_EMAILER_TABLES:
100
100
  epstein_files.print_emails_table_for(name)
101
101
 
102
- if not specified_names:
102
+ if not args.names:
103
103
  epstein_files.print_email_device_info()
104
104
 
105
105
  if args.all_emails:
106
106
  _verify_all_emails_were_printed(epstein_files, already_printed_emails)
107
107
 
108
- fwded_articles = [e for e in already_printed_emails if e.config and e.config.is_fwded_article]
109
- log_msg = f"Rewrote {len(Email.rewritten_header_ids)} email headers (out of {len(already_printed_emails)})"
108
+ fwded_articles = [e for e in already_printed_emails if e.config and e.is_fwded_article()]
109
+ log_msg = f"Rewrote {len(Email.rewritten_header_ids)} of {len(already_printed_emails)} email headers"
110
110
  logger.warning(f"{log_msg}, {len(fwded_articles)} of the emails were forwarded articles.")
111
- return len(already_printed_emails)
111
+ return already_printed_emails
112
112
 
113
113
 
114
114
  def print_json_files(epstein_files: EpsteinFiles):
@@ -125,17 +125,6 @@ def print_json_files(epstein_files: EpsteinFiles):
125
125
  console.print_json(json_file.json_str(), indent=4, sort_keys=False)
126
126
 
127
127
 
128
- def write_json_metadata(epstein_files: EpsteinFiles) -> None:
129
- json_str = epstein_files.json_metadata()
130
-
131
- if args.build:
132
- with open(JSON_METADATA_PATH, 'w') as f:
133
- f.write(json_str)
134
- log_file_write(JSON_METADATA_PATH)
135
- else:
136
- console.print_json(json_str, indent=4, sort_keys=True)
137
-
138
-
139
128
  def print_json_stats(epstein_files: EpsteinFiles) -> None:
140
129
  console.line(5)
141
130
  console.print(Panel('JSON Stats Dump', expand=True, style='reverse bold'), '\n')
@@ -149,21 +138,52 @@ def print_json_stats(epstein_files: EpsteinFiles) -> None:
149
138
  print_json("count_by_month", count_by_month(epstein_files.all_documents()))
150
139
 
151
140
 
152
- def print_text_messages(epstein_files: EpsteinFiles) -> None:
153
- print_section_header('Text Messages')
141
+ def print_other_files_section(files: list[OtherFile], epstein_files: EpsteinFiles) -> None:
142
+ """Returns the OtherFile objects that were interesting enough to print."""
143
+ category_table = OtherFile.count_by_category_table(files)
144
+ other_files_preview_table = OtherFile.files_preview_table(files)
145
+ header_pfx = '' if args.all_other_files else 'Selected '
146
+ print_section_header(f"{FIRST_FEW_LINES} of {len(files)} {header_pfx}Files That Are Neither Emails Nor Text Messages")
147
+
148
+ if args.all_other_files:
149
+ console.line(1)
150
+ else:
151
+ print_all_files_page_link(epstein_files)
152
+ console.line(2)
153
+
154
+ for table in [category_table, other_files_preview_table]:
155
+ table.title = f"{header_pfx}{table.title}"
156
+
157
+ print_centered(category_table)
158
+ console.line(2)
159
+ console.print(other_files_preview_table)
160
+
161
+
162
+ def print_text_messages_section(epstein_files: EpsteinFiles) -> None:
163
+ """Print summary table and stats for text messages."""
164
+ print_section_header('All of His Text Messages')
154
165
  print_centered("(conversations are sorted chronologically based on timestamp of first message)\n", style='gray30')
155
- authors: list[str | None] = specified_names if specified_names else [JEFFREY_EPSTEIN]
156
- log_files = epstein_files.imessage_logs_for(authors)
157
166
 
158
- for log_file in log_files:
167
+ for log_file in epstein_files.imessage_logs:
159
168
  console.print(Padding(log_file))
160
169
  console.line(2)
161
170
 
162
- epstein_files.print_imessage_summary()
171
+ print_centered(MessengerLog.summary_table(epstein_files.imessage_logs))
172
+
173
+
174
+ def write_json_metadata(epstein_files: EpsteinFiles) -> None:
175
+ json_str = epstein_files.json_metadata()
176
+
177
+ if args.build:
178
+ with open(JSON_METADATA_PATH, 'w') as f:
179
+ f.write(json_str)
180
+ log_file_write(JSON_METADATA_PATH)
181
+ else:
182
+ console.print_json(json_str, indent=4, sort_keys=True)
163
183
 
164
184
 
165
185
  def write_urls() -> None:
166
- """Write _URL style constant variables to a file bash scripts can load as env vars."""
186
+ """Write _URL style constant variables to URLS_ENV file so bash scripts can load as env vars."""
167
187
  url_vars = {k: v for k, v in vars(output_files).items() if k.endswith('URL') and not k.startswith('GH')}
168
188
 
169
189
  if not args.suppress_output:
@@ -190,8 +210,8 @@ def _verify_all_emails_were_printed(epstein_files: EpsteinFiles, already_printed
190
210
  logger.warning(f"Printed {len(already_printed_emails):,} emails of {len(email_ids_that_were_printed):,} unique file IDs.")
191
211
  missed_an_email = False
192
212
 
193
- for email in epstein_files.emails:
194
- if email.file_id not in email_ids_that_were_printed and not email.is_duplicate():
213
+ for email in epstein_files.non_duplicate_emails():
214
+ if email.file_id not in email_ids_that_were_printed:
195
215
  logger.warning(f"Failed to print {email.summary()}")
196
216
  missed_an_email = True
197
217
 
@@ -102,8 +102,13 @@ def build_highlighter(pattern: str) -> EpsteinHighlighter:
102
102
  return TempHighlighter()
103
103
 
104
104
 
105
- def build_table(title: str | None, **kwargs) -> Table:
106
- return Table(title=title, **{**DEFAULT_TABLE_KWARGS, **kwargs})
105
+ def build_table(title: str | None, cols: list[str | dict] | None = None, **kwargs) -> Table:
106
+ table = Table(title=title, **{**DEFAULT_TABLE_KWARGS, **kwargs})
107
+
108
+ if cols:
109
+ add_cols_to_table(table, cols)
110
+
111
+ return table
107
112
 
108
113
 
109
114
  def join_texts(txts: list[Text], join: str = ' ', encloser: str = '', encloser_style: str = 'wheat4') -> Text:
@@ -138,6 +143,13 @@ def parenthesize(msg: str | Text, style: str = '') -> Text:
138
143
  return Text('(', style=style).append(txt).append(')')
139
144
 
140
145
 
146
+ def print_all_files_page_link(epstein_files: 'EpsteinFiles') -> None:
147
+ markup_msg = link_markup(SITE_URLS[EMAIL], 'the other page', style='light_slate_grey bold')
148
+ txt = Text.from_markup(markup_msg).append(f' is uncurated and has all {len(epstein_files.other_files)}')
149
+ txt.append(f" unclassifiable files and {len(epstein_files.emails):,} emails")
150
+ print_centered(parenthesize(txt), style='dim')
151
+
152
+
141
153
  def print_author_header(msg: str, color: str | None, footer: str | None = None) -> None:
142
154
  txt = Text(msg, justify='center')
143
155
  color = color or 'white'
@@ -183,7 +195,20 @@ def print_header(epstein_files: 'EpsteinFiles') -> None:
183
195
 
184
196
  console.print(f"{not_optimized_msg}.\n", style='dim')
185
197
  print_page_title(width=TITLE_WIDTH)
186
- print_other_site_link()
198
+ site_type: SiteType = EMAIL if args.all_emails else TEXT_MESSAGE
199
+ print_starred_header(f"This is the Epstein {site_type.title()}s site", num_spaces=4, num_stars=14)
200
+ other_site_type: SiteType = TEXT_MESSAGE if site_type == EMAIL else EMAIL
201
+ other_site_msg = "another site with" + (' all of' if other_site_type == EMAIL else '')
202
+ other_site_msg += f" Epstein's {other_site_type}s also generated by this code"
203
+
204
+ markup_msg = link_markup(SITE_URLS[other_site_type], other_site_msg, OTHER_SITE_LINK_STYLE)
205
+ print_centered(parenthesize(Text.from_markup(markup_msg)), style='bold')
206
+ word_count_link = link_text_obj(WORD_COUNT_URL, 'most frequently used words in the emails and texts', AUX_SITE_LINK_STYLE)
207
+ print_centered(parenthesize(word_count_link))
208
+ metadata_link = link_text_obj(JSON_METADATA_URL, 'author attribution explanations', AUX_SITE_LINK_STYLE)
209
+ print_centered(parenthesize(metadata_link))
210
+ json_link = link_text_obj(WORD_COUNT_URL, "epstein's json files", AUX_SITE_LINK_STYLE)
211
+ print_centered(parenthesize(json_link))
187
212
  _print_external_links()
188
213
  console.line()
189
214
  _print_abbreviations_table()
@@ -247,31 +272,6 @@ def print_numbered_list_of_emailers(_list: list[str | None], epstein_files = Non
247
272
  console.line()
248
273
 
249
274
 
250
- def print_other_site_link(is_header: bool = True) -> None:
251
- """Print a link to the emails site if we're building text messages site and vice versa."""
252
- site_type: SiteType = EMAIL if args.all_emails else TEXT_MESSAGE
253
- link_style = OTHER_SITE_LINK_STYLE if is_header else 'light_slate_grey bold'
254
-
255
- if is_header:
256
- print_starred_header(f"This is the Epstein {site_type.title()}s site", num_spaces=4, num_stars=14)
257
-
258
- other_site_type: SiteType = TEXT_MESSAGE if site_type == EMAIL else EMAIL
259
- other_site_msg = "another site with" + (' all of' if other_site_type == EMAIL else '')
260
- other_site_msg += f" Epstein's {other_site_type}s also generated by this code"
261
- markup_msg = link_markup(SITE_URLS[other_site_type], other_site_msg, link_style)
262
- print_centered(parenthesize(Text.from_markup(markup_msg)), style='bold')
263
-
264
- if not is_header:
265
- return
266
-
267
- word_count_link = link_text_obj(WORD_COUNT_URL, 'most frequently used words in the emails and texts', AUX_SITE_LINK_STYLE)
268
- print_centered(parenthesize(word_count_link))
269
- metadata_link = link_text_obj(JSON_METADATA_URL, 'author attribution explanations', AUX_SITE_LINK_STYLE)
270
- print_centered(parenthesize(metadata_link))
271
- json_link = link_text_obj(WORD_COUNT_URL, "epstein's json files", AUX_SITE_LINK_STYLE)
272
- print_centered(parenthesize(json_link))
273
-
274
-
275
275
  def print_page_title(expand: bool = True, width: int | None = None) -> None:
276
276
  title_panel = Panel(Text(PAGE_TITLE, justify='center'), expand=expand, style=TITLE_STYLE, width=width)
277
277
  console.print(Align.center(vertically_pad(title_panel)))
@@ -294,7 +294,7 @@ def print_panel(msg: str, style: str = 'black on white', padding: tuple | None =
294
294
  def print_section_header(msg: str, style: str = SECTION_HEADER_STYLE, is_centered: bool = False) -> None:
295
295
  panel = Panel(Text(msg, justify='center'), expand=True, padding=(1, 1), style=style)
296
296
  panel = Align.center(panel) if is_centered else panel
297
- console.print(Padding(panel, (3, 0, 1, 0)))
297
+ console.print(Padding(panel, (3, 2, 1, 2)))
298
298
 
299
299
 
300
300
  def print_starred_header(msg: str, num_stars: int = 7, num_spaces: int = 2, style: str = TITLE_STYLE) -> None:
@@ -14,7 +14,7 @@ from epstein_files.util.constant.common_words import COMMON_WORDS_LIST, COMMON_W
14
14
  from epstein_files.util.constant.names import OTHER_NAMES
15
15
  from epstein_files.util.constant.output_files import WORD_COUNT_HTML_PATH
16
16
  from epstein_files.util.data import ALL_NAMES, flatten, sort_dict
17
- from epstein_files.util.env import args, specified_names
17
+ from epstein_files.util.env import args
18
18
  from epstein_files.util.logging import logger
19
19
  from epstein_files.util.rich import (console, highlighter, print_centered, print_color_key, print_page_title,
20
20
  print_panel, print_starred_header, write_html)
@@ -198,10 +198,10 @@ def write_word_counts_html() -> None:
198
198
  word_count = WordCount()
199
199
 
200
200
  # Remove dupes, junk mail, and fwded articles from emails
201
- emails = [e for e in epstein_files.emails if not (e.is_duplicate() or e.is_junk_mail() or e.is_fwded_article())]
201
+ emails = [e for e in epstein_files.non_duplicate_emails() if not (e.is_junk_mail() or e.is_fwded_article())]
202
202
 
203
203
  for email in emails:
204
- if specified_names and email.author not in specified_names:
204
+ if args.names and email.author not in args.names:
205
205
  continue
206
206
 
207
207
  logger.info(f"Counting words in {email}\n [SUBJECT] {email.subject()}")
@@ -218,14 +218,12 @@ def write_word_counts_html() -> None:
218
218
  for word in line.split():
219
219
  word_count.tally_word(word, SearchResult(email, [MatchedLine(line, i)]))
220
220
 
221
- # Add in iMessage conversation words
222
- imessage_logs = epstein_files.imessage_logs_for(specified_names) if specified_names else epstein_files.imessage_logs
223
-
224
- for imessage_log in imessage_logs:
221
+ # Add in iMessage conversations
222
+ for imessage_log in epstein_files.imessage_logs:
225
223
  logger.info(f"Counting words in {imessage_log}")
226
224
 
227
225
  for i, msg in enumerate(imessage_log.messages):
228
- if specified_names and msg.author not in specified_names:
226
+ if args.names and msg.author not in args.names:
229
227
  continue
230
228
  elif HTML_REGEX.search(line):
231
229
  continue
@@ -234,7 +232,7 @@ def write_word_counts_html() -> None:
234
232
  word_count.tally_word(word, SearchResult(imessage_log, [MatchedLine(msg.text, i)]))
235
233
 
236
234
  print_page_title(expand=False)
237
- print_starred_header(f"Most Common Words in {len(emails):,} Emails and {len(imessage_logs)} iMessage Logs")
235
+ print_starred_header(f"Most Common Words in {len(emails):,} Emails and {len(epstein_files.imessage_logs)} iMessage Logs")
238
236
  print_centered(f"(excluding {len(COMMON_WORDS_LIST)} particularly common words at bottom)", style='dim')
239
237
  console.line()
240
238
  print_color_key()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: epstein-files
3
- Version: 1.0.13
3
+ Version: 1.0.15
4
4
  Summary: Tools for working with the Jeffrey Epstein documents released in November 2025.
5
5
  Home-page: https://michelcrypt4d4mus.github.io/epstein_text_messages/
6
6
  License: GPL-3.0-or-later
@@ -43,11 +43,12 @@ Description-Content-Type: text/markdown
43
43
 
44
44
 
45
45
  ## Usage
46
-
47
46
  #### Installation
48
47
  1. Requires you have a local copy of the OCR text files from the House Oversight document release in a directory `/path/to/epstein/ocr_txt_files`. You can download those OCR text files from [the Congressional Google Drive folder](https://drive.google.com/drive/folders/1ldncvdqIf6miiskDp_EDuGSDAaI_fJx8) (make sure you grab both the `001/` and `002/` folders).
49
48
  1. Use `poetry install` for easiest time installing. `pip install epstein-files` should also work, though `pipx install epstein-files` is usually better.
50
49
 
50
+
51
+ #### Command Line Tools
51
52
  You need to set the `EPSTEIN_DOCS_DIR` environment variable with the path to the folder of files you just downloaded when running. You can either create a `.env` file modeled on [`.env.example`](./.env.example) (which will set it permanently) or you can run with:
52
53
 
53
54
  ```bash
@@ -63,7 +64,7 @@ epstein_generate
63
64
  # Search for a string:
64
65
  epstein_search Bannon
65
66
  # Or a regex:
66
- epstein_search '\bSteve\s*Bannon\b'
67
+ epstein_search '\bSteve\s*Bannon|Jeffrey\s*Epstein\b'
67
68
 
68
69
  # Show a file with color highlighting of keywords:
69
70
  epstein_show 030999
@@ -82,6 +83,12 @@ epstein_diff 030999 020442
82
83
  The first time you run anything it will take a few minutes to fix all the janky OCR text, attribute the redacted emails, etc. After that things will be quick.
83
84
  Run `epstein_generate --help` for command line option assistance.
84
85
 
86
+ **Optional:** There are a handful of emails that I extracted from the legal filings they were contained in. If you want to include these files in your local analysis you'll need to copy those files from the repo into your local document directory. Something like:
87
+
88
+ ```bash
89
+ cp ./emails_extracted_from_legal_filings/*.txt "$EPSTEIN_DOCS_DIR"
90
+ ```
91
+
85
92
 
86
93
  #### As A Library
87
94
  ```python
@@ -0,0 +1,33 @@
1
+ epstein_files/__init__.py,sha256=nOJ26LghS0sCdQ4qGwklVm18kbuFRn6Uu1-JDE8jwd4,5050
2
+ epstein_files/documents/communication.py,sha256=oqNsSDWe-N0jSmchIHxpihihzIWha-foFqMwKZlxyng,2057
3
+ epstein_files/documents/document.py,sha256=5GdM8grhaaefmXeV26XwYRZvMNqFETFnE7mFpVGGNik,17249
4
+ epstein_files/documents/email.py,sha256=h8V-20JAw2U_7mIWfnt3phvnykf-ioCdML8dAYoFVMc,40937
5
+ epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
+ epstein_files/documents/imessage/text_message.py,sha256=JPHlO-5Xgt5V5E9fDsgCEr3XOp7FyzlhIHmZhFNZcmg,2806
7
+ epstein_files/documents/json_file.py,sha256=WcZW5NNqA67rHTdopbOGtup00muNaLlvrNgKb-K4zO8,1504
8
+ epstein_files/documents/messenger_log.py,sha256=yFw5ScyP3KM8AoV9D36GUxLIT3pLsDdpi5F61Dw7fwQ,6510
9
+ epstein_files/documents/other_file.py,sha256=CCwOYsipYTWZj8pSTl0kgUy_LRu7Z5ZuWygQEYhilNA,9778
10
+ epstein_files/epstein_files.py,sha256=pBtrcEGZAMUDO_Xghxt-bd_RZp6JQlDj770EaM9oEZ4,17887
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=nk_kuOtIo_UTl4R4klUGJRfCRNDZZkqKkjbJx6XCOzQ,10471
14
+ epstein_files/util/constant/output_files.py,sha256=BkV4_gmdj46RfGy5SFYp6dgTty3FtlBth5YGmaGutls,1700
15
+ epstein_files/util/constant/strings.py,sha256=rOKmYrGIZFPQbhCgd8z7mUF0CbQQBO4ij8kXvGTDkoE,1857
16
+ epstein_files/util/constant/urls.py,sha256=Rpr9QQfjk2-8YGTXSQYg2oNA2ZxWrkedr5tL_53Z6ak,4896
17
+ epstein_files/util/constants.py,sha256=cIFDxq7-t6UE_qs2RtcyY2R3BAZmVV3glgTgKVkrG0c,112348
18
+ epstein_files/util/data.py,sha256=JccGFZGiCGm7XtwpQTocIjGYOr6hTUpEPwHhjyW9Xnc,3164
19
+ epstein_files/util/doc_cfg.py,sha256=aBIm0hyxf-aeMsb8ZUNiQFVsPFimjVUIkrVdDrg1iQU,9105
20
+ epstein_files/util/env.py,sha256=aSUC_TwdtKB8z6PCDaLeu3k5qZE3AgcsP9jU2p9eaP0,5640
21
+ epstein_files/util/file_helper.py,sha256=uJzNHihuAi2-XMNbUdjdovgppcIt-fVIIrXHXVShA6Q,2904
22
+ epstein_files/util/highlighted_group.py,sha256=ACDwLratRV9bemDyHY528JMFDf0ZDjm9HBfFJiqDgyY,36535
23
+ epstein_files/util/logging.py,sha256=fuREq06xUUI3DfCV2JE-8QM-sQKxpLDj0_AYFO6qR1M,1983
24
+ epstein_files/util/output.py,sha256=2YKpL2gGhS2SI5nC2yan0vNHvYMg1Ayq_ptzx9Gi9E4,9055
25
+ epstein_files/util/rich.py,sha256=bQPlOEZ6qTpVF4yPnwmlBk4K11zH5RJjwbWeBIOUUGE,15191
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=o_-HnfzHdPDPR8oA_dv6fjy1dbsHee8p_aoe62PEQHw,9213
29
+ epstein_files-1.0.15.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
+ epstein_files-1.0.15.dist-info/METADATA,sha256=yELMsoWwHhLiDjU7OFOYDAmifBak0h6xGLEu-3nwiHc,5867
31
+ epstein_files-1.0.15.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
+ epstein_files-1.0.15.dist-info/entry_points.txt,sha256=5qYgwAXpxegeAicD_rzda_trDRnUC51F5UVDpcZ7j6Q,240
33
+ epstein_files-1.0.15.dist-info/RECORD,,
@@ -1,33 +0,0 @@
1
- epstein_files/__init__.py,sha256=qVFB7sS6XSlZX-ByyDwdbGSn2h06aoX2Mx8WcgRb-To,4710
2
- epstein_files/documents/communication.py,sha256=i6eob0ucnI7AY1sGuJlzrtU_C0mxEtrPEQZE4yNeM9w,2049
3
- epstein_files/documents/document.py,sha256=VsXIJhY7HTUlQrnTzYv5VLtYugdb-c2ClrfInPb5l2M,17095
4
- epstein_files/documents/email.py,sha256=P2c8Z23qaiWj6qWf4QKTuLvqKDoUJmu7SyzJ6FQCmPA,40727
5
- epstein_files/documents/emails/email_header.py,sha256=wkPfSLbmzkAeQwvhf0bAeFDLPbQT-EeG0v8vNNLYktM,7502
6
- epstein_files/documents/imessage/text_message.py,sha256=4gFvTfulj_Su10lNQl6Hq_p9ArTrSmn5pfC22YRJXjI,2794
7
- epstein_files/documents/json_file.py,sha256=tIYTwA3FYkwVZSpXvFYyUoH9m2sGYCD1U0ttamH6r1o,1306
8
- epstein_files/documents/messenger_log.py,sha256=BW3J52a9XxNVoK7SxtfJGydSNPoeKGE0PkdkMpf9sJ0,6294
9
- epstein_files/documents/other_file.py,sha256=pnl_q1o7ur3eeqGPwsYL2qbM3Y8O9LX6j6LbWnoxAiE,9939
10
- epstein_files/epstein_files.py,sha256=sbgS7GlrlWo1kuH4YXUSvbYX_SApgrwhpx6_qdHmrBM,19119
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=ObLJCvit_C1cwLc-7Wcjh-C5oQrpww1HLk6DrEvnu8E,10368
14
- epstein_files/util/constant/output_files.py,sha256=BkV4_gmdj46RfGy5SFYp6dgTty3FtlBth5YGmaGutls,1700
15
- epstein_files/util/constant/strings.py,sha256=02DwbhAe8qBRq5HOUFx5FafXJ1P2-RJf9TCVu2b7UDQ,1932
16
- epstein_files/util/constant/urls.py,sha256=EKzpL1np3cdyYvUlgv1zl9IJU8Vrg8jXpAu6YpM0_Bk,5283
17
- epstein_files/util/constants.py,sha256=tSHrgzDOTx0KwGy4HI7ShIwaRMX1o7otW3CkKvRplZs,112121
18
- epstein_files/util/data.py,sha256=gOaETo4LvN3VgRvA1dB2_NRDL3wiL-xBICZ2jfD-knk,2997
19
- epstein_files/util/doc_cfg.py,sha256=irQljeGXlB9wbRbP05pWQZMS2-DbhdugfVGD8Q2UhSg,9006
20
- epstein_files/util/env.py,sha256=HnYcfHSNkwVJ_T75Woy43_OpDyxD0KHPj3GxcVx86N4,5751
21
- epstein_files/util/file_helper.py,sha256=tacTe1GcAnckPFvjMgxRRSLnFgr2aVIYsgfDR_C9uXk,2780
22
- epstein_files/util/highlighted_group.py,sha256=rKJsUQfPzQwMMu5--QWsxNFxW303RI8yq69sw4vi2RA,36720
23
- epstein_files/util/logging.py,sha256=fuREq06xUUI3DfCV2JE-8QM-sQKxpLDj0_AYFO6qR1M,1983
24
- epstein_files/util/output.py,sha256=XcflgSOlzUGj6FsFaK6j4Dljld8A0h_uVV7ERcI_EYw,8120
25
- epstein_files/util/rich.py,sha256=V8WDQPuCcubn46HW1cLZ6uT-CBAnBB17Hozsvv7Pd4g,14987
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=8qBTuq3d0Q-3fwiuECKWi2RfL-KUiZD8TciwvfL0D_o,9353
29
- epstein_files-1.0.13.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
- epstein_files-1.0.13.dist-info/METADATA,sha256=ZfGSbuEOmAhzDs_a6KiKjXfhLNRwcZoXklAK1KphX7I,5480
31
- epstein_files-1.0.13.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
32
- epstein_files-1.0.13.dist-info/entry_points.txt,sha256=5qYgwAXpxegeAicD_rzda_trDRnUC51F5UVDpcZ7j6Q,240
33
- epstein_files-1.0.13.dist-info/RECORD,,