Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wiseplat
GitHub Repository: wiseplat/python-code
Path: blob/master/ invest-robot-contest_TinkoffBotTwitch-main/venv/lib/python3.8/site-packages/numpy/distutils/cpuinfo.py
7757 views
1
#!/usr/bin/env python3
2
"""
3
cpuinfo
4
5
Copyright 2002 Pearu Peterson all rights reserved,
6
Pearu Peterson <[email protected]>
7
Permission to use, modify, and distribute this software is given under the
8
terms of the NumPy (BSD style) license. See LICENSE.txt that came with
9
this distribution for specifics.
10
11
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
12
Pearu Peterson
13
14
"""
15
__all__ = ['cpu']
16
17
import os
18
import platform
19
import re
20
import sys
21
import types
22
import warnings
23
24
from subprocess import getstatusoutput
25
26
27
def getoutput(cmd, successful_status=(0,), stacklevel=1):
28
try:
29
status, output = getstatusoutput(cmd)
30
except OSError as e:
31
warnings.warn(str(e), UserWarning, stacklevel=stacklevel)
32
return False, ""
33
if os.WIFEXITED(status) and os.WEXITSTATUS(status) in successful_status:
34
return True, output
35
return False, output
36
37
def command_info(successful_status=(0,), stacklevel=1, **kw):
38
info = {}
39
for key in kw:
40
ok, output = getoutput(kw[key], successful_status=successful_status,
41
stacklevel=stacklevel+1)
42
if ok:
43
info[key] = output.strip()
44
return info
45
46
def command_by_line(cmd, successful_status=(0,), stacklevel=1):
47
ok, output = getoutput(cmd, successful_status=successful_status,
48
stacklevel=stacklevel+1)
49
if not ok:
50
return
51
for line in output.splitlines():
52
yield line.strip()
53
54
def key_value_from_command(cmd, sep, successful_status=(0,),
55
stacklevel=1):
56
d = {}
57
for line in command_by_line(cmd, successful_status=successful_status,
58
stacklevel=stacklevel+1):
59
l = [s.strip() for s in line.split(sep, 1)]
60
if len(l) == 2:
61
d[l[0]] = l[1]
62
return d
63
64
class CPUInfoBase:
65
"""Holds CPU information and provides methods for requiring
66
the availability of various CPU features.
67
"""
68
69
def _try_call(self, func):
70
try:
71
return func()
72
except Exception:
73
pass
74
75
def __getattr__(self, name):
76
if not name.startswith('_'):
77
if hasattr(self, '_'+name):
78
attr = getattr(self, '_'+name)
79
if isinstance(attr, types.MethodType):
80
return lambda func=self._try_call,attr=attr : func(attr)
81
else:
82
return lambda : None
83
raise AttributeError(name)
84
85
def _getNCPUs(self):
86
return 1
87
88
def __get_nbits(self):
89
abits = platform.architecture()[0]
90
nbits = re.compile(r'(\d+)bit').search(abits).group(1)
91
return nbits
92
93
def _is_32bit(self):
94
return self.__get_nbits() == '32'
95
96
def _is_64bit(self):
97
return self.__get_nbits() == '64'
98
99
class LinuxCPUInfo(CPUInfoBase):
100
101
info = None
102
103
def __init__(self):
104
if self.info is not None:
105
return
106
info = [ {} ]
107
ok, output = getoutput('uname -m')
108
if ok:
109
info[0]['uname_m'] = output.strip()
110
try:
111
fo = open('/proc/cpuinfo')
112
except OSError as e:
113
warnings.warn(str(e), UserWarning, stacklevel=2)
114
else:
115
for line in fo:
116
name_value = [s.strip() for s in line.split(':', 1)]
117
if len(name_value) != 2:
118
continue
119
name, value = name_value
120
if not info or name in info[-1]: # next processor
121
info.append({})
122
info[-1][name] = value
123
fo.close()
124
self.__class__.info = info
125
126
def _not_impl(self): pass
127
128
# Athlon
129
130
def _is_AMD(self):
131
return self.info[0]['vendor_id']=='AuthenticAMD'
132
133
def _is_AthlonK6_2(self):
134
return self._is_AMD() and self.info[0]['model'] == '2'
135
136
def _is_AthlonK6_3(self):
137
return self._is_AMD() and self.info[0]['model'] == '3'
138
139
def _is_AthlonK6(self):
140
return re.match(r'.*?AMD-K6', self.info[0]['model name']) is not None
141
142
def _is_AthlonK7(self):
143
return re.match(r'.*?AMD-K7', self.info[0]['model name']) is not None
144
145
def _is_AthlonMP(self):
146
return re.match(r'.*?Athlon\(tm\) MP\b',
147
self.info[0]['model name']) is not None
148
149
def _is_AMD64(self):
150
return self.is_AMD() and self.info[0]['family'] == '15'
151
152
def _is_Athlon64(self):
153
return re.match(r'.*?Athlon\(tm\) 64\b',
154
self.info[0]['model name']) is not None
155
156
def _is_AthlonHX(self):
157
return re.match(r'.*?Athlon HX\b',
158
self.info[0]['model name']) is not None
159
160
def _is_Opteron(self):
161
return re.match(r'.*?Opteron\b',
162
self.info[0]['model name']) is not None
163
164
def _is_Hammer(self):
165
return re.match(r'.*?Hammer\b',
166
self.info[0]['model name']) is not None
167
168
# Alpha
169
170
def _is_Alpha(self):
171
return self.info[0]['cpu']=='Alpha'
172
173
def _is_EV4(self):
174
return self.is_Alpha() and self.info[0]['cpu model'] == 'EV4'
175
176
def _is_EV5(self):
177
return self.is_Alpha() and self.info[0]['cpu model'] == 'EV5'
178
179
def _is_EV56(self):
180
return self.is_Alpha() and self.info[0]['cpu model'] == 'EV56'
181
182
def _is_PCA56(self):
183
return self.is_Alpha() and self.info[0]['cpu model'] == 'PCA56'
184
185
# Intel
186
187
#XXX
188
_is_i386 = _not_impl
189
190
def _is_Intel(self):
191
return self.info[0]['vendor_id']=='GenuineIntel'
192
193
def _is_i486(self):
194
return self.info[0]['cpu']=='i486'
195
196
def _is_i586(self):
197
return self.is_Intel() and self.info[0]['cpu family'] == '5'
198
199
def _is_i686(self):
200
return self.is_Intel() and self.info[0]['cpu family'] == '6'
201
202
def _is_Celeron(self):
203
return re.match(r'.*?Celeron',
204
self.info[0]['model name']) is not None
205
206
def _is_Pentium(self):
207
return re.match(r'.*?Pentium',
208
self.info[0]['model name']) is not None
209
210
def _is_PentiumII(self):
211
return re.match(r'.*?Pentium.*?II\b',
212
self.info[0]['model name']) is not None
213
214
def _is_PentiumPro(self):
215
return re.match(r'.*?PentiumPro\b',
216
self.info[0]['model name']) is not None
217
218
def _is_PentiumMMX(self):
219
return re.match(r'.*?Pentium.*?MMX\b',
220
self.info[0]['model name']) is not None
221
222
def _is_PentiumIII(self):
223
return re.match(r'.*?Pentium.*?III\b',
224
self.info[0]['model name']) is not None
225
226
def _is_PentiumIV(self):
227
return re.match(r'.*?Pentium.*?(IV|4)\b',
228
self.info[0]['model name']) is not None
229
230
def _is_PentiumM(self):
231
return re.match(r'.*?Pentium.*?M\b',
232
self.info[0]['model name']) is not None
233
234
def _is_Prescott(self):
235
return self.is_PentiumIV() and self.has_sse3()
236
237
def _is_Nocona(self):
238
return (self.is_Intel()
239
and (self.info[0]['cpu family'] == '6'
240
or self.info[0]['cpu family'] == '15')
241
and (self.has_sse3() and not self.has_ssse3())
242
and re.match(r'.*?\blm\b', self.info[0]['flags']) is not None)
243
244
def _is_Core2(self):
245
return (self.is_64bit() and self.is_Intel() and
246
re.match(r'.*?Core\(TM\)2\b',
247
self.info[0]['model name']) is not None)
248
249
def _is_Itanium(self):
250
return re.match(r'.*?Itanium\b',
251
self.info[0]['family']) is not None
252
253
def _is_XEON(self):
254
return re.match(r'.*?XEON\b',
255
self.info[0]['model name'], re.IGNORECASE) is not None
256
257
_is_Xeon = _is_XEON
258
259
# Varia
260
261
def _is_singleCPU(self):
262
return len(self.info) == 1
263
264
def _getNCPUs(self):
265
return len(self.info)
266
267
def _has_fdiv_bug(self):
268
return self.info[0]['fdiv_bug']=='yes'
269
270
def _has_f00f_bug(self):
271
return self.info[0]['f00f_bug']=='yes'
272
273
def _has_mmx(self):
274
return re.match(r'.*?\bmmx\b', self.info[0]['flags']) is not None
275
276
def _has_sse(self):
277
return re.match(r'.*?\bsse\b', self.info[0]['flags']) is not None
278
279
def _has_sse2(self):
280
return re.match(r'.*?\bsse2\b', self.info[0]['flags']) is not None
281
282
def _has_sse3(self):
283
return re.match(r'.*?\bpni\b', self.info[0]['flags']) is not None
284
285
def _has_ssse3(self):
286
return re.match(r'.*?\bssse3\b', self.info[0]['flags']) is not None
287
288
def _has_3dnow(self):
289
return re.match(r'.*?\b3dnow\b', self.info[0]['flags']) is not None
290
291
def _has_3dnowext(self):
292
return re.match(r'.*?\b3dnowext\b', self.info[0]['flags']) is not None
293
294
class IRIXCPUInfo(CPUInfoBase):
295
info = None
296
297
def __init__(self):
298
if self.info is not None:
299
return
300
info = key_value_from_command('sysconf', sep=' ',
301
successful_status=(0, 1))
302
self.__class__.info = info
303
304
def _not_impl(self): pass
305
306
def _is_singleCPU(self):
307
return self.info.get('NUM_PROCESSORS') == '1'
308
309
def _getNCPUs(self):
310
return int(self.info.get('NUM_PROCESSORS', 1))
311
312
def __cputype(self, n):
313
return self.info.get('PROCESSORS').split()[0].lower() == 'r%s' % (n)
314
def _is_r2000(self): return self.__cputype(2000)
315
def _is_r3000(self): return self.__cputype(3000)
316
def _is_r3900(self): return self.__cputype(3900)
317
def _is_r4000(self): return self.__cputype(4000)
318
def _is_r4100(self): return self.__cputype(4100)
319
def _is_r4300(self): return self.__cputype(4300)
320
def _is_r4400(self): return self.__cputype(4400)
321
def _is_r4600(self): return self.__cputype(4600)
322
def _is_r4650(self): return self.__cputype(4650)
323
def _is_r5000(self): return self.__cputype(5000)
324
def _is_r6000(self): return self.__cputype(6000)
325
def _is_r8000(self): return self.__cputype(8000)
326
def _is_r10000(self): return self.__cputype(10000)
327
def _is_r12000(self): return self.__cputype(12000)
328
def _is_rorion(self): return self.__cputype('orion')
329
330
def get_ip(self):
331
try: return self.info.get('MACHINE')
332
except Exception: pass
333
def __machine(self, n):
334
return self.info.get('MACHINE').lower() == 'ip%s' % (n)
335
def _is_IP19(self): return self.__machine(19)
336
def _is_IP20(self): return self.__machine(20)
337
def _is_IP21(self): return self.__machine(21)
338
def _is_IP22(self): return self.__machine(22)
339
def _is_IP22_4k(self): return self.__machine(22) and self._is_r4000()
340
def _is_IP22_5k(self): return self.__machine(22) and self._is_r5000()
341
def _is_IP24(self): return self.__machine(24)
342
def _is_IP25(self): return self.__machine(25)
343
def _is_IP26(self): return self.__machine(26)
344
def _is_IP27(self): return self.__machine(27)
345
def _is_IP28(self): return self.__machine(28)
346
def _is_IP30(self): return self.__machine(30)
347
def _is_IP32(self): return self.__machine(32)
348
def _is_IP32_5k(self): return self.__machine(32) and self._is_r5000()
349
def _is_IP32_10k(self): return self.__machine(32) and self._is_r10000()
350
351
352
class DarwinCPUInfo(CPUInfoBase):
353
info = None
354
355
def __init__(self):
356
if self.info is not None:
357
return
358
info = command_info(arch='arch',
359
machine='machine')
360
info['sysctl_hw'] = key_value_from_command('sysctl hw', sep='=')
361
self.__class__.info = info
362
363
def _not_impl(self): pass
364
365
def _getNCPUs(self):
366
return int(self.info['sysctl_hw'].get('hw.ncpu', 1))
367
368
def _is_Power_Macintosh(self):
369
return self.info['sysctl_hw']['hw.machine']=='Power Macintosh'
370
371
def _is_i386(self):
372
return self.info['arch']=='i386'
373
def _is_ppc(self):
374
return self.info['arch']=='ppc'
375
376
def __machine(self, n):
377
return self.info['machine'] == 'ppc%s'%n
378
def _is_ppc601(self): return self.__machine(601)
379
def _is_ppc602(self): return self.__machine(602)
380
def _is_ppc603(self): return self.__machine(603)
381
def _is_ppc603e(self): return self.__machine('603e')
382
def _is_ppc604(self): return self.__machine(604)
383
def _is_ppc604e(self): return self.__machine('604e')
384
def _is_ppc620(self): return self.__machine(620)
385
def _is_ppc630(self): return self.__machine(630)
386
def _is_ppc740(self): return self.__machine(740)
387
def _is_ppc7400(self): return self.__machine(7400)
388
def _is_ppc7450(self): return self.__machine(7450)
389
def _is_ppc750(self): return self.__machine(750)
390
def _is_ppc403(self): return self.__machine(403)
391
def _is_ppc505(self): return self.__machine(505)
392
def _is_ppc801(self): return self.__machine(801)
393
def _is_ppc821(self): return self.__machine(821)
394
def _is_ppc823(self): return self.__machine(823)
395
def _is_ppc860(self): return self.__machine(860)
396
397
398
class SunOSCPUInfo(CPUInfoBase):
399
400
info = None
401
402
def __init__(self):
403
if self.info is not None:
404
return
405
info = command_info(arch='arch',
406
mach='mach',
407
uname_i='uname_i',
408
isainfo_b='isainfo -b',
409
isainfo_n='isainfo -n',
410
)
411
info['uname_X'] = key_value_from_command('uname -X', sep='=')
412
for line in command_by_line('psrinfo -v 0'):
413
m = re.match(r'\s*The (?P<p>[\w\d]+) processor operates at', line)
414
if m:
415
info['processor'] = m.group('p')
416
break
417
self.__class__.info = info
418
419
def _not_impl(self): pass
420
421
def _is_i386(self):
422
return self.info['isainfo_n']=='i386'
423
def _is_sparc(self):
424
return self.info['isainfo_n']=='sparc'
425
def _is_sparcv9(self):
426
return self.info['isainfo_n']=='sparcv9'
427
428
def _getNCPUs(self):
429
return int(self.info['uname_X'].get('NumCPU', 1))
430
431
def _is_sun4(self):
432
return self.info['arch']=='sun4'
433
434
def _is_SUNW(self):
435
return re.match(r'SUNW', self.info['uname_i']) is not None
436
def _is_sparcstation5(self):
437
return re.match(r'.*SPARCstation-5', self.info['uname_i']) is not None
438
def _is_ultra1(self):
439
return re.match(r'.*Ultra-1', self.info['uname_i']) is not None
440
def _is_ultra250(self):
441
return re.match(r'.*Ultra-250', self.info['uname_i']) is not None
442
def _is_ultra2(self):
443
return re.match(r'.*Ultra-2', self.info['uname_i']) is not None
444
def _is_ultra30(self):
445
return re.match(r'.*Ultra-30', self.info['uname_i']) is not None
446
def _is_ultra4(self):
447
return re.match(r'.*Ultra-4', self.info['uname_i']) is not None
448
def _is_ultra5_10(self):
449
return re.match(r'.*Ultra-5_10', self.info['uname_i']) is not None
450
def _is_ultra5(self):
451
return re.match(r'.*Ultra-5', self.info['uname_i']) is not None
452
def _is_ultra60(self):
453
return re.match(r'.*Ultra-60', self.info['uname_i']) is not None
454
def _is_ultra80(self):
455
return re.match(r'.*Ultra-80', self.info['uname_i']) is not None
456
def _is_ultraenterprice(self):
457
return re.match(r'.*Ultra-Enterprise', self.info['uname_i']) is not None
458
def _is_ultraenterprice10k(self):
459
return re.match(r'.*Ultra-Enterprise-10000', self.info['uname_i']) is not None
460
def _is_sunfire(self):
461
return re.match(r'.*Sun-Fire', self.info['uname_i']) is not None
462
def _is_ultra(self):
463
return re.match(r'.*Ultra', self.info['uname_i']) is not None
464
465
def _is_cpusparcv7(self):
466
return self.info['processor']=='sparcv7'
467
def _is_cpusparcv8(self):
468
return self.info['processor']=='sparcv8'
469
def _is_cpusparcv9(self):
470
return self.info['processor']=='sparcv9'
471
472
class Win32CPUInfo(CPUInfoBase):
473
474
info = None
475
pkey = r"HARDWARE\DESCRIPTION\System\CentralProcessor"
476
# XXX: what does the value of
477
# HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0
478
# mean?
479
480
def __init__(self):
481
if self.info is not None:
482
return
483
info = []
484
try:
485
#XXX: Bad style to use so long `try:...except:...`. Fix it!
486
import winreg
487
488
prgx = re.compile(r"family\s+(?P<FML>\d+)\s+model\s+(?P<MDL>\d+)"
489
r"\s+stepping\s+(?P<STP>\d+)", re.IGNORECASE)
490
chnd=winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, self.pkey)
491
pnum=0
492
while True:
493
try:
494
proc=winreg.EnumKey(chnd, pnum)
495
except winreg.error:
496
break
497
else:
498
pnum+=1
499
info.append({"Processor":proc})
500
phnd=winreg.OpenKey(chnd, proc)
501
pidx=0
502
while True:
503
try:
504
name, value, vtpe=winreg.EnumValue(phnd, pidx)
505
except winreg.error:
506
break
507
else:
508
pidx=pidx+1
509
info[-1][name]=value
510
if name=="Identifier":
511
srch=prgx.search(value)
512
if srch:
513
info[-1]["Family"]=int(srch.group("FML"))
514
info[-1]["Model"]=int(srch.group("MDL"))
515
info[-1]["Stepping"]=int(srch.group("STP"))
516
except Exception as e:
517
print(e, '(ignoring)')
518
self.__class__.info = info
519
520
def _not_impl(self): pass
521
522
# Athlon
523
524
def _is_AMD(self):
525
return self.info[0]['VendorIdentifier']=='AuthenticAMD'
526
527
def _is_Am486(self):
528
return self.is_AMD() and self.info[0]['Family']==4
529
530
def _is_Am5x86(self):
531
return self.is_AMD() and self.info[0]['Family']==4
532
533
def _is_AMDK5(self):
534
return self.is_AMD() and self.info[0]['Family']==5 \
535
and self.info[0]['Model'] in [0, 1, 2, 3]
536
537
def _is_AMDK6(self):
538
return self.is_AMD() and self.info[0]['Family']==5 \
539
and self.info[0]['Model'] in [6, 7]
540
541
def _is_AMDK6_2(self):
542
return self.is_AMD() and self.info[0]['Family']==5 \
543
and self.info[0]['Model']==8
544
545
def _is_AMDK6_3(self):
546
return self.is_AMD() and self.info[0]['Family']==5 \
547
and self.info[0]['Model']==9
548
549
def _is_AMDK7(self):
550
return self.is_AMD() and self.info[0]['Family'] == 6
551
552
# To reliably distinguish between the different types of AMD64 chips
553
# (Athlon64, Operton, Athlon64 X2, Semperon, Turion 64, etc.) would
554
# require looking at the 'brand' from cpuid
555
556
def _is_AMD64(self):
557
return self.is_AMD() and self.info[0]['Family'] == 15
558
559
# Intel
560
561
def _is_Intel(self):
562
return self.info[0]['VendorIdentifier']=='GenuineIntel'
563
564
def _is_i386(self):
565
return self.info[0]['Family']==3
566
567
def _is_i486(self):
568
return self.info[0]['Family']==4
569
570
def _is_i586(self):
571
return self.is_Intel() and self.info[0]['Family']==5
572
573
def _is_i686(self):
574
return self.is_Intel() and self.info[0]['Family']==6
575
576
def _is_Pentium(self):
577
return self.is_Intel() and self.info[0]['Family']==5
578
579
def _is_PentiumMMX(self):
580
return self.is_Intel() and self.info[0]['Family']==5 \
581
and self.info[0]['Model']==4
582
583
def _is_PentiumPro(self):
584
return self.is_Intel() and self.info[0]['Family']==6 \
585
and self.info[0]['Model']==1
586
587
def _is_PentiumII(self):
588
return self.is_Intel() and self.info[0]['Family']==6 \
589
and self.info[0]['Model'] in [3, 5, 6]
590
591
def _is_PentiumIII(self):
592
return self.is_Intel() and self.info[0]['Family']==6 \
593
and self.info[0]['Model'] in [7, 8, 9, 10, 11]
594
595
def _is_PentiumIV(self):
596
return self.is_Intel() and self.info[0]['Family']==15
597
598
def _is_PentiumM(self):
599
return self.is_Intel() and self.info[0]['Family'] == 6 \
600
and self.info[0]['Model'] in [9, 13, 14]
601
602
def _is_Core2(self):
603
return self.is_Intel() and self.info[0]['Family'] == 6 \
604
and self.info[0]['Model'] in [15, 16, 17]
605
606
# Varia
607
608
def _is_singleCPU(self):
609
return len(self.info) == 1
610
611
def _getNCPUs(self):
612
return len(self.info)
613
614
def _has_mmx(self):
615
if self.is_Intel():
616
return (self.info[0]['Family']==5 and self.info[0]['Model']==4) \
617
or (self.info[0]['Family'] in [6, 15])
618
elif self.is_AMD():
619
return self.info[0]['Family'] in [5, 6, 15]
620
else:
621
return False
622
623
def _has_sse(self):
624
if self.is_Intel():
625
return ((self.info[0]['Family']==6 and
626
self.info[0]['Model'] in [7, 8, 9, 10, 11])
627
or self.info[0]['Family']==15)
628
elif self.is_AMD():
629
return ((self.info[0]['Family']==6 and
630
self.info[0]['Model'] in [6, 7, 8, 10])
631
or self.info[0]['Family']==15)
632
else:
633
return False
634
635
def _has_sse2(self):
636
if self.is_Intel():
637
return self.is_Pentium4() or self.is_PentiumM() \
638
or self.is_Core2()
639
elif self.is_AMD():
640
return self.is_AMD64()
641
else:
642
return False
643
644
def _has_3dnow(self):
645
return self.is_AMD() and self.info[0]['Family'] in [5, 6, 15]
646
647
def _has_3dnowext(self):
648
return self.is_AMD() and self.info[0]['Family'] in [6, 15]
649
650
if sys.platform.startswith('linux'): # variations: linux2,linux-i386 (any others?)
651
cpuinfo = LinuxCPUInfo
652
elif sys.platform.startswith('irix'):
653
cpuinfo = IRIXCPUInfo
654
elif sys.platform == 'darwin':
655
cpuinfo = DarwinCPUInfo
656
elif sys.platform.startswith('sunos'):
657
cpuinfo = SunOSCPUInfo
658
elif sys.platform.startswith('win32'):
659
cpuinfo = Win32CPUInfo
660
elif sys.platform.startswith('cygwin'):
661
cpuinfo = LinuxCPUInfo
662
#XXX: other OS's. Eg. use _winreg on Win32. Or os.uname on unices.
663
else:
664
cpuinfo = CPUInfoBase
665
666
cpu = cpuinfo()
667
668
#if __name__ == "__main__":
669
#
670
# cpu.is_blaa()
671
# cpu.is_Intel()
672
# cpu.is_Alpha()
673
#
674
# print('CPU information:'),
675
# for name in dir(cpuinfo):
676
# if name[0]=='_' and name[1]!='_':
677
# r = getattr(cpu,name[1:])()
678
# if r:
679
# if r!=1:
680
# print('%s=%s' %(name[1:],r))
681
# else:
682
# print(name[1:]),
683
# print()
684
685