tradedangerous 10.13.10__py3-none-any.whl → 10.14.3__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.

Potentially problematic release.


This version of tradedangerous might be problematic. Click here for more details.

tradedangerous/cache.py CHANGED
@@ -285,12 +285,12 @@ def getStationByNameIndex(cur):
285
285
  """ Build station index in STAR/Station notation """
286
286
  cur.execute("""
287
287
  SELECT station_id,
288
- UPPER(system.name) || '/' || UPPER(station.name)
288
+ system.name || '/' || station.name
289
289
  FROM System
290
290
  INNER JOIN Station
291
291
  USING (system_id)
292
292
  """)
293
- return { name: ID for (ID, name) in cur }
293
+ return { name.upper(): ID for (ID, name) in cur }
294
294
 
295
295
 
296
296
  def getItemByNameIndex(cur):
tradedangerous/gui.py CHANGED
@@ -47,6 +47,7 @@ from pathlib import Path
47
47
  from appJar import gui
48
48
  import appJar
49
49
 
50
+
50
51
  # from tkinter import *
51
52
  # import tkinter.font as font
52
53
  # import tkinter.scrolledtext as scrolledtext
@@ -0,0 +1,389 @@
1
+ import os
2
+ import sys
3
+ import time
4
+ from datetime import datetime, timedelta
5
+ from collections import namedtuple
6
+ from pathlib import Path
7
+
8
+ import requests
9
+ import simdjson
10
+ import sqlite3
11
+
12
+ from .. import plugins, cache, fs
13
+
14
+ SOURCE_URL = 'https://downloads.spansh.co.uk/galaxy_stations.json'
15
+
16
+ STATION_TYPE_MAP = {
17
+ 'Drake-Class Carrier': 24, # fleet carriers
18
+ 'Settlement': 25, # odyssey settlements
19
+ }
20
+
21
+ System = namedtuple('System', 'name,pos_x,pos_y,pos_z,modified')
22
+ Station = namedtuple('Station', 'name,distance,max_pad_size,market,black_market,shipyard,outfitting,rearm,refuel,repair,planetary,type,modified')
23
+ Commodity = namedtuple('Commodity', 'id,name,category,demand,supply,sell,buy,modified')
24
+
25
+
26
+ class Timing:
27
+
28
+ def __init__(self):
29
+ self.start_ts = None
30
+ self.end_ts = None
31
+
32
+ def __enter__(self):
33
+ self.start_ts = time.perf_counter()
34
+ self.end_ts = None
35
+ return self
36
+
37
+ def __exit__(self, *args):
38
+ self.end_ts = time.perf_counter()
39
+
40
+ @property
41
+ def elapsed(self):
42
+ if self.start_ts is None:
43
+ return None
44
+ return (self.end_ts or time.perf_counter()) - self.start_ts
45
+
46
+ @property
47
+ def is_finished(self):
48
+ return self.end_ts is not None
49
+
50
+
51
+ class ImportPlugin(plugins.ImportPluginBase):
52
+ """Plugin that downloads data from https://spansh.co.uk/dumps.
53
+ """
54
+
55
+ pluginOptions = {
56
+ 'url': f'URL to download galaxy data from (defaults to {SOURCE_URL})',
57
+ 'file': 'Local filename to import galaxy data from; use "-" to load from stdin',
58
+ 'listener': 'For use by TD-listener, prevents updating cache from generated prices file',
59
+ }
60
+
61
+ def __init__(self, *args, **kwargs):
62
+ super().__init__(*args, **kwargs)
63
+ self.url = self.getOption('url')
64
+ self.file = self.getOption('file')
65
+ self.listener = self.getOption('listener')
66
+ assert not (self.url and self.file), 'Provide either url or file, not both'
67
+ if self.file and (self.file != '-'):
68
+ self.file = (Path(self.tdenv.cwDir) / self.file).resolve()
69
+ self.known_space = self.load_known_space()
70
+ self.known_commodities = self.load_known_commodities()
71
+
72
+ def print(self, *args, **kwargs):
73
+ return self.tdenv.uprint(*args, **kwargs)
74
+
75
+ def run(self):
76
+ fs.ensurefolder(self.tdenv.tmpDir)
77
+ filePath = self.tdenv.tmpDir / Path("spansh.prices")
78
+ if self.tdenv.detail < 1:
79
+ self.print('This will take at least several minutes...')
80
+ self.print('You can increase verbosity (-v) to get a sense of progress')
81
+ with open(filePath, 'w') as f, Timing() as timing:
82
+ self.print(f'Writing prices to {filePath}')
83
+ f.write('# Generated from spansh galaxy data\n')
84
+ f.write(f'# Source: {self.file or self.url}\n')
85
+ f.write('#\n')
86
+ f.write((
87
+ '# {name:50s} {sell:>7s} {buy:>7s} '
88
+ '{demand:>11s} {supply:>11s} {ts}\n'
89
+ ).format(
90
+ name='Item Name',
91
+ sell='SellCr',
92
+ buy='BuyCr',
93
+ demand='Demand',
94
+ supply='Supply',
95
+ ts='Timestamp',
96
+ ))
97
+ system_count = 0
98
+ total_station_count = 0
99
+ total_commodity_count = 0
100
+ self.need_commit = False
101
+ seen_stations = set()
102
+ for system, stations in self.data_stream():
103
+ self.ensure_system(system)
104
+ station_count = 0
105
+ commodity_count = 0
106
+ for station, commodities in stations:
107
+ if (system.name.upper(), station.name.upper()) in seen_stations:
108
+ fq_station_name = f'@{system.name.upper()}/{station.name}'
109
+ if self.tdenv.detail >= 1:
110
+ self.print(f' | {fq_station_name:50s} | Skipping duplicate station record')
111
+ continue
112
+ seen_stations.add((system.name.upper(), station.name.upper()))
113
+ self.ensure_station(system, station)
114
+ f.write('\n')
115
+ f.write(f'@ {system.name.upper()}/{station.name}\n')
116
+ categories = self.categorise_commodities(commodities)
117
+ for category_name, category_commodities in categories.items():
118
+ f.write(f' + {category_name}\n')
119
+ for commodity in category_commodities:
120
+ commodity = self.ensure_commodity(station, commodity)
121
+ f.write((
122
+ ' {name:50s} {sell:7d} {buy:7d} '
123
+ '{demand:10d}? {supply:10d}? {modified}\n'
124
+ ).format(
125
+ name=commodity.name,
126
+ sell=commodity.sell,
127
+ buy=commodity.buy,
128
+ demand=commodity.demand,
129
+ supply=commodity.supply,
130
+ modified=commodity.modified,
131
+ ))
132
+ commodity_count += 1
133
+ station_count += 1
134
+ system_count += 1
135
+ total_station_count += station_count
136
+ total_commodity_count += commodity_count
137
+ if self.tdenv.detail >= 1:
138
+ self.print(
139
+ f'{system_count:6d} | {system.name.upper():50s} | '
140
+ f'{station_count:3d} st {commodity_count:6d} co'
141
+ )
142
+ if self.need_commit:
143
+ self.execute('COMMIT')
144
+ self.need_commit = False
145
+ self.print(
146
+ f'{timedelta(seconds=int(timing.elapsed))!s} Done '
147
+ f'{total_station_count} st {total_commodity_count} co'
148
+ )
149
+
150
+ if not self.listener:
151
+ with Timing() as timing:
152
+ self.print('Importing to cache...')
153
+ self.tdenv.mergeImport = True
154
+ cache.importDataFromFile(self.tdb, self.tdenv, filePath)
155
+ self.print(f'Cache import completed in {timedelta(seconds=int(timing.elapsed))!s}')
156
+ return False
157
+
158
+ def data_stream(self):
159
+ if self.file == '-':
160
+ self.print('Reading prices from stdin')
161
+ stream = sys.stdin
162
+ elif self.file:
163
+ self.print(f'Reading prices from local file: {self.file}')
164
+ stream = open(self.file, 'r', encoding='utf8')
165
+ else:
166
+ url = self.url or SOURCE_URL
167
+ self.print(f'Reading prices from remote URL: {url}')
168
+ req = requests.get(url, stream=True)
169
+ stream = req.iter_lines(decode_unicode=True)
170
+ return ingest_stream(stream)
171
+
172
+ def categorise_commodities(self, commodities):
173
+ categories = {}
174
+ for commodity in commodities:
175
+ categories.setdefault(commodity.category, []).append(commodity)
176
+ return categories
177
+
178
+ def execute(self, query, *params, **kwparams):
179
+ attempts = 5
180
+ cursor = self.tdb.getDB().cursor()
181
+ while True:
182
+ try:
183
+ return cursor.execute(query, params or kwparams)
184
+ except sqlite3.OperationalError as ex:
185
+ if not attempts:
186
+ raise
187
+ attempts -= 1
188
+ self.print(f'Retrying query: {ex!s}')
189
+ time.sleep(1)
190
+
191
+ def load_known_space(self):
192
+ cache = {}
193
+ result = self.execute(
194
+ '''
195
+ SELECT System.name, Station.name FROM System
196
+ LEFT JOIN Station USING (system_id)
197
+ '''
198
+ ).fetchall()
199
+ for system, station in result:
200
+ cache.setdefault(system.upper(), set())
201
+ if station is not None:
202
+ cache[system.upper()].add(station.upper())
203
+ return cache
204
+
205
+ def load_known_commodities(self):
206
+ return dict(self.execute('SELECT fdev_id, name FROM Item').fetchall())
207
+
208
+ def ensure_system(self, system):
209
+ if system.name.upper() in self.known_space:
210
+ return
211
+ self.execute(
212
+ '''
213
+ INSERT INTO System (name, pos_x, pos_y, pos_z, modified) VALUES (?, ?, ?, ?, ?)
214
+ ''',
215
+ system.name, system.pos_x, system.pos_y, system.pos_z, system.modified,
216
+ )
217
+ self.need_commit = True
218
+ if self.tdenv.detail >= 2:
219
+ self.print(f' | {system.name.upper():50s} | Added missing system')
220
+ self.known_space[system.name.upper()] = set()
221
+
222
+ def ensure_station(self, system, station):
223
+ if station.name.upper() in self.known_space.get(system.name.upper(), set()):
224
+ return
225
+ self.execute(
226
+ '''
227
+ INSERT INTO Station (
228
+ system_id,
229
+ name,
230
+ ls_from_star,
231
+ max_pad_size,
232
+ market,
233
+ blackmarket,
234
+ shipyard,
235
+ outfitting,
236
+ rearm,
237
+ refuel,
238
+ repair,
239
+ planetary,
240
+ modified,
241
+ type_id
242
+ )
243
+ VALUES (
244
+ (SELECT system_id FROM System WHERE upper(name) = ?),
245
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
246
+ )
247
+ ''',
248
+ system.name.upper(),
249
+ station.name,
250
+ station.distance,
251
+ station.max_pad_size,
252
+ self.bool_yn(station.market),
253
+ self.bool_yn(station.black_market),
254
+ self.bool_yn(station.shipyard),
255
+ self.bool_yn(station.outfitting),
256
+ self.bool_yn(station.rearm),
257
+ self.bool_yn(station.refuel),
258
+ self.bool_yn(station.repair),
259
+ self.bool_yn(station.planetary),
260
+ station.modified,
261
+ station.type,
262
+ )
263
+ self.need_commit = True
264
+ if self.tdenv.detail >= 2:
265
+ self.print(f' | {station.name:50s} | Added missing station')
266
+ self.known_space[system.name.upper()].add(station.name.upper())
267
+
268
+ def ensure_commodity(self, station, commodity):
269
+ if commodity.id in self.known_commodities:
270
+ if self.known_commodities[commodity.id] != commodity.name:
271
+ if self.tdenv.detail >= 3:
272
+ self.print(f' | - {station.name:45s} | Replace "{commodity.name}" with pre-existing "{self.known_commodities[commodity.id]}"')
273
+ return Commodity(
274
+ id=commodity.id,
275
+ name=self.known_commodities[commodity.id],
276
+ category=commodity.category,
277
+ demand=commodity.demand,
278
+ supply=commodity.supply,
279
+ sell=commodity.sell,
280
+ buy=commodity.buy,
281
+ modified=commodity.modified,
282
+ )
283
+ return commodity
284
+ self.execute(
285
+ '''
286
+ INSERT INTO Item (category_id, name, fdev_id)
287
+ VALUES ((SELECT category_id FROM Category WHERE upper(name) = ?), ?, ?)
288
+ ''',
289
+ commodity.category.upper(),
290
+ commodity.name,
291
+ commodity.id,
292
+ )
293
+ self.need_commit = True
294
+ if self.tdenv.detail >= 2:
295
+ self.print(f' | {commodity.name:50s} | Added missing commodity')
296
+ self.known_commodities[commodity.id] = commodity.name
297
+ return commodity
298
+
299
+ def bool_yn(self, value):
300
+ return '?' if value is None else ('Y' if value else 'N')
301
+
302
+
303
+ def ingest_stream(stream):
304
+ """Ingest a spansh-style galaxy dump, yielding system-level data."""
305
+ line = next(stream)
306
+ assert line.rstrip(' \n,') == '['
307
+ for line in stream:
308
+ line = line.rstrip().rstrip(',')
309
+ if line == ']':
310
+ break
311
+ system_data = simdjson.Parser().parse(line)
312
+ coords = system_data.get('coords', {})
313
+ yield (
314
+ System(
315
+ name=system_data.get('name', 'Unnamed'),
316
+ pos_x=coords.get('x', 999999),
317
+ pos_y=coords.get('y', 999999),
318
+ pos_z=coords.get('z', 999999),
319
+ modified=parse_ts(system_data.get('date')),
320
+ ),
321
+ ingest_stations(system_data),
322
+ )
323
+
324
+
325
+ def ingest_stations(system_data):
326
+ """Ingest system-level data, yielding station-level data."""
327
+ targets = [system_data, *system_data.get('bodies', ())]
328
+ is_planetary = False
329
+ for target in targets:
330
+ for station_data in target.get('stations', ()):
331
+ services = set(station_data.get('services', ()))
332
+ if 'Market' not in services:
333
+ continue
334
+ market = station_data.get('market', {})
335
+ if not market.get('commodities'):
336
+ continue
337
+ landing_pads = station_data.get('landingPads', {})
338
+ max_pad_size = '?'
339
+ if landing_pads.get('large'):
340
+ max_pad_size = 'L'
341
+ elif landing_pads.get('medium'):
342
+ max_pad_size = 'M'
343
+ elif landing_pads.get('small'):
344
+ max_pad_size = 'S'
345
+ yield (
346
+ Station(
347
+ name=station_data.get('name', 'Unnamed'),
348
+ distance=station_data.get('distanceToArrival', 999999),
349
+ max_pad_size=max_pad_size,
350
+ market=True,
351
+ black_market='Black Market' in services,
352
+ shipyard='Shipyard' in services,
353
+ outfitting='Outfitting' in services,
354
+ rearm='Restock' in services,
355
+ refuel='Refuel' in services,
356
+ repair='Repair' in services,
357
+ planetary=is_planetary,
358
+ type=STATION_TYPE_MAP.get(station_data.get('type'), 0),
359
+ modified=parse_ts(station_data.get('updateTime')),
360
+ ),
361
+ ingest_market(market),
362
+ )
363
+ # first target is system stations, everything else is planetary
364
+ is_planetary = True
365
+
366
+
367
+ def ingest_market(market):
368
+ """Ingest station-level market data, yielding commodities."""
369
+ for commodity in market['commodities']:
370
+ yield Commodity(
371
+ id=commodity.get('commodityId'),
372
+ name=commodity.get('name', 'Unnamed'),
373
+ category=commodity.get('category', 'Uncategorised'),
374
+ demand=commodity.get('demand', 0),
375
+ supply=commodity.get('supply', 0),
376
+ sell=commodity.get('sellPrice', 0),
377
+ buy=commodity.get('buyPrice', 0),
378
+ modified=parse_ts(market.get('updateTime'))
379
+ )
380
+
381
+
382
+ def parse_ts(ts):
383
+ if ts is None:
384
+ return None
385
+ if ts.endswith('+00'):
386
+ ts = ts[:-3]
387
+ if '.' not in ts:
388
+ ts += '.0'
389
+ return datetime.strptime(ts, '%Y-%m-%d %H:%M:%S.%f').replace(microsecond=0)
tradedangerous/version.py CHANGED
@@ -12,5 +12,5 @@
12
12
  """just keeper of current version"""
13
13
 
14
14
  # TODO: remember to update tests when version changes
15
- __version__ = '10.13.10'
15
+ __version__ = '10.14.3'
16
16
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tradedangerous
3
- Version: 10.13.10
3
+ Version: 10.14.3
4
4
  Summary: Trade-Dangerous is a set of powerful trading tools for Elite Dangerous, organized around one of the most powerful trade run optimizers available.
5
5
  Home-page: https://github.com/eyeonus/Trade-Dangerous
6
6
  Author: eyeonus
@@ -21,6 +21,7 @@ Description-Content-Type: text/markdown
21
21
  License-File: LICENSE
22
22
  Requires-Dist: requests
23
23
  Requires-Dist: appJar
24
+ Requires-Dist: pysimdjson
24
25
 
25
26
 
26
27
  ----------
@@ -1,5 +1,5 @@
1
1
  tradedangerous/__init__.py,sha256=5ZeypoZaM8hlh6c-yTkD8x5hZYP8q3Q8a3bVeicHr90,1122
2
- tradedangerous/cache.py,sha256=_kcGrEI1CMbMftJvGU3QpXIUPwEj_2-BcL-WHmGGHWA,32948
2
+ tradedangerous/cache.py,sha256=t9--q6etNH5vigvA_1VLf_XTdoC_116qkjnqswhshpg,32942
3
3
  tradedangerous/cli.py,sha256=ycGkzMszwpP9OrngFIyhQbYoZ2wzRhJMTDCW1YhLrNI,4727
4
4
  tradedangerous/corrections.py,sha256=QMs-7MKLw2imFgIHthnwcpqWT1yJTb3CrABJw9LaKLA,1441
5
5
  tradedangerous/csvexport.py,sha256=OcOKe_VIgafw6rCvG3k5tM11KwwoYXMNY5DSSfCC0mU,8705
@@ -7,7 +7,7 @@ tradedangerous/edscupdate.py,sha256=-aglmhmtCKYrUyYKO1SBs4xmEHafTL4CjVeAt8uproU,
7
7
  tradedangerous/edsmupdate.py,sha256=GesavwY7rI5tuoTTMrM8sjYSN50QaPsDqKR2rrVbRZk,14924
8
8
  tradedangerous/formatting.py,sha256=3uqO9zHOTdfgZdFfhhL32gK_jIpliYOPhJocY5C1cfU,6162
9
9
  tradedangerous/fs.py,sha256=zVh5dF9dnJB0WLPSGX1KlJ8Sgqff5my3wer7m_4ddwM,2530
10
- tradedangerous/gui.py,sha256=DvHUB-evcVSoJS1skTe7urx54ovD5jAi6rHPpVgh-xk,44100
10
+ tradedangerous/gui.py,sha256=gHGiFSmprQNNYWewRVqdV22XK1EIt9eODnpgVrL3imA,44101
11
11
  tradedangerous/jsonprices.py,sha256=AQ2YFMc18s-KdvXAGZnYDw2bNbfBksWnM-vXRS8IP70,7013
12
12
  tradedangerous/mapping.py,sha256=RNjZy5hpokFVFDw_KkOUELmT4fPJC1RZiN9D8ZeAu5o,4034
13
13
  tradedangerous/prices.py,sha256=AcETd8b-lKwuyyx6cTud2jyoQLPZaxMuGgQNI9N-SYU,7593
@@ -21,7 +21,7 @@ tradedangerous/tradeexcept.py,sha256=aZ-Y31MbkjF7lmAzBAbaMsPPE7FEEfuf4gaX2GvriDk
21
21
  tradedangerous/tradegui.py,sha256=JbGFnsWupgesk6hrcUgKSdD9NNDyo0U9gh6m3DccAwU,782
22
22
  tradedangerous/transfers.py,sha256=NmXXk2aF88YkAvYqc9Syt_aO6d2jJjC-OxoRFoOyQH4,9923
23
23
  tradedangerous/utils.py,sha256=PUPvAEqUyxYGqqQa0b_yfLAvq8YVUxK6HfdS-CxM-Lo,5186
24
- tradedangerous/version.py,sha256=XS35iBSFdbTM6DjV7JPdxmKUR629HgyX_cKgx8qIsaM,648
24
+ tradedangerous/version.py,sha256=VBIRuG9loKYCnGzK0E0bfus4x6vzyFHvezJnZoIiXl8,647
25
25
  tradedangerous/commands/TEMPLATE.py,sha256=7oXL124aqxGHwnb0h9yRylUiwc6M5QrRrGVrubwI1gg,2124
26
26
  tradedangerous/commands/__init__.py,sha256=6B0WuqkFBOll5Hj67yKDAnhmyr5ZAnHc6nzUNEUh384,9640
27
27
  tradedangerous/commands/buildcache_cmd.py,sha256=oJvP06fA8svnHrfrpWkHKR16cba8GIhHdMOyZqds18Y,2332
@@ -66,13 +66,14 @@ tradedangerous/plugins/eddblink_plug.py,sha256=n8AzLh2pJdHdar1SnqSSjCwWPl4f-OKQ8
66
66
  tradedangerous/plugins/edmc_batch_plug.py,sha256=3Ptr-SZqaZFR8ViIIrp9Ak7rvfU3zl11AZYBhIceN7s,4224
67
67
  tradedangerous/plugins/journal_plug.py,sha256=K1oIeI7E3mb04fvYLXyoAh7fOTyM9NBelibTI88MIDQ,23696
68
68
  tradedangerous/plugins/netlog_plug.py,sha256=Gw_HSZWpN17D--OIYEM3Vo8y9SvDOv9UwAUfY24kz28,13460
69
+ tradedangerous/plugins/spansh_plug.py,sha256=ngG0CFpXJYBcR4e_p5U6h4JJlLEpHem5eJ-8oBENP54,15024
69
70
  tradedangerous/templates/Added.csv,sha256=8o54civQCcS9y7_DBo0GX196XWRbbREQqKDYTKibsgQ,649
70
71
  tradedangerous/templates/DefaultShipIndex.json,sha256=m5cI3vkKiqRk1VKO1Z_8LZrG9nczV0PUMDfBSt4-1RM,94739
71
72
  tradedangerous/templates/RareItem.csv,sha256=F1RhRnTD82PiwrVUO-ai2ErGH2PTqNnQaDw5mcgljXs,10483
72
73
  tradedangerous/templates/TradeDangerous.sql,sha256=6sjEogGHy-9zYpjPo0Y2a5tElowmHFyJNwrimOUBfHk,8079
73
- tradedangerous-10.13.10.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
74
- tradedangerous-10.13.10.dist-info/METADATA,sha256=Aq7LfqX_C0zTErgC2jOcfVSem8ZJJhZ1vBW0q9ajo1M,4396
75
- tradedangerous-10.13.10.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92
76
- tradedangerous-10.13.10.dist-info/entry_points.txt,sha256=pSwa-q0ob443uiKux7xFKYQl8uen66iDTnjdrQhNLx8,92
77
- tradedangerous-10.13.10.dist-info/top_level.txt,sha256=bF29i-oEltmNICgElEKxNsg83oahJvxg3a7YrxZi9Rk,15
78
- tradedangerous-10.13.10.dist-info/RECORD,,
74
+ tradedangerous-10.14.3.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
75
+ tradedangerous-10.14.3.dist-info/METADATA,sha256=-Lda3u808UY_L8LOjux9wCHS01kw1JkQgV4QlxjetEE,4421
76
+ tradedangerous-10.14.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
77
+ tradedangerous-10.14.3.dist-info/entry_points.txt,sha256=pSwa-q0ob443uiKux7xFKYQl8uen66iDTnjdrQhNLx8,92
78
+ tradedangerous-10.14.3.dist-info/top_level.txt,sha256=bF29i-oEltmNICgElEKxNsg83oahJvxg3a7YrxZi9Rk,15
79
+ tradedangerous-10.14.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.38.4)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5