1if not modules then modules = { } end modules ['char-tex'] = {
2 version = 1.001,
3 comment = "companion to char-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local lpeg = lpeg
10local tonumber, next, type = tonumber, next, type
11local format, find, gmatch, match, gsub = string.format, string.find, string.gmatch, string.match, string.gsub
12local utfchar, utfbyte = utf.char, utf.byte
13local concat, tohash = table.concat, table.tohash
14local P, C, R, S, V, Cs, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.V, lpeg.Cs, lpeg.Cc
15
16local lpegpatterns = lpeg.patterns
17local lpegmatch = lpeg.match
18local utfchartabletopattern = lpeg.utfchartabletopattern
19
20local allocate = utilities.storage.allocate
21local mark = utilities.storage.mark
22
23local context = context
24local commands = commands
25
26if not characters then require("char-ini") require("char-utf") end
27
28local characters = characters
29local texcharacters = { }
30characters.tex = texcharacters
31local utffilters = characters.filters.utf
32
33local allocate = utilities.storage.allocate or function() return { } end
34local mark = utilities.storage.mark or allocate
35
36local is_character = characters.is_character
37local is_letter = characters.is_letter
38local is_command = characters.is_command
39local is_spacing = characters.is_spacing
40local is_mark = characters.is_mark
41
42local data = characters.data if not data then return end
43local blocks = characters.blocks
44
45local trace_defining = false trackers.register("characters.defining", function(v) characters_defining = v end)
46
47local report_defining = logs.reporter("characters")
48
49
50
51
52
53
54
55
56
57
58local low = allocate()
59local high = allocate()
60local escapes = allocate()
61local special = "~#$%^&_{}\\|"
62
63local private = {
64 low = low,
65 high = high,
66 escapes = escapes,
67}
68
69utffilters.private = private
70
71for ch in gmatch(special,".") do
72 local cb
73 if type(ch) == "number" then
74 cb, ch = ch, utfchar(ch)
75 else
76 cb = utfbyte(ch)
77 end
78 if cb < 256 then
79 escapes[ch] = "\\" .. ch
80 low[ch] = utfchar(0x0F0000 + cb)
81 if ch == "%" then
82 ch = "%%"
83 end
84 high[utfchar(0x0F0000 + cb)] = ch
85 end
86end
87
88local tohigh = lpeg.replacer(low)
89local tolow = lpeg.replacer(high)
90
91lpegpatterns.utftohigh = tohigh
92lpegpatterns.utftolow = tolow
93
94function utffilters.harden(str)
95 return lpegmatch(tohigh,str)
96end
97
98function utffilters.soften(str)
99 return lpegmatch(tolow,str)
100end
101
102private.escape = utf.remapper(escapes)
103private.replace = utf.remapper(low)
104private.revert = utf.remapper(high)
105
106local accentmapping = allocate {
107 ['"'] = { [""] = "¨",
108 A = "Ä", a = "ä",
109 E = "Ë", e = "ë",
110 I = "Ï", i = "ï", ["ı"] = "ï", ["\\i"] = "ï",
111 O = "Ö", o = "ö",
112 U = "Ü", u = "ü",
113 Y = "Ÿ", y = "ÿ",
114 },
115 ["'"] = { [""] = "´",
116 A = "Á", a = "á",
117 C = "Ć", c = "ć",
118 E = "É", e = "é",
119 I = "Í", i = "í", ["ı"] = "í", ["\\i"] = "í",
120 L = "Ĺ", l = "ĺ",
121 N = "Ń", n = "ń",
122 O = "Ó", o = "ó",
123 R = "Ŕ", r = "ŕ",
124 S = "Ś", s = "ś",
125 U = "Ú", u = "ú",
126 Y = "Ý", y = "ý",
127 Z = "Ź", z = "ź",
128 },
129 ["."] = { [""] = "˙",
130 C = "Ċ", c = "ċ",
131 E = "Ė", e = "ė",
132 G = "Ġ", g = "ġ",
133 I = "İ", i = "i", ["ı"] = "i", ["\\i"] = "i",
134 Z = "Ż", z = "ż",
135 },
136 ["="] = { [""] = "¯",
137 A = "Ā", a = "ā",
138 E = "Ē", e = "ē",
139 I = "Ī", i = "ī", ["ı"] = "ī", ["\\i"] = "ī",
140 O = "Ō", o = "ō",
141 U = "Ū", u = "ū",
142 },
143 ["H"] = { [""] = "˝",
144 O = "Ő", o = "ő",
145 U = "Ű", u = "ű",
146 },
147 ["^"] = { [""] = "ˆ",
148 A = "Â", a = "â",
149 C = "Ĉ", c = "ĉ",
150 E = "Ê", e = "ê",
151 G = "Ĝ", g = "ĝ",
152 H = "Ĥ", h = "ĥ",
153 I = "Î", i = "î", ["ı"] = "î", ["\\i"] = "î",
154 J = "Ĵ", j = "ĵ",
155 O = "Ô", o = "ô",
156 S = "Ŝ", s = "ŝ",
157 U = "Û", u = "û",
158 W = "Ŵ", w = "ŵ",
159 Y = "Ŷ", y = "ŷ",
160 },
161 ["`"] = { [""] = "`",
162 A = "À", a = "à",
163 E = "È", e = "è",
164 I = "Ì", i = "ì", ["ı"] = "ì", ["\\i"] = "ì",
165 O = "Ò", o = "ò",
166 U = "Ù", u = "ù",
167 Y = "Ỳ", y = "ỳ",
168 },
169 ["c"] = { [""] = "¸",
170 C = "Ç", c = "ç",
171 K = "Ķ", k = "ķ",
172 L = "Ļ", l = "ļ",
173 N = "Ņ", n = "ņ",
174 R = "Ŗ", r = "ŗ",
175 S = "Ş", s = "ş",
176 T = "Ţ", t = "ţ",
177 },
178 ["k"] = { [""] = "˛",
179 A = "Ą", a = "ą",
180 E = "Ę", e = "ę",
181 I = "Į", i = "į",
182 U = "Ų", u = "ų",
183 },
184 ["r"] = { [""] = "˚",
185 A = "Å", a = "å",
186 U = "Ů", u = "ů",
187 },
188 ["u"] = { [""] = "˘",
189 A = "Ă", a = "ă",
190 E = "Ĕ", e = "ĕ",
191 G = "Ğ", g = "ğ",
192 I = "Ĭ", i = "ĭ", ["ı"] = "ĭ", ["\\i"] = "ĭ",
193 O = "Ŏ", o = "ŏ",
194 U = "Ŭ", u = "ŭ",
195 },
196 ["v"] = { [""] = "ˇ",
197 C = "Č", c = "č",
198 D = "Ď", d = "ď",
199 E = "Ě", e = "ě",
200 L = "Ľ", l = "ľ",
201 N = "Ň", n = "ň",
202 R = "Ř", r = "ř",
203 S = "Š", s = "š",
204 T = "Ť", t = "ť",
205 Z = "Ž", z = "ž",
206 },
207 ["~"] = { [""] = "˜",
208 A = "Ã", a = "ã",
209 I = "Ĩ", i = "ĩ", ["ı"] = "ĩ", ["\\i"] = "ĩ",
210 N = "Ñ", n = "ñ",
211 O = "Õ", o = "õ",
212 U = "Ũ", u = "ũ",
213 },
214}
215
216texcharacters.accentmapping = accentmapping
217
218local accent_map = allocate {
219 ['~'] = "̃" ,
220 ['"'] = "̈" ,
221 ["`"] = "̀" ,
222 ["'"] = "́" ,
223 ["^"] = "̂" ,
224
225
226
227
228
229
230
231
232
233
234
235
236}
237
238
239
240local function remap_accent(a,c,braced)
241 local m = accentmapping[a]
242 if m then
243 local n = m[c]
244 if n then
245 return n
246 end
247 end
248
249
250
251
252 if braced then
253 return "\\" .. a .. "{" .. c .. "}"
254 else
255 return "\\" .. a .. " " .. c
256 end
257end
258
259local commandmapping = allocate {
260 ["aa"] = "å", ["AA"] = "Å",
261 ["ae"] = "æ", ["AE"] = "Æ",
262 ["cc"] = "ç", ["CC"] = "Ç",
263 ["i"] = "ı", ["j"] = "ȷ",
264 ["ij"] = "ij", ["IJ"] = "IJ",
265 ["l"] = "ł", ["L"] = "Ł",
266 ["o"] = "ø", ["O"] = "Ø",
267 ["oe"] = "œ", ["OE"] = "Œ",
268 ["sz"] = "ß", ["SZ"] = "SZ", ["ss"] = "ß", ["SS"] = "ß",
269}
270
271texcharacters.commandmapping = commandmapping
272
273
274
275
276
277
278
279
280
281
282
283local untex, pattern
284
285local function toutfpattern()
286 if not untex then
287 local hash = { }
288 for k, v in next, accentmapping do
289 for kk, vv in next, v do
290 if (k >= "a" and k <= "z") or (k >= "A" and k <= "Z") then
291 hash[ "\\"..k.." "..kk ] = vv
292 hash["{\\"..k.." "..kk.."}"] = vv
293 else
294 hash["\\" ..k ..kk ] = vv
295 hash["{\\"..k ..kk.."}"] = vv
296 end
297 hash["\\" ..k.."{"..kk.."}" ] = vv
298 hash["{\\"..k.."{"..kk.."}}"] = vv
299 end
300 end
301 for k, v in next, commandmapping do
302 hash["\\"..k.." "] = v
303 hash["{\\"..k.."}"] = v
304 hash["{\\"..k.." }"] = v
305 end
306
307
308
309 untex = utfchartabletopattern(hash) / hash
310 end
311 return untex
312end
313
314local function prepare()
315 pattern = Cs((toutfpattern() + P(1))^0)
316 return pattern
317end
318
319local function textoutf(str,strip)
320 if str == "" then
321 return str
322 elseif not find(str,"\\",1,true) then
323 return str
324
325 else
326 return lpegmatch(pattern or prepare(),str)
327 end
328end
329
330texcharacters.toutfpattern = toutfpattern
331texcharacters.toutf = textoutf
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348local untex, pattern
349
350local function toutfpattern()
351 if not untex then
352 local hash = { }
353 for k, v in next, accentmapping do
354 for kk, vv in next, v do
355 hash[k..kk] = vv
356 end
357 end
358 for k, v in next, commandmapping do
359 hash[k] = v
360 end
361
362
363
364 untex = utfchartabletopattern(hash) / hash
365 end
366 return untex
367end
368
369local function prepare()
370 pattern = Cs((toutfpattern() + P(1))^0)
371 return pattern
372end
373
374local function textoutf(str)
375 return lpegmatch(pattern or prepare(),str)
376end
377
378texcharacters.strtoutfpattern = toutfpattern
379texcharacters.strtextoutf = textoutf
380
381local collapse = utffilters.collapse
382local combine = utffilters.combine
383
384if not interfaces then return end
385
386local implement = interfaces.implement
387
388local pattern1, pattern2
389
390local verbosemarks = characters.verbosemarks
391
392if verbosemarks then
393
394 mark(verbosemarks)
395
396else
397
398 verbosemarks = allocate {
399 ["stroke"] = utfchar(0x02F), ["slash"] = utfchar(0x02F),
400 ["middle dot"] = utfchar(0x0B7),
401
402 ["grave"] = utfchar(0x300),
403 ["acute"] = utfchar(0x301),
404 ["circumflex"] = utfchar(0x302),
405 ["circumflex"] = utfchar(0x302),
406 ["tilde"] = utfchar(0x303),
407 ["macron"] = utfchar(0x304), ["line"] = utfchar(0x304),
408 ["overline"] = utfchar(0x305),
409 ["breve"] = utfchar(0x306),
410 ["dot"] = utfchar(0x307),
411 ["dieresis"] = utfchar(0x308), ["diaeresis"] = utfchar(0x308),
412 ["hook"] = utfchar(0x309),
413 ["ring"] = utfchar(0x30A),
414 ["double acute"] = utfchar(0x30B), ["hungarumlaut"] = utfchar(0x30B),
415 ["caron"] = utfchar(0x30C),
416 ["vertical line"] = utfchar(0x30D),
417 ["double vertical line"] = utfchar(0x30E),
418 ["double grave"] = utfchar(0x30F),
419 ["inverted breve"] = utfchar(0x311),
420 ["dot below"] = utfchar(0x323),
421 ["ring below"] = utfchar(0x325),
422 ["cedilla"] = utfchar(0x327), ["comma below"] = utfchar(0x327),
423 ["ogonek"] = utfchar(0x328),
424 ["caron below"] = utfchar(0x32C),
425 ["circumflex below"] = utfchar(0x32D),
426 ["tilde below"] = utfchar(0x330),
427 ["macron below"] = utfchar(0x331), ["line below"] = utfchar(0x331),
428
429 ["hook below"] = utfchar(0x1FA9D),
430
431 }
432
433 characters.verbosemarks = verbosemarks
434
435 if storage then
436 storage.register("characters/verbosemarks", verbosemarks, "characters.verbosemarks")
437 end
438
439end
440
441local function prepare1()
442 pattern1 = Cs(
443 (
444P("\\")/"" * (utfchartabletopattern(commandmapping) / commandmapping) * (P(" ")/"")
445+ utfchartabletopattern(verbosemarks) / verbosemarks
446 + lpegpatterns.space/""
447 + lpegpatterns.utf8character
448 )^0
449 )
450 return pattern1
451end
452
453local function prepare2()
454 local back = {
455 ["ı"] = "i",
456 ["ȷ"] = "j",
457 }
458 pattern2 = Cs(
459 (
460 utfchartabletopattern(back) / back
461 + lpegpatterns.utf8character
462 )^0
463 )
464 return pattern2
465end
466
467local hash = table.setmetatableindex(function(t,k)
468 local f = k
469 k = lpegmatch(pattern1 or prepare1(),k) or k
470 k = lpegmatch(pattern2 or prepare2(),k) or k
471 local v = collapse(k) or k
472 if k ~= v then
473 goto DONE
474 end
475 v = combine(k) or k
476 if k ~= v then
477 goto DONE
478 end
479 v = commandmapping[k] or k
480 if k ~= v then
481 f = "\\" .. f
482 goto DONE
483 end
484 v = textoutf(k) or k
485 if k ~= v then
486 f = "\\" .. f
487 goto DONE
488 end
489 ::DONE::
490 report_defining("instead of old school '%s' you can input the utf sequence %s",f,v)
491 t[k] = v
492 return v
493end)
494
495implement {
496 name = "chr",
497
498 arguments = "string",
499 public = true,
500 actions = function(str)
501 local hsh = hash[str]
502 context(hsh)
503 end
504}
505
506function texcharacters.safechar(n)
507 local c = data[n]
508 if c and c.contextname then
509 return "\\" .. c.contextname
510 else
511 return utfchar(n)
512 end
513end
514
515if not context or not commands then
516
517 return
518end
519
520
521
522local tex = tex
523local texsetlccode = tex.setlccode
524local texsetsfcode = tex.setsfcode
525local texsetcatcode = tex.setcatcode
526
527local contextsprint = context.sprint
528local ctxcatcodes = catcodes.numbers.ctxcatcodes
529
530local texsetmacro = tokens.setters.macro
531local texsetchar = tokens.setters.char
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549function texcharacters.defineaccents()
550 local ctx_dodefinecombine = context.dodefinecombine
551 local ctx_dodefinecommand = context.dodefinecommand
552 for verbose, mark in next, verbosemarks do
553 ctx_dodefinecombine((gsub(verbose," ","")),mark)
554 end
555 for command, mapping in next, commandmapping do
556 ctx_dodefinecommand(command,mapping)
557 end
558end
559
560implement {
561 name = "defineaccents",
562 actions = texcharacters.defineaccents
563}
564
565
566
567
568local function to_number(s)
569 local n = tonumber(s)
570 if n then
571 return n
572 end
573 return tonumber(match(s,'^"(.*)$'),16) or 0
574end
575
576implement {
577 name = "utfchar",
578 actions = { to_number, utfchar, contextsprint },
579 arguments = "string"
580}
581
582implement {
583 name = "safechar",
584 actions = { to_number, texcharacters.safechar, contextsprint },
585 arguments = "string"
586}
587
588implement {
589 name = "uchar",
590 arguments = "2 integers",
591 actions = function(h,l)
592 context(utfchar(h*256+l))
593 end
594}
595
596tex.uprint = commands.utfchar
597
598
599
600
601
602
603local forbidden = tohash {
604 0x000A0,
605 0x000AD,
606
607
608
609
610
611
612
613
614
615 0x02000,
616 0x02001,
617 0x02002,
618 0x02003,
619 0x02004,
620 0x02005,
621 0x02006,
622 0x02007,
623 0x02008,
624 0x02009,
625 0x0200A,
626 0x0200B,
627 0x0200C,
628 0x0200D,
629 0x0202F,
630 0x0205F,
631
632
633}
634
635local csletters = characters.csletters
636local activated = { }
637local sfmode = "unset"
638local block_too = false
639
640directives.register("characters.blockstoo",function(v) block_too = v end)
641
642
643
644
645local function setuppersfcodes(v,n)
646 if sfstate ~= "unset" then
647 report_defining("setting uppercase sf codes to %a",n)
648 for u, chr in next, data do
649 if chr.category == "lu" then
650 texsetsfcode(u,n)
651 end
652 end
653 end
654 sfstate = v
655end
656
657directives.register("characters.spaceafteruppercase",function(v)
658 if v == "traditional" then
659 setuppersfcodes(v,999)
660 elseif v == "normal" then
661 setuppersfcodes(v,1000)
662 end
663end)
664
665if not csletters then
666
667 csletters = allocate()
668 characters.csletters = csletters
669
670 report_defining("setting up character related codes and commands")
671
672 if sfstate == "unset" then
673 sfstate = "traditional"
674 end
675
676 local traditional = sfstate == "traditional"
677
678 for u, chr in next, data do
679 local contextname = chr.contextname
680 local category = chr.category
681 local isletter = is_letter[category]
682 if contextname then
683 if is_character[category] then
684 if chr.unicodeslot < 128 then
685 if isletter then
686 local c = utfchar(u)
687 csletters[c] = u
688 end
689 else
690 local c = utfchar(u)
691 if isletter and u >= 32 and u <= 65536 then
692 csletters[c] = u
693 end
694 end
695 if isletter then
696 local lc = chr.lccode
697 local uc = chr.uccode
698 if not lc then
699 chr.lccode = u
700 lc = u
701 elseif type(lc) == "table" then
702 lc = u
703 end
704 if not uc then
705 chr.uccode = u
706 uc = u
707 elseif type(uc) == "table" then
708 uc = u
709 end
710 texsetlccode(u,lc,uc)
711 if traditional and category == "lu" then
712 texsetsfcode(code,999)
713 end
714 end
715 elseif is_command[category] and not forbidden[u] then
716
717 elseif is_mark[category] then
718 texsetlccode(u,u,u)
719 end
720 elseif isletter then
721 csletters[utfchar(u)] = u
722 local lc, uc = chr.lccode, chr.uccode
723 if not lc then
724 chr.lccode = u
725 lc = u
726 elseif type(lc) == "table" then
727 lc = u
728 end
729 if not uc then
730 chr.uccode = u
731 uc = u
732 elseif type(uc) == "table" then
733 uc = u
734 end
735 texsetlccode(u,lc,uc)
736 if traditional and category == "lu" then
737 texsetsfcode(code,999)
738 end
739 elseif is_mark[category] then
740 texsetlccode(u,u,u)
741 end
742 end
743
744 if blocks_too then
745
746 for k, v in next, blocks do
747 if v.catcode == "letter" then
748 local first = v.first
749 local last = v.last
750 local gaps = v.gaps
751 if first and last then
752 for u=first,last do
753 csletters[utfchar(u)] = u
754
755
756
757 end
758 end
759 if gaps then
760 for i=1,#gaps do
761 local u = gaps[i]
762 csletters[utfchar(u)] = u
763
764
765
766 end
767 end
768 end
769 end
770 end
771
772 if storage then
773 storage.register("characters/csletters", csletters, "characters.csletters")
774 end
775
776
777
778
779
780
781
782
783
784
785
786
787 local pattern = P("greek") + P("arabic") + P("hebrew") + P("cyrillic") + P("roman")
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805 local function setname(category,chr,u,contextname)
806 if lpegmatch(pattern,contextname) then
807
808 elseif is_character[category] then
809 if chr.unicodeslot < 128 then
810 if is_letter[category] then
811 texsetmacro(contextname,utfchar(u),"immutable")
812 else
813 texsetchar(contextname,u,"immutable")
814 end
815 else
816 texsetmacro(contextname,utfchar(u),"immutable")
817 end
818 elseif is_command[category] and not forbidden[u] then
819 texsetmacro(contextname,utfchar(u),"immutable")
820 end
821 end
822
823 function characters.setcharacternames(ctt)
824 for u, chr in next, data do
825 local contextname = chr.contextname
826 local contextspec = chr.contextspec
827 local category = chr.category
828 if contextname then
829 setname(category,chr,u,contextname)
830 end
831 if contextspec then
832 for i=1,#contextspec do
833 local extraname = contextspec[i]
834 if extraname ~= contextname then
835 setname(category,chr,u,extraname)
836 end
837 end
838 end
839 end
840 end
841
842else
843 mark(csletters)
844end
845
846lpegpatterns.csletter = utfchartabletopattern(csletters)
847
848
849
850function characters.setlettercatcodes(cct)
851 if trace_defining then
852 report_defining("assigning letter catcodes to catcode table %a",cct)
853 end
854 local saved = tex.catcodetable
855 tex.catcodetable = cct
856 texsetcatcode(0x200C,11)
857 texsetcatcode(0x200D,11)
858 for c, u in next, csletters do
859 texsetcatcode(u,11)
860 end
861 tex.catcodetable = saved
862end
863
864function characters.setothercatcodes(cct)
865 if trace_defining then
866 report_defining("assigning other catcodes to catcode table %a",cct)
867 end
868 local saved = tex.catcodetable
869 tex.catcodetable = cct
870 for u=65,90 do
871 texsetcatcode(u,12)
872 end
873 for u=97,122 do
874 texsetcatcode(u,12)
875 end
876 tex.catcodetable = saved
877end
878
879function characters.setactivecatcodes(cct)
880 local saved = tex.catcodetable
881 tex.catcodetable = cct
882 for i=1,#activated do
883 local u = activated[i]
884 texsetcatcode(u,13)
885 if trace_defining then
886 report_defining("character %U (%s) is active in set %a",u,data[u].description,cct)
887 end
888 end
889 tex.catcodetable = saved
890end
891
892implement {
893 name = "chardescription",
894 arguments = "integer",
895 actions = function(slot)
896 local d = data[slot]
897 if d then
898 context(d.description)
899 end
900 end,
901}
902
903if characters.setcharacternames then
904
905 implement { name = "setlettercatcodes", scope = "private", actions = characters.setlettercatcodes, arguments = "integer" }
906 implement { name = "setothercatcodes", scope = "private", actions = characters.setothercatcodes, arguments = "integer" }
907 implement { name = "setactivecatcodes", scope = "private", actions = characters.setactivecatcodes, arguments = "integer" }
908 implement { name = "setcharacternames", scope = "private", actions = characters.setcharacternames, arguments = "integer" }
909
910end
911
912
913
914local function overload(c,u,code,codes)
915 local c = tonumber(c)
916 if not c then
917 return
918 end
919 local u = utilities.parsers.settings_to_array(u)
920 local n = #u
921 if n == 0 then
922 return
923 end
924 local t = nil
925 if n == 1 then
926 t = tonumber(u[1])
927 else
928 t = { }
929 for i=1,n do
930 t[#t+1] = tonumber(u[i])
931 end
932 end
933 if t then
934 data[c][code] = t
935 characters[codes][c] = nil
936 end
937end
938
939implement {
940 name = "overloaduppercase",
941 arguments = "2 strings",
942 actions = function(c,u)
943 overload(c,u,"uccode","uccodes")
944 end
945}
946
947implement {
948 name = "overloadlowercase",
949 arguments = "2 strings",
950 actions = function(c,u)
951 overload(c,u,"lccode","lccodes")
952 end
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
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037 |