1
2 """Medication handling code.
3
4 license: GPL
5 """
6
7
8
9 __version__ = "$Revision: 1.21 $"
10 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
11
12 import sys, logging, csv, codecs, os, re as regex
13
14
15 if __name__ == '__main__':
16 sys.path.insert(0, '../../')
17 from Gnumed.pycommon import gmBusinessDBObject, gmPG2, gmShellAPI, gmTools, gmDateTime
18 from Gnumed.business import gmATC
19
20
21 _log = logging.getLogger('gm.meds')
22 _log.info(__version__)
23
24
25
26
27
28
29
30
32 """Iterator over a Gelbe Liste/MMI v8.2 CSV file."""
33
34 version = u'Gelbe Liste/MMI v8.2 CSV file interface'
35 default_transfer_file_windows = r"c:\rezept.txt"
36
37 default_encoding = 'cp1250'
38 csv_fieldnames = [
39 u'name',
40 u'packungsgroesse',
41 u'darreichungsform',
42 u'packungstyp',
43 u'festbetrag',
44 u'avp',
45 u'hersteller',
46 u'rezepttext',
47 u'pzn',
48 u'status_vertrieb',
49 u'status_rezeptpflicht',
50 u'status_fachinfo',
51 u'btm',
52 u'atc',
53 u'anzahl_packungen',
54 u'zuzahlung_pro_packung',
55 u'einheit',
56 u'schedule_morgens',
57 u'schedule_mittags',
58 u'schedule_abends',
59 u'schedule_nachts',
60 u'status_dauermedikament',
61 u'status_hausliste',
62 u'status_negativliste',
63 u'ik_nummer',
64 u'status_rabattvertrag',
65 u'wirkstoffe',
66 u'wirkstoffmenge',
67 u'wirkstoffeinheit',
68 u'wirkstoffmenge_bezug',
69 u'wirkstoffmenge_bezugseinheit',
70 u'status_import',
71 u'status_lifestyle',
72 u'status_ausnahmeliste',
73 u'packungsmenge',
74 u'apothekenpflicht',
75 u'status_billigere_packung',
76 u'rezepttyp',
77 u'besonderes_arzneimittel',
78 u't-rezept-pflicht',
79 u'erstattbares_medizinprodukt',
80 u'hilfsmittel',
81 u'hzv_rabattkennung',
82 u'hzv_preis'
83 ]
84 boolean_fields = [
85 u'status_rezeptpflicht',
86 u'status_fachinfo',
87 u'btm',
88 u'status_dauermedikament',
89 u'status_hausliste',
90 u'status_negativliste',
91 u'status_rabattvertrag',
92 u'status_import',
93 u'status_lifestyle',
94 u'status_ausnahmeliste',
95 u'apothekenpflicht',
96 u'status_billigere_packung',
97 u'besonderes_arzneimittel',
98 u't-rezept-pflicht',
99 u'erstattbares_medizinprodukt',
100 u'hilfsmittel'
101 ]
102
122
125
127 line = self.csv_lines.next()
128
129 for field in cGelbeListeCSVFile.boolean_fields:
130 line[field] = (line[field].strip() == u'T')
131
132
133 if line['wirkstoffe'].strip() == u'':
134 line['wirkstoffe'] = []
135 else:
136 line['wirkstoffe'] = [ wirkstoff.strip() for wirkstoff in line['wirkstoffe'].split(u';') ]
137
138 return line
139
140 - def close(self, truncate=True):
141 try: self.csv_file.close()
142 except: pass
143
144 if truncate:
145 try: os.open(self.filename, 'wb').close
146 except: pass
147
149
150
152 raise NotImplementedError
153
155 raise NotImplementedError
156
158 raise NotImplementedError
159
161 raise NotImplementedError
162
164 raise NotImplementedError
165
167 raise NotImplementedError
168
170 raise NotImplementedError
171
173 """Support v8.2 CSV file interface only."""
174
175 version = u'Gelbe Liste/MMI v8.2 interface'
176 default_encoding = 'cp1250'
177 bdt_line_template = u'%03d6210#%s\r\n'
178 bdt_line_base_length = 8
179
181 _log.info(u'%s (native Windows)', cGelbeListeWindowsInterface.version)
182
183 self.path_to_binary = r'C:\Programme\MMI PHARMINDEX\glwin.exe'
184 self.args = r'-KEEPBACKGROUND -PRESCRIPTIONFILE %s -CLOSETOTRAY'
185
186 paths = gmTools.gmPaths()
187
188 self.default_csv_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'rezept.txt')
189 self.default_csv_filename_arg = os.path.join(paths.home_dir, '.gnumed', 'tmp')
190 self.interactions_filename = os.path.join(paths.home_dir, '.gnumed', 'tmp', 'gm2mmi.bdt')
191 self.data_date_filename = r'C:\Programme\MMI PHARMINDEX\datadate.txt'
192
193 self.data_date = None
194 self.online_update_date = None
195
196
197
199
200 open(self.data_date_filename, 'wb').close()
201
202 cmd = u'%s -DATADATE' % self.path_to_binary
203 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True):
204 _log.error('problem querying the MMI drug database for version information')
205 return {
206 'data': u'?',
207 'online_update': u'?'
208 }
209
210 version_file = open(self.data_date_filename, 'rU')
211 versions = {
212 'data': version_file.readline()[:10],
213 'online_update': version_file.readline()[:10]
214 }
215 version_file.close()
216
217 return versions
218
220 versions = self.get_data_source_version()
221
222 args = {
223 'lname': u'Medikamentendatenbank "mmi PHARMINDEX" (Gelbe Liste)',
224 'sname': u'GL/MMI',
225 'ver': u'Daten: %s, Preise (Onlineupdate): %s' % (versions['data'], versions['online_update']),
226 'src': u'Medizinische Medien Informations GmbH, Am Forsthaus Gravenbruch 7, 63263 Neu-Isenburg',
227 'lang': u'de'
228 }
229
230 cmd = u"""select pk from ref.data_source where name_long = %(lname)s and name_short = %(sname)s and version = %(ver)s"""
231 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
232 if len(rows) > 0:
233 return rows[0]['pk']
234
235 cmd = u"""
236 INSERT INTO ref.data_source (name_long, name_short, version, source, lang)
237 VALUES (
238 %(lname)s,
239 %(sname)s,
240 %(ver)s,
241 %(src)s,
242 %(lang)s
243 )
244 returning pk
245 """
246
247 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
248
249 return rows[0]['pk']
250
252
253
254 open(self.default_csv_filename, 'wb').close()
255
256 if cmd is None:
257 cmd = (u'%s %s' % (self.path_to_binary, self.args)) % self.default_csv_filename_arg
258
259 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = blocking):
260 _log.error('problem switching to the MMI drug database')
261
262
263
264
265 return True
266
276
278
279 selected_drugs = self.select_drugs()
280 if selected_drugs is None:
281 return None
282
283 new_substances = []
284
285 for drug in selected_drugs:
286 atc = None
287 if len(drug['wirkstoffe']) == 1:
288 atc = drug['atc']
289 for wirkstoff in drug['wirkstoffe']:
290 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc))
291
292 selected_drugs.close()
293
294 return new_substances
295
297
298 selected_drugs = self.select_drugs()
299 if selected_drugs is None:
300 return None
301
302 data_src_pk = self.create_data_source_entry()
303
304 new_drugs = []
305 new_substances = []
306
307 for entry in selected_drugs:
308
309 _log.debug('importing drug: %s %s', entry['name'], entry['darreichungsform'])
310
311 if entry[u'hilfsmittel']:
312 _log.debug('skipping Hilfsmittel')
313 continue
314
315 if entry[u'erstattbares_medizinprodukt']:
316 _log.debug('skipping sonstiges Medizinprodukt')
317 continue
318
319
320 drug = create_branded_drug(brand_name = entry['name'], preparation = entry['darreichungsform'])
321 if drug is None:
322 drug = get_drug_by_brand(brand_name = entry['name'], preparation = entry['darreichungsform'])
323 new_drugs.append(drug)
324
325
326 drug['is_fake'] = False
327 drug['atc_code'] = entry['atc']
328 drug['external_code'] = u'%s::%s' % ('DE-PZN', entry['pzn'])
329 drug['fk_data_source'] = data_src_pk
330 drug.save()
331
332
333 atc = None
334 if len(entry['wirkstoffe']) == 1:
335 atc = entry['atc']
336 for wirkstoff in entry['wirkstoffe']:
337 drug.add_component(substance = wirkstoff, atc = atc)
338
339
340 atc = None
341 if len(entry['wirkstoffe']) == 1:
342 atc = entry['atc']
343 for wirkstoff in entry['wirkstoffe']:
344 new_substances.append(create_used_substance(substance = wirkstoff, atc = atc))
345
346 return new_drugs, new_substances
347
377
398
400
402 cGelbeListeWindowsInterface.__init__(self)
403
404 _log.info(u'%s (WINE extension)', cGelbeListeWindowsInterface.version)
405
406
407 self.path_to_binary = r'wine "C:\Programme\MMI PHARMINDEX\glwin.exe"'
408 self.args = r'"-PRESCRIPTIONFILE %s -KEEPBACKGROUND"'
409
410 paths = gmTools.gmPaths()
411
412 self.default_csv_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'mmi2gm.csv')
413 self.default_csv_filename_arg = r'c:\windows\temp\mmi2gm.csv'
414 self.interactions_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'windows', 'temp', 'gm2mmi.bdt')
415 self.data_date_filename = os.path.join(paths.home_dir, '.wine', 'drive_c', 'Programme', 'MMI PHARMINDEX', 'datadate.txt')
416
418 """empirical CSV interface"""
419
422
424
425 try:
426 csv_file = open(filename, 'rb')
427 except:
428 _log.exception('cannot access [%s]', filename)
429 csv_file = None
430
431 field_names = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split()
432
433 if csv_file is None:
434 return False
435
436 csv_lines = csv.DictReader (
437 csv_file,
438 fieldnames = field_names,
439 delimiter = ';'
440 )
441
442 for line in csv_lines:
443 print "--------------------------------------------------------------------"[:31]
444 for key in field_names:
445 tmp = ('%s ' % key)[:30]
446 print '%s: %s' % (tmp, line[key])
447
448 csv_file.close()
449
450
451
452
453
454
455
456
457
458
459
460
461 drug_data_source_interfaces = {
462 'Gelbe Liste/MMI (Windows)': cGelbeListeWindowsInterface,
463 'Gelbe Liste/MMI (WINE)': cGelbeListeWineInterface
464 }
465
466
467
469 cmd = u'select * from clin.consumed_substance order by description'
470 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
471 return rows
472
474 cmd = u'select * from clin.consumed_substance WHERE pk = %(pk)s'
475 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk}}])
476 if len(rows) == 0:
477 return None
478 return rows[0]
479
481
482 substance = substance.strip()
483
484 if atc is not None:
485 atc = atc.strip()
486
487 args = {'desc': substance, 'atc': atc}
488
489 cmd = u'select pk, atc_code, description from clin.consumed_substance where description = %(desc)s'
490 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
491
492 if len(rows) == 0:
493 cmd = u'insert into clin.consumed_substance (description, atc_code) values (%(desc)s, gm.nullify_empty_string(%(atc)s)) returning pk, atc_code, description'
494 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
495
496 gmATC.propagate_atc(substance = substance, atc = atc)
497
498 row = rows[0]
499
500
501 row[1] = args['atc']
502 return row
503
505 args = {'pk': substance}
506 cmd = u"""
507 delete from clin.consumed_substance
508 where
509 pk = %(pk)s and not exists (
510 select 1 from clin.substance_intake
511 where fk_substance = %(pk)s
512 )"""
513 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
514
515 -class cSubstanceIntakeEntry(gmBusinessDBObject.cBusinessDBObject):
516 """Represents a substance currently taken by a patient."""
517
518 _cmd_fetch_payload = u"select * from clin.v_pat_substance_intake where pk_substance_intake = %s"
519 _cmds_store_payload = [
520 u"""update clin.substance_intake set
521 clin_when = %(started)s,
522 strength = gm.nullify_empty_string(%(strength)s),
523 preparation = %(preparation)s,
524 schedule = gm.nullify_empty_string(%(schedule)s),
525 aim = gm.nullify_empty_string(%(aim)s),
526 narrative = gm.nullify_empty_string(%(notes)s),
527 intake_is_approved_of = %(intake_is_approved_of)s,
528
529 -- is_long_term = %(is_long_term)s,
530 is_long_term = (
531 case
532 when (
533 (%(is_long_term)s is False)
534 and
535 (gm.is_null_or_blank_string(%(duration)s) is True)
536 ) is True then null
537 else %(is_long_term)s
538 end
539 )::boolean,
540 duration = (
541 case
542 when %(is_long_term)s is True then null
543 else gm.nullify_empty_string(%(duration)s)
544 end
545 )::interval,
546
547 fk_brand = %(pk_brand)s,
548 fk_substance = %(pk_substance)s,
549 fk_episode = %(pk_episode)s
550 where
551 pk = %(pk_substance_intake)s and
552 xmin = %(xmin_substance_intake)s
553 returning
554 xmin as xmin_substance_intake
555 """
556 ]
557 _updatable_fields = [
558 u'started',
559 u'preparation',
560 u'strength',
561 u'intake_is_approved_of',
562 u'schedule',
563 u'duration',
564 u'aim',
565 u'is_long_term',
566 u'notes',
567 u'pk_brand',
568 u'pk_substance',
569 u'pk_episode'
570 ]
571
572 - def format(self, left_margin=0, date_format='%Y-%m-%d'):
573
574 if self._payload[self._idx['duration']] is None:
575 duration = gmTools.bool2subst (
576 self._payload[self._idx['is_long_term']],
577 _('long-term'),
578 _('short-term'),
579 _('?short-term')
580 )
581 else:
582 duration = gmDateTime.format_interval (
583 self._payload[self._idx['duration']],
584 accuracy_wanted = gmDateTime.acc_days
585 )
586
587 line = u'%s%s (%s %s): %s %s %s (%s)' % (
588 u' ' * left_margin,
589 self._payload[self._idx['started']].strftime(date_format),
590 gmTools.u_right_arrow,
591 duration,
592 self._payload[self._idx['substance']],
593 self._payload[self._idx['strength']],
594 self._payload[self._idx['preparation']],
595 gmTools.bool2subst(self._payload[self._idx['is_currently_active']], _('ongoing'), _('inactive'), _('?ongoing'))
596 )
597
598 return line
599
600
601
602 - def _get_ddd(self):
603
604 try: self.__ddd
605 except AttributeError: self.__ddd = None
606
607 if self.__ddd is not None:
608 return self.__ddd
609
610 if self._payload[self._idx['atc_substance']] is not None:
611 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_substance']])
612 if len(ddd) != 0:
613 self.__ddd = ddd[0]
614 else:
615 if self._payload[self._idx['atc_brand']] is not None:
616 ddd = gmATC.atc2ddd(atc = self._payload[self._idx['atc_brand']])
617 if len(ddd) != 0:
618 self.__ddd = ddd[0]
619
620 return self.__ddd
621
622 ddd = property(_get_ddd, lambda x:x)
623
625 drug = self.containing_drug
626
627 if drug is None:
628 return None
629
630 return drug.external_code
631
632 external_code = property(_get_external_code, lambda x:x)
633
635 if self._payload[self._idx['pk_brand']] is None:
636 return None
637
638 return cBrandedDrug(aPK_obj = self._payload[self._idx['pk_brand']])
639
640 containing_drug = property(_get_containing_drug, lambda x:x)
641
643 tests = [
644
645 ' 1-1-1-1 ',
646
647 '1-1-1-1',
648 '22-1-1-1',
649 '1/3-1-1-1',
650 '/4-1-1-1'
651 ]
652 pattern = "^(\d\d|/\d|\d/\d|\d)[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}[\s-]{1,5}\d{0,2}$"
653 for test in tests:
654 print test.strip(), ":", regex.match(pattern, test.strip())
655
657
658 args = {
659 'enc': encounter,
660 'epi': episode,
661 'prep': preparation,
662 'subst': create_used_substance(substance = substance, atc = atc)['pk']
663 }
664
665 cmd = u"""
666 insert into clin.substance_intake (
667 fk_encounter,
668 fk_episode,
669 fk_substance,
670 preparation,
671 intake_is_approved_of
672 ) values (
673 %(enc)s,
674 %(epi)s,
675 %(subst)s,
676 gm.nullify_empty_string(%(prep)s),
677 False
678 )
679 returning pk
680 """
681 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
682 return cSubstanceIntakeEntry(aPK_obj = rows[0][0])
683
685 cmd = u'delete from clin.substance_intake where pk = %(pk)s'
686 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': substance}}])
687
689 """Represents a drug as marketed by a manufacturer."""
690
691 _cmd_fetch_payload = u"select *, xmin from ref.branded_drug where pk = %s"
692 _cmds_store_payload = [
693 u"""update ref.branded_drug set
694 description = %(description)s,
695 preparation = %(preparation)s,
696 atc_code = gm.nullify_empty_string(%(atc_code)s),
697 external_code = gm.nullify_empty_string(%(external_code)s),
698 is_fake = %(is_fake)s,
699 fk_data_source = %(fk_data_source)s
700 where
701 pk = %(pk)s and
702 xmin = %(xmin)s
703 returning
704 xmin
705 """
706 ]
707 _updatable_fields = [
708 u'description',
709 u'preparation',
710 u'atc_code',
711 u'is_fake',
712 u'external_code',
713 u'fk_data_source'
714 ]
715
717 if self._payload[self._idx['external_code']] is None:
718 return None
719
720 if regex.match(u'.+::.+', self._payload[self._idx['external_code']], regex.UNICODE) is None:
721
722 return None
723
724 return regex.split(u'::', self._payload[self._idx['external_code']], 1)
725
726 external_code = property(_get_external_code, lambda x:x)
727
729 cmd = u'select * from ref.substance_in_brand where fk_brand = %(brand)s'
730 args = {'brand': self._payload[self._idx['pk']]}
731 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
732 return rows
733
734 components = property(_get_components, lambda x:x)
735
737
738
739 atc = gmATC.propagate_atc(substance = substance, atc = atc)
740
741 args = {
742 'brand': self.pk_obj,
743 'desc': substance,
744 'atc': atc
745 }
746
747
748 cmd = u"""
749 SELECT pk
750 FROM ref.substance_in_brand
751 WHERE
752 fk_brand = %(brand)s
753 AND
754 ((description = %(desc)s) OR ((atc_code = %(atc)s) IS TRUE))
755 """
756 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
757 if len(rows) > 0:
758 return
759
760
761 cmd = u"""
762 INSERT INTO ref.substance_in_brand (fk_brand, description, atc_code)
763 VALUES (%(brand)s, %(desc)s, %(atc)s)
764 """
765 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
766
769
771 cmd = u'SELECT * FROM ref.v_substance_in_brand ORDER BY brand, substance'
772 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
773 return rows
774
776
777 cmd = u'SELECT pk FROM ref.branded_drug ORDER BY description'
778 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
779
780 return [ cBrandedDrug(aPK_obj = r['pk']) for r in rows ]
781
783 args = {'brand': brand_name, 'prep': preparation}
784
785 cmd = u'SELECT pk FROM ref.branded_drug WHERE description = %(brand)s AND preparation = %(prep)s'
786 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
787
788 if len(rows) == 0:
789 return None
790
791 return cBrandedDrug(aPK_obj = rows[0]['pk'])
792
794
795 if preparation is None:
796 preparation = _('units')
797
798 if preparation.strip() == u'':
799 preparation = _('units')
800
801 drug = get_drug_by_brand(brand_name = brand_name, preparation = preparation)
802
803 if drug is not None:
804 if return_existing:
805 return drug
806 return None
807
808 cmd = u'insert into ref.branded_drug (description, preparation) values (%(brand)s, %(prep)s) returning pk'
809 args = {'brand': brand_name, 'prep': preparation}
810 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False)
811
812 return cBrandedDrug(aPK_obj = rows[0]['pk'])
813
815 cmd = u'delete from ref.branded_drug where pk = %(pk)s'
816 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': brand}}])
817
819 cmd = u'delete from ref.substance_in_brand where fk_brand = %(brand)s and pk = %(comp)s'
820 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'brand': brand, 'comp': component}}])
821
822
823
824 if __name__ == "__main__":
825
826 from Gnumed.pycommon import gmLog2
827 from Gnumed.pycommon import gmI18N
828
829 gmI18N.activate_locale()
830
831
837
839 mmi_file = cGelbeListeCSVFile(filename = sys.argv[2])
840 for drug in mmi_file:
841 print "-------------"
842 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
843 for stoff in drug['wirkstoffe']:
844 print " Wirkstoff:", stoff
845 print drug
846 mmi_file.close()
847
851
853 mmi = cGelbeListeWineInterface()
854 mmi_file = mmi.select_drugs()
855 for drug in mmi_file:
856 print "-------------"
857 print '"%s" (ATC: %s / PZN: %s)' % (drug['name'], drug['atc'], drug['pzn'])
858 for stoff in drug['wirkstoffe']:
859 print " Wirkstoff:", stoff
860 print drug
861 mmi_file.close()
862
866
868 mmi = cGelbeListeInterface()
869 print mmi
870 print "interface definition:", mmi.version
871
872 diclofenac = '7587712'
873 phenprocoumon = '4421744'
874 mmi.check_drug_interactions(pzn_list = [diclofenac, phenprocoumon])
875
877 drug = create_substance_intake (
878 substance = u'Whiskey',
879 atc = u'no ATC available',
880 encounter = 1,
881 episode = 1,
882 preparation = 'a nice glass'
883 )
884 print drug
885
890
891 if (len(sys.argv)) > 1 and (sys.argv[1] == 'test'):
892
893
894
895
896
897
898
899
900 test_show_components()
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992