diff --git a/ASSETS.md b/ASSETS.md index b915260..d267c64 100644 --- a/ASSETS.md +++ b/ASSETS.md @@ -8,6 +8,8 @@ Generated-in-code art is original and has no file to list: the UI icon set (`cra | Asset | Author | Source | Licence | Notes | |---|---|---|---|---| +| `assets/hyphenation/en-us.dic` | Grady Ward (Moby Hyphenator II word list); converted by DesignCraft contributors | https://www.gutenberg.org/ebooks/3204 (file `https://www.gutenberg.org/files/3204/files/mhyph.txt`, SHA-256 `eeb30474c86b8af3469035ec1a0913e35905325ca885290db9dfed9881e230ac`) | Public Domain ("Public Domain material by grant from the author, January, 2001"; Project Gutenberg: "Public domain in the USA") | ~165k words with break points, front-coded + deflate; regenerate with `cargo run --release -p designcraft-compose --example hyphgen -- mhyph.txt assets/hyphenation` | +| `assets/hyphenation/en-us.pat` | DesignCraft contributors (generated) | trained from `en-us.dic`'s source list by `crates/compose/src/hyphen/patgen.rs` (`examples/hyphgen.rs`) | Public Domain (CC0-1.0) | Our own Liang hyphenation patterns (no TeX/hyph-utf8 patterns used) | | `assets/fonts/Inter-Medium.ttf` | Rasmus Andersson / The Inter Project Authors | https://github.com/rsms/inter | OFL-1.1 (`assets/fonts/OFL-Inter.txt`) | Open-source typeface | | `assets/fonts/Inter-Regular.ttf` | Rasmus Andersson / The Inter Project Authors | https://github.com/rsms/inter | OFL-1.1 (`assets/fonts/OFL-Inter.txt`) | Open-source typeface | | `assets/fonts/Inter-SemiBold.ttf` | Rasmus Andersson / The Inter Project Authors | https://github.com/rsms/inter | OFL-1.1 (`assets/fonts/OFL-Inter.txt`) | Open-source typeface | diff --git a/Cargo.lock b/Cargo.lock index 51da976..4469008 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -871,6 +871,7 @@ dependencies = [ "designcraft-fonts", "designcraft-geom", "log", + "miniz_oxide 0.8.9", "proptest", ] diff --git a/NOTICE b/NOTICE index 1bf862a..ed809a7 100644 --- a/NOTICE +++ b/NOTICE @@ -7,6 +7,9 @@ This product bundles third-party material under the following licences. Per-file - Source Sans 3 and Source Serif 4 (assets/fonts/Source*) — SIL Open Font License 1.1. See assets/fonts/OFL-SourceSans3.txt, OFL-SourceSerif4.txt. - Inter (assets/fonts/Inter-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-Inter.txt. - JetBrains Mono (assets/fonts/JetBrainsMono-*.ttf) — SIL Open Font License 1.1. See assets/fonts/OFL-JetBrainsMono.txt. +- English hyphenation word list (assets/hyphenation/en-us.dic) — derived from the Moby Hyphenator II + list by Grady Ward, public domain (Project Gutenberg eBook #3204). The hyphenation patterns + (assets/hyphenation/en-us.pat) are trained from it by DesignCraft and released as CC0-1.0. - All UI icons are drawn in code (crates/ui-egui/src/icons.rs) and are original work, MIT OR Apache-2.0. Rust dependencies (vello_cpu, kurbo, skrifa, harfrust, image, egui, eframe, …) are permissively diff --git a/ROADMAP.md b/ROADMAP.md index 3e3fa0c..2693006 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,7 +6,7 @@ DesignCraft aims at full Adobe InDesign parity — and to be better: faster, ope **Working today** - Document model: facing/non-facing spreads, parent pages with page-number markers, sections, layers, frames (text / graphic / unassigned), threaded stories, paragraph/character/object styles with based-on, swatches (process/spot/tints/gradients), corner options, text wrap, drop shadow, opacity/blend. -- Text engine: Knuth–Plass paragraph composer and single-line composer, hyphenation, justification, columns, threading across frames and spreads, tabs, bullets/numbering, rules, shading, baseline grid, first-baseline options, vertical justification, wrap exclusions, overset detection, caret/hit testing. +- Text engine: Knuth–Plass paragraph composer and single-line composer, dictionary hyphenation (public-domain Moby list + our own trained Liang patterns), justification with word/letter/glyph-scaling ranges, keep options (keep with next, keep lines together, widows/orphans), balance ragged lines, optical margin alignment, hyphenation zone/limit, columns, threading across frames and spreads, tabs, bullets/numbering, rules, shading, baseline grid, first-baseline options, vertical justification, wrap exclusions, overset detection, caret/hit testing. - Rendering: vello_cpu (SIMD, multithreaded) — pages, items, images with mip levels, gradients, composed text. - UI (egui): application bar + menus, Control panel (object and text modes), Tools panel with flyouts, document tabs, rulers, pasteboard, guides (margins, columns, bleed, baseline grid), frame edges, selection handles, text ports and threads, Properties / Pages / Layers dock, Swatches, Styles, Character, Paragraph, Stroke, Text Wrap panels, New Document dialog, ⌘K palette, 4 brightness themes. - Pen tool, Direct Selection anchor/handle editing, rotate from corners, Rotate/Scale/Shear tools, Eyedropper, snapping & smart guides, Align/Distribute, Find/Change (text + GREP), Story Editor, Paragraph Style Options, Effects panel, hidden characters, native macOS menu bar, measured InDesign 2026 look (Medium Dark). @@ -17,7 +17,7 @@ DesignCraft aims at full Adobe InDesign parity — and to be better: faster, ope - MCP server (`designcraft-cli mcp [--connect PORT]`, docs/mcp.md): headless engine or the running app; commands, batch, document/story inspection, page renders as images, window screenshots, pointer/keyboard/dialog input. - Web build (`apps/designcraft-web`, trunk): the same UI on WebGPU with a WebGL2 fallback; open/place via the browser file picker or drag-and-drop, save/export as downloads. -**Next (in order):** IDML import/export · dictionary hyphenation · native format as zip · tables · PDF/X-4 output intent, bookmarks, tagged PDF · Links panel + relink · Preflight panel · TOC/index/footnotes · EPUB. +**Next (in order):** IDML import/export · native format as zip · tables · PDF/X-4 output intent, bookmarks, tagged PDF · Links panel + relink · Preflight panel · TOC/index/footnotes · EPUB. ## Milestones diff --git a/assets/hyphenation/en-us.dic b/assets/hyphenation/en-us.dic new file mode 100644 index 0000000..a090091 Binary files /dev/null and b/assets/hyphenation/en-us.dic differ diff --git a/assets/hyphenation/en-us.pat b/assets/hyphenation/en-us.pat new file mode 100644 index 0000000..92dc61f --- /dev/null +++ b/assets/hyphenation/en-us.pat @@ -0,0 +1,1633 @@ +% DesignCraft US English hyphenation patterns (Liang/TeX notation). +% Generated by crates/compose/examples/hyphgen.rs: trained with DesignCraft's patgen-style trainer +% from the Moby Hyphenator II word list by Grady Ward (public domain, Project Gutenberg #3204). +% Released into the public domain (CC0-1.0) by the DesignCraft contributors. +'2c '4cl '4do 'emil4 'emili4 'exi4 '4fa '4fl 'ha4 'immor4 '4in 'l2 +4'll 4're 2's 4's. .a2 .a4ba. .a3bas .a4b3er .ab3h .a4bia. .a4bie .a4bil +.ab5ir .a4bl .ab3la .a4bo. .a4bos .a3b4u .a6cetyl. .a4cl .a5coe .ac3t .ac4te .ac4u +.a4cus .acu4ta .a4cy .ad4ded .ad4der. .ad6din .a4dh .a4di .ad3ia .ad3ip .a4don .ad3um +.a4dur .a4dy .ae4r3 .ae4ta .af1 .af3t .a4gan .a4g3a4t .ag4e .a3gen .agis4te .a3gl +.a4glet .a3gu .aile4 .ak2 .alar4 .ald4 .a4ley .al4fa. .ali4as. .al3ie .al3im .a5lin +.al4ist .alk4 .al5ky .al3l .alli4e .alm4 .a3lon .alth4 .amalgam5 .ama4li .ama4ra. .amato6ry +.amb4 .ame4l .a4ment .ami4r .a4mosi .amp4 .an1 .a4na. .a6nac .an3ar .a3nath .an3c +.anchis4 .an3g .a4n3i .an3k4 .an4nem .an3or .an3s .an4tal .an4tat .anti3a .anti5f .anti3s +.an3y .a3o .a4pal .a3par .ap3at .a6perie .a4phar .apho3 .aph3or .a4plan .ap4le .a5por4 +.appe3t .a3pr .aqui3 .arbo6rea .archa5i .ar4chan .ar3d4 .are4l .ar3g .ar2i .aria4 .ar4ia. +.ar4io .ar4iu .ar4mes .a3rou .ar4rie .ar3s .arsen6 .ar4sp .ar4sy. .ar3t .ar4tier .ar4tin +.ar4tl .ar4ty .as4a .as5ce .as4d .as4e .as3p4 .as4r .as1s .ass4e .as6teria .as4tom +.as6tron. .as4u .at5ar .a4t4e .ate4l .ath3a .ath4em .a4to4 .ato2m .atom3i .at4ty .au3b +.au4rou .aus3 .aus4a .a4val .a4vat .a4ven .a5veng .a3vi .a4vid .aw4r .ax3 .ax4en +.ay4l .a3yu .a4zi .b2 .ba4bel. .ba2bi .bach3 .ba4cl .ba4di .ba4ga .ba4la. .bal4lu +.ba2lu .banda4 .ba4ni4 .ba4r .ba4san .bas6tia .bate4 .b4b .b4d .be4a. .be2d .beef3 +.bel4lo. .be3ni .ber2a .ber4i .be3str .bev3 .b4h .bi2al .bi4e .bi4lan .bill4a .binar4 +.biz4 .bk4 .b4l4 .ble4 .bli4n6 .b4m .b4o .boan4 .bod2e .bo4ral .bor4t .b4r +.brea4 .bre4c .brel4 .bres4 .bre4t .bri4t .bro4s .b4s .b4t .bul4bar .bun4di .bunk4e +.bun4t .bu4ri .bz4 .c2 .c4a2 .ca4bel .ca4dil .ca4le .cal3o .ca4mas .candi4a .carbon5y +.ca4ro. .car3ol .ca4t .cat4as .cat3e .catter4 .c4b .ce4br .cec4 .ce4lan .ce4li4a. .cens4 +.cer2a .cer4i .ce3r4o .cess4 .c4h4 .che4m3 .chi4g .chiv3 .chol4i .cho3ro .chthon4 .church5 +.chy4p .c4i .ci4a .cic5e .cid4e .cin3 .ciner4 .ci4s .ci4t .cit3i .cit3r .cit3y +.c4l4 .cla4d .cla4r .cle4l .cli4nal .cli4t .clu4 .c4n .cnid4 .co3ed .co5et .co4let. +.co4lo. .co4mat .convin6 .cop2e .co4pl .copol5 .co4p3y .corn4in .corre5s .cotti4 .cotu4 .cout4 +.cow5a .cp4 .cret4 .cre4ti .cro4ma .cro4p .cro4se .cru4d .c4to .cu4mi .cun4 .cu4rati +.cur4b .cur4vy .cu2t .cutin3 .c4v .cya4ne .cyan4o .cy4n .cys6tic. .cy4th .cz4 .d2 +.d4a2 .da4ce .dacty4 .da4li .da4m .da4ni .dar4ia .dar4i4u .dar4te .da4to .da4vit. .dd4 +.d4e .de4an. .dea4t .de2bo .de4bra .de4cil .de4lis .de4mi. .de4moi .de4mons .de4mos. .dent4 +.de3r4a4 .dern4 .de3sce .de6sert. .de3t2 .de4vil .de4war .dez4 .di4a. .di6able. .di4al. .diar4y +.didy4 .di4f .di4le .di4os. .diot4 .diri6gi .dis3 .disar4m .d4m4 .d4na. .do2 .do4co +.dola4 .dol2o .dors4 .dous4 .do4v .dow4y .dr4 .dre4 .dro4 .dro2m5 .d4s4 .d4u +.du4ca .dul4la .dun4nit .du3r4a .du6rativ .dus4 .d4v .dy4f .dy4nas .dy4s .d4z .eac4 +.ea3g .eak4 .eal4i .ear4t .east3 .ea4sy .ea4te .e2b .eb3o4 .ech3o .e4cla .e2cle +.e4clo .e4col .e4con. .e2cos4 .e2cot .e4da. .e4deli .ed4h .ed4it. .e4do. .ed4t .ee4 +.eer4 .e4f .efflu6e .eg4ge .e2i .eid4 .el4a .elab3 .e6later. .e4lay .eld4i .e3le +.e4lea .e4lect. .el3e3g2 .el4egit .e4len .ele3p .el4f .el4i .eli4as .e4lie .e4lio .e4lip +.e3lis .eli4so .e2ly .e2man .em3ana .e4mer .e4met .em5igra .emil4 .emili4 .emi4r .e4mis +.e4mog .e4mor .e2na .en3act .enam3 .e3name .en3an .en3c .en4cy. .en3e .enervat6 .enes4 +.e4nosi .ent2 .eon4 .eo3si .e2p .eph4 .epho4 .ep3ic .epid4 .ep3in .e4pio .e4po +.e6quine .eq3ui5t .e6quiva .er2 .e1ra .er4e .erg4 .e4ri .eri4d .er3m .e1ro .ero6g +.er4rab .er4ri .e4s3 .es4op .eso3t .es4u .et4al .e3te .e3ther .eth4yl. .e4tia .e4tow +.etu4 .eun4 .eu4ra .e4va. .e4van. .evapor4 .e4var .e4vat .ever2 .evers4 .ever4t .eve3ry +.evo4c .e4wan .ex3 .exhaus4 .ex4or. .ex5u .ey4a .f2 .fanat3 .f4b .f4c .fe4me +.fen4d .fer4a .feri4a .fe4ta. .f4f .f4i2 .fi4do .figur5at .final4 .fi6nan .finea6 .fin3g +.fis4ti .f4l .fle4 .frin4 .f4s .fu4el. .fu3si .g2 .g4a2 .ga4da .ga4m .gam3i +.gam3o .ga4p .ga4ri .gar4th .ga4s3 .ga4th .g4b .g4c .g4d .ge2a .ge4li .gen4f +.geni4a .genom4 .gent4 .gen3tl .geo4me .ger4ent .ger4i .ger4o .ghi4 .gi2 .gian4 .gi4b +.gin5ge .g4l .glass5 .g6le .gle4a .gluti6na .g4n .gne4 .go4l .go4me .gon3o .go4r +.go4s5p .gou4t .g4r .gra4ce .graduat6 .gra4p .grip4pa .gro4g .gu4g .gu4ri .gu4t .gy4b +.h2 .ha2 .ha4c .hae2 .ha4g .hag3i .ha3la .hal3i .ham5ad .hand3i .han4g3 .hank4 +.ha4no .haran4 .has4k .has4t .hast6i .ha4v .he2 .he4a .hec3at .he4i .he4la. .hel3ic +.help5 .hem3i .hem4ic. .hemis6 .he3mot .hemo6tr .hem4p .hep3a .he3red .he5resi .her6in .hero4p +.he4s .hi3b .hi4c .hi4dr .hi4lary .hil5d4 .hiller4 .hil4li .hil4ly .hi4m .hin4der .hin4g +.hi4o .hi4s .hi4t .h4m .ho4a .ho4do .hoe4s .ho4i .ho4la .ho4le .hol3o .ho4ma +.ho4mon .ho4my .hoo4 .hoosi4 .ho4p .ho4rac .ho4sen .ho4th .hov5er .h4s .huff3 .hurs4 +.hy3g .hyo4 .ia2 .iae4 .i5am .i4as. .i4ast .ia4t .i4ata .iat3r .i4br .i4ca +.i4cel .ich3 .ich4i .i4da. .idel4 .i4des .i4d3i .i3d4l .ido2 .idol3 .i4e .if4u +.ig4f .i4gl .ig3n .i4h .i4j .ikar4 .ile4a .i4li .ili4s .ilk4 .il4lima .illo4 +.il4lus. .i4lo. .i2m .im3age .imi4d .im4in .im4it. .im3m .i4mo .im4ph .im5pin .i4n3 +.ina4m .inc4 .in5ce .ind2 .in4dic. .indi6cat .ine4a .in4gly .in4k .inow4 .in6suran .i1o +.i4oa .io4b .i4or .i4ou .i4pa .ipi4 .iq4 .i4ra. .i4ran. .ir2i .i3ric .ir3id +.iri4s .i4ro. .ir3r .i4si .i4so. .i4ta. .i4tac .ital3 .i4tal. .i3tem .i3ti .i4to. +.i4tu. .iv2 .ixo4 .j2 .jame4 .jh4 .joli4 .juni4 .ju1r .jus3 .k2 .ka4le +.kal4i .ka4li. .ka4te .ka4ti .k4c .ke4g .ke4p .ke4r .kh2 .ki2 .kian4 .ki4b +.kil1 .ki4l3o .kin3em .k4l .kle4s .k4n .kni4f .kold4 .kon4e .ko4ni4a .k4u .k4w +.l2 .l4a2 .la4br .lab5y .la4cy .la4ga .lalish4 .la3ma .la4me .la4na .lan4dr .laps4ib +.lar4g .lar4i .las4t .lat3er .la4th .la4ti .lati6na .latin5i .lau2d .laz3a .l4e2 .lea4 +.lear4 .le4b .lech3e .lecith4 .le4gat .le4m .lemo4 .len4g .le4om .lep3r .le4pu .le4va. +.lew3i .l4h .l4i2 .lid4i .lie4 .li4f .li4go .li4me .limo4 .linar4 .lin4eag .li3o4 +.lis6ter. .li4tu .l4l4 .lo2 .lo4chi. .lo4g .lo4i .lo4n .lo4p .lor4in .lot4i .lo4v +.l4s .l4u .lub4l .lu4e .l4y .ly4b .ly4l .m2 .ma4bi .ma2c .mack4er .maga3 +.ma4la. .mal3ad .ma2n .mand4 .man4is .mans4 .mar4ia. .mar3ti .ma4thi .ma4tin .may4er .m4b +.mc3 .mensu4 .mer4a .mer4ise .merit6e .me4s1 .met4al. .me6te6or. .meth6yl. .me4to .m4i .mia4 +.mi4a. .mi4d .mif4 .mi4na .mi4ne .mines4 .mi4n3i .mini4a .mi4s1 .mis4er. .mk4 .m4la. +.m4m .m4ne .mo2 .mod1 .mo4da .mol4o .mo4no. .moth3 .mou4 .mould5 .mo4v .m4p +.m4s4 .mul3 .mun4ga .muni4 .munis4 .mus5ke .mw4 .mye3 .my4i .my4t .n2 .naba4 +.na4bat .na4ch .nadi4 .na4i .nal4g .nan4i .na4ri .na4to .na2v .naw4 .n4c .n4d4 +.n4e2 .ne4bri .neb3u .ne4gro. .nem3at .neph3e .ner2 .ne4th3 .neva4 .ne4vi .n4g4 .n4i +.ni2c .ni4da. .ni4e .ni4ne .nish4 .nit4e .n4n .n4o2 .no3e .no4m .no4n .no4r +.nor4thi .no4s .noy4 .ns4 .nu4i .nu4n .nur4s .ny2 .o'4 .oax4 .obe3l .ob5elis +.o5ber .o4bit4 .o4bl .ob5la .ob5lo .oblon4 .o4br .o2c .o4ca .oca4l .o4cel .o4ch +.och3l .od4 .odel4 .o6donta .o4dr .o2dy .oe6co .oes3t .o4h .oil3 .ois4 .oit4 +.ok4 .o3le .ole4c .ol3ig .ol4la .o3ly .o4mad .on4as .ond4 .on4de .on4eros .oni4 +.onk4 .on3o .ood4 .o5og .o3o3ph .oos4 .o3pa4 .o4pec .ophe4 .o3pin .o2r .or3ato +.orbi4 .or3c .or3d .o5ron .ors4 .ory4 .os3 .os4a .o4sa. .o4sc .os4i .o4st +.os4tl .ote4 .ot4i .o4tr .ou4 .ous4 .out3 .ov2 .over3 .o4ver. .o4vu .ox3 +.oy4 .o4za .p2 .p4a2 .pa4b .paci4 .pa4k4 .pa4li .pan5at .par1 .par3at .par4ch +.pa4ri. .park4e .parti4a .part4ib .pe4a .pear2 .pearl3 .pe4ba .pec3t .pe4lik .pel4te .pend4 +.pe6nult. .per4a. .pe4r3ia .per4lie .peron4 .pe3ru .pet3a .pe4ti .p4f .p4g .ph4 .pha4c +.pha4n3 .phar3i .phil4ia .pho3n4 .phtha4 .p4i2 .pic5r .pi3ge .pi4mo .pin4dl .pin4er .pi4ol +.pi3ra .pi4t .pit3y .p4l .plas3t .plat3i .pli6catu .po4dite .po3e .po4et. .po4k .po4lis +.po4ni .po4p .pop5i .pop5l .port4e .post3a .post3h .post3o .p4r .pre3ad .pre4cat .pre4lat +.pre6sent .pri4c .pro3a .proc4i4 .prolo6gi .pro4phy .propos6a .p4s .psa4 .p4t .pter4on .ptot4 +.ptyal4 .p4u .pur4ri .put4ter .p4v .q2 .qi4 .q4t .qua4m .r2 .r4a2 .ra4be +.ra4bid .ra4ce .ra4cy .ra3d .ra4da. .ra4du .ra4f .ra4gi .rain4e .ra4pi .rap4pis .ra4to. +.rave4 .rawl4i .r4c4 .re1 .re4an. .recho4 .re4col .rec5oll .rec3re .red4ded .red4din .red5in +.redriv6 .reduc4e .re5end .re4go. .re4ist .re3ma .ren4ta .re4par .rep4i .re4rem .res4t .rest4i +.ret2 .re3te .re4trib .re3vi .r3ge .rgen3 .rhag4 .rhet4 .rhe4to .rhe4u .rhot4 .ri2 +.ri4ba. .rib4e .ri4bl .ri4co .ri4e .ri4i .rio4 .ri4sh .ri4ta. .riv3e .r4ma .r4n4 +.r4o .ro4ba .ro4bi .rob4o4 .ro4ch .ro4g .rol4lin .romani6a .ro4p .ro4q .ro4san .ro2sc +.ro4set. .ro4sin .ro4sy .ro4th .rough3 .ro4ze .rp4 .rs4 .r4sa .rt4 .rud4e .ru4in. +.ru4l .run4i .runt3 .ru3r .r4w .ry4c .s2 .sa2 .sa4do .sak4e .sali6na .sal4is +.sal4te .san4de .sani3 .sa4t3in .satur4a .sa4ve .s4c4 .sca4li .scar3a .sca6tol .schil5 .sci3e +.s4e2 .se4a .se4lag .sel4e .self5 .sel4i .sel4li .sem3 .se4pa .sepho4 .ser4ice .ses3 +.se4v .s4f .s4g .s4h4 .shan3t .shing4 .shov3 .s4i2 .si3al .si4b .si4de .sid4eri +.silk3 .si5lo .sin4ga .sin3g4l .sin3i .sis3 .s4k4 .s4l .sli4 .s4m .smal4 .smar2 +.smell3 .smok4in .s4n .sna4 .sne4 .so4a .soap3 .sodom4 .so4lute .so4me .som5er .son4a +.soni4 .sot4e .soth4 .s4p4 .spel4 .spen4 .sper4o .spi4c .spi3d .spi4e .spi6ral. .spi4t +.spo3ro .s4s4 .s4t4 .sta3li .stal4l .ste4n .ster4ic .stin4 .sto4le .sto4ria .stort4 .stot4i +.sto4v .sub5l .sug3a .s4w .sy2 .sy5ring .sz4 .t2 .ta2 .ta4b .tac3i .ta4gr +.ta4l .tal4ly. .ta4mi .tani4a .tanis4 .tanta3 .ta4p .tark4 .tas4si .tati4 .t4bil .t4c +.te4 .tecto4 .tel1 .tel3a .tel3et .tel4li .ten3d4 .ten4o .ten4ti .ten4ty .tep4 .ter4as +.ter4ent .ter4me .termin4 .ter4mo .teu3 .th4 .the3a .tho4m .tho6rax .thro4 .t4i2 .tia4 +.ti4f .ti3ge .til4lag .timet4 .ting4 .ti4p .tisa4 .tita4 .ti4ti .to4e .to4i .to4li +.to4mal .tona4 .to4p .tor4c .to4th .trache5 .tra4s .tra4v .tre2 .tre4a .trep3o3 .tristi4 +.tri4ti .tro4po .t4s4 .tsu3 .t4u .tu4r4i .tuy4 .t4v .t4w .twin4i .ty3ro .tz4 +.u2 .u3b .uc4 .uca4 .u4da. .u4di. .udo4me .ugar4 .umen4 .un3 .unch4 .und2 +.under5e .under5s .u4ne .un5er4 .une4s3 .un5et .ung4 .un5in3 .unk4 .u4no .un5p .un5s +.unsel4 .un5t4 .unta4 .u4p1 .u3ra .ura4l .u3re3 .ure4ti .u3ri .u4rial .u4rid .u3ro +.u3ru .u4ru. .u4sa .u4si .usur4 .uta4 .ut4e4 .u3ti .u3tr .ut4s .u3v .v2 +.va2 .vac3i .va4len .val4is .va3p .vapo4 .var5ic .va4s .vas3o3 .v4c .ve2b .vei4 +.vel4la .ve3l4o .ven4er. .ver4se .ver4sy .ve2s .ve4ti .vi3gn .vi4ne .vin4i .vi2t .vi5va +.vivipa6 .vi5zi .vo2l .vol5v .vo4r .v4r .v4z .w2 .wap5 .ward4er .war4e .wc4 +.whirl3 .wi4 .wk4 .wo4m .wr4 .x2 .xe3r .x4i4 .xn4 .x4t .x4v .xy3 +.xyl4 .y2 .ye4 .yes3t .yh4 .ym4 .y4o .yog4 .ys4e .y4u .yw4 .z2 +.za4c .zar4i .za4s .ze2 .zh4 .z4i .zi4b .zo4i .zo4n .zo4oty .zori4 .z4v +2aa2 aad4 aa4f aar4d aar4i ab2 4a4b. 4aba. 4abag 4abaj abal2 a4bala +a3ball abal4lo a3ban aba4ri 4abasi a4basine abas4si 4abas4tro a4batea a4batis a4batt 4a4b3b +abba4s ab3d abe2 4abee a4bef a3bel a4bela abel3i a4bell. 4aber a4berc ab3erd +a4bern a3bet ab3ho 4abhu 4abia4 ab3ica abi4d a4bidit a4bien a4biet ab3if 4abile +4abilia abilis6e a6bilism abiliz6e a4bily 4abin4 abini4 a4bino ab5irr a4bist 2abi2t abit3ab +ab3itat ab3j 1a3bl a4bla ab3lat ab4lin a5bling ab3lis a4blu ab3n 2a2bo 4abo. +4aboa 4a3bob 3abolic ab5o5lise ab5olism ab3o3liz ab3olo abon4 4abor ab3ora 3about a2br +4abra. a4brad 4abran abras4 4abria ab3ric ab3rog a4b3s4 4absh absin4 a2bu a4bu. +ab3ul a3b4un 4abur a3but 4aby abyl4 aby3r abys4s 4aca. a2cad acan4d a5cap +4acara acare4 ac3a5ro 4acas. acas4se ac3c4 4acch acci4a ac5edl ac1er ac4er4o acess4 +acet2 ac3eta 4acetam ac5eton 2ac4h 4ach. 4acha achal4 a3chan ache3a ache4t a3chian +a4chic ach5ic. 5achiev ach5inat a6chiop ach5ronis ach3ry a5chu 3achut a2ci acic3 ac3id. +ac3ido a3cien ac5ifie ac5ify ac5ile a3cili aci4nate 2a3cio a6ciology 2acit ac3ita a4city +aci4u ack4erel ac4l a4clav a3cly ac3m acoat4 a4coco acoid4 a4coli aco4pa aco4ph +acorpo4 a3cou 5acoust ac3ram 4acre ac1ri ac3rob ac3roc acros4c acrot4 ac4so 4actac +acte3a ac3ti actuar4y acu1 ac3ua a4cue ac3ul ac4ulifo a3c4um acun2 a4cuse a3cut +a3cy a4cy4l a2d 2a4d. 4ada. a4daea a4daeu ad5aman 3adap 4a3das adav5e a4dc +a4dd4 4addai ade4a. ade4mia 3ademic 6ademici a3denc ad3eno a3dent ad3er. ader4y adev4 +a4df adge4t a3dha 2adi a3dia adia4p adiaph5 a4d3ic. a4d3ica a4dice a3dii a4dina +a4ding a4dinit a3dio adio3t adi4ph ad3ipo adi4ra adis4c a4dish a3d4it a4ditiv a4dito +a3diu 3adju 4adk adm4 4admil 3admit a4dn 4ado. ado4ce ado4e a4doma a4dona +a4doph adop4te ador5ab a4dot a3dou 3adox adria4 ad2t a3d4uc a4d3ula ad3umb 3adv +adwom4 a4dyn 4adyr adys4 2a2e 4ae1a ae1di ae3g4 ae4gl ae3i ae2l ael3it +ae1m ae2ma aem3or ae1n aen4i aeo4logu ae2r aer4ar aer3o1 3aerob aer4on. aer4ono +ae4sal aes3t aes4ta ae3t4 ae4tat aeth4i ae1u ae4vu aey4 a2f 4af. a3fa +a4fae a4fag af4e 4afe. afem4 affi4c a4fia a4fie a3fil a4flat a3fo4 afor4 +afri3 a3fu af4y4 4ag. agan3d aganis4t agar4ic. a4gath a4gaz ag3azi ag4c 2agea +agean4 agel4i ag3ella age3na 4a3ge2o a4geol ager4y age2s ages3i 4aget 4ageur ageus4 +4aggi aggo4 4agh aght4 ag1i a3g4ia agi3an agiar4 ag3ic. 4agie agin2 ag4ines +agio2 ag2is ag2l agli4 a3gly 4aglyphy agmen4 agn4 4agna ag4nac agni4s agnoli6 +a2go ag3oc ag1on 4ago3n4i agor4i a5gos 3agou agout4 ag3p a3g4ra a4grag agra4p +a4grapha a3g4re a4grop agrue4 agth4 4agua 4ague a3gui agus4 a2gy ag4y. agy4r +a3ha aha4li aha4n a3he ahe4m a3h4i ahi4e ahil4 ahi4m ahli4 a3ho aho4g +a3hu a1hy 2ai2 4ai. ai4a ai3b a1ic ai3ca a3i3ci ai4d aig2 ai5ko +ail3ab ail3i ail4ia. aim3ab aim3er 4a4in ain3ag ai4ne ain3i ain3ou ain2t ai4o +a4ip4 aiq4 air3l air3m ais4e aish4e a3ism aiss4 a3isti aite4 aitor5 a4ity +aiu4 aiwa4 4aj. a3ja aja4m a4jer a4jl a4jn a3jo a4joi 2ak ak4al +aka4n a3kar ak1er ak4erli ak4et ak4ey ak1i a3ki. ak4ings ako4i aks4 aky4 +ak3y. al1 4ala. 4a5laa al3ab al4abr a3laci al3a3co ala4f a3lak a4lal. 4alam +al3ama al3amu al3an4c a3lang al4ar2 a4laro al3ata al4ate a4lath al4ati a4latt a4laty +ala4zi albur4y al3c 4alci 2ald4a alde4b ald4er alder4a 4aldi al4dis 4aldu 4ale. +ale3a a3lee. aleer4 alem4a a1len a3lene. a4lenti al5entin a3leo a3lep aler4a a4les +ale4so a5less. 4alet aleth4 a3lexi a4leya alfi4 al3g4 4ali. 2ali2a a3l4ia. al3iat +alib4 2alic a4l3ic. al3ida ali2e a4lifa a1l4ig ali4ge a4liger a4lika al5imen al3ing +a4linite a4lio ali4ol alipa4 al5ipe 6alipo alipu4 alir4i 4aliste alit4e al3iva alk3at +allad4e alla4l al4lena alle4t al4leye al3li 2allic 4alloce 4allop 4alloth 4allu. al3ly +al2mer al4mic al4min almon4d alm4s al2o aloblas4 a4locy al3ogiz a1lon4 a2lony a3loo +a3lopi al4ora al3ori a3los aloy4 alp4 4alpa als4i al4sie. 4alta. alth3i al4tin +al4tis 4alu. a3lu3b al3ue al3ui a5luk a1lum a3lumi a3lumn a1lus a5lus. a2lust +a3lute a3luti alv4 al3va aly2 4alye 4alyn a3lyp 4alysan 5alyse 4alysi a3lyst +1alyt 1alyz al4z 2am. a2ma 4ama. am3ab ama3c ama3d4 am3age am3agi amak4 +a4maka a4male ama4lia a3man a4mandu. ama4ne a4manit ama3ra amas4c a4mash a3matic am3atis +am4atis. am3atiz am3ato am3atu a3maze 4amba. ambar4 am3bi ambi4er 4ambo 4ambr am4da +4amele ameli4a a3men ame3na amen4d amendato6 ame4ne. ament4a a4mentab amenta5ry ameral4 am5eris +am3ero ame4si ames4o ami4b 2am1ic a3micr am4ien am3if ami4la am3ily ami4m am3ina +ami6nize amis4e am3ito a5miu am3iz am3l amme4d5 4ammel ammis4 amn4 a4moi am5ois +4amon a4mora a4mort a4mosit a4moy ampa4nu amp3ing ampi4r am4por ampu3t 2ams am3sh +am4sp 4a4mue a4mul 4amun amy4a amz4 a4n. a5naa an4abase ana4basi an4abr a3na4ch +ana4din an4adr an3aer an3age an4al. anal6ise anal6ize. an4all an4ame4 an4amm anan4i 4anao +an3arc ana4ri. anari4a anar4ia. an2as 4anasy a4nat. anath3 anat3ic ana4tr anau4 4anca +anchan4 an3chi 3anchol 4ancht anci6nate 4anco. 2and and3ag andes5cen andev4 an4dies. an2dis +andoo4 an4dow andown6e an4drac 4andre. 4androp and4t 4andu andu4a an4dun a3nea. a3nean. +a3nemi ane4mon a3nen4t ane4p 4aner an4erg a4n3est an3eta ane4to 2ang 4ang. angar4 +anger4y ang2l an4glan an3gli angol4 an4gou angov4 an4gres an4gru an3gu an1i 4ani. +an4ia 4aniac 4a3nial a4niar an3ic a4nic. an5ica an5icis an5ics a3nicul an4id a3nide +an3iel ani4er an3if ani4la an4ilit ani4lo 4an4imi 4animo a3nine a4n3ing 4anio a3nip +a4nipl an4ir an3is an5ish anis4tr an3ito ani4toi an3ity 4a3niu ani4y an3iz 4anke +ank5ly an3l ann4 4ann. annar4 an4nema an4nia a3noc4 an3od anogam6 a3nol. 4anoli +a1no4m a3noma anon4g an3onis a4nopo anora4 a3nosi anoti4 a4nour a3nov a4nove ano4vi +4anow4 an5ox an3q 4anr an2s ans5co anse4l an5sen an4sil ans3l ans3m an4soc +anso6phi ans3pa anspar3 ans3po an4sure an4sut an4tac antal2 an4talk antar4 4ante. an4ters +anth4 an4thor anti3e 3antio 4antis 4anto. anto4c an4try an2ty a4nu. an4ub an3uf +an3ul an5umi a3nut anx3 an3ya 2anz 2ao a4o. ao4a a4ob a4oh ao3li +aos4 ao2t aout4 a2p 2ap. 4apa. 4apab a3pac apach4 a3pal a4pala a3pann +apar2 a4parin ap3aro a3part ap4bl 4ape. 4aped apel4e ape4r 4aper. a6peries ap3ero +a4pete apeu3 a3pezi aph3ano a4phare a3phe a4phes a4phot 4aphrasi aph3ro3 a4pid a3pien +ap3illo ap3ing a4pio ap4is ap3ita a4plana ap4len ap3li apo4c a4poe ap3oge ap3ola +a3polo a4p3o3m4 apon4a a4ponin a4pon4ism a4ponit apop4 apo4ph ap3opl apo4re apor3iz apor4t +a4posp apos3t a4posto a4potac a3pou app4 appe3ti 4appi appi4a. ap4ri a4pric aprog4 +aproge4 a4prop apro4pi apro4s 3aptat 4apte. ap5ule a5pun 4a3pur a4puri a1py a3py. +apyret4 a4qa aquil4 aquin4 aqui4v aq4w 2ar. a1ra. ar2ab ar3abe arac4i a3rade +ara3di a3raj 4arak ar1al ar4alo ar4amb ara3me aramel3 ara4mu ar4an. a3rang aran4gu +ar4ani aran4tis a4rap ar1as4 ar2at ara3th a3ratio ara3v4 arawa4 arb4 arbal4 arbalis4 +arbe2 arbel3i ar3bi arbor5i arbu3r arbut4 4arca ar4cant arce3n ar4chang archiv4 arcion4 +ar4cla 2ar2d ard3er. ard3is ard3ous a4rea ar3ean 2ared a1ree areli4 4aren ar3ent. +ar5eou 4a4r3er ar4ero a3res4s a4rev ar3gic ar4gre ar3gu 4arguar ar1h a2r1i a3ri. +4ar3ia aria4d ar4iali a4ric ar3ic. ar4i4cl ari4dea ar3ies a3rieta ari6ette arif4f a4rify +arimi4 a3rina. ar3inat a3rine. 4a4r3ing a3rini ar4int ar3io 4arion ari4oso ar2is ar3ish. +ariso4 ar3ison a5riss ar4it. ari3ta ar5ity ar3iu a3riv 2ariz ar3ko a4rl arla3t +ar4lite armag4 4arman arm3er. ar4mes. armis4 armon6g armo5n4is armo5niz 4armos 2ar1n ar3na +arnel4 arnet4t ar2o a3ro. ar4ob 4aroc a3roch aro4i aro4mat. ar5omatic arone4 a5roo +a3rop a3ros4e a1rou aroun4 2arov ar3ox ar4per arp5ing arpos4 arr4 arri4an. arris4t +4arrit arrol4 ar4sl ar4sn ar4sph arta4n ar3ter 4arth. 4arthe ar4thor ar4tom a1ru +4aru. a4ruc a3rus 4arv arv4e arves4 ar3w ar1y arya2 a4rz 2asa asag4 +4asal asal4a a6salt. asan4i a4sanit as3an4t a4sav as3c4 ascar4 asca4t as4ch as4cop +as4di a4sec as3ect aseli4 a4sent 4as4h ashal4 ash3er. ashi2 ashim4 ash4o a4shout +ash3y asi2 as4ia asi5al a3sib 4asic asi4d a4sidim a4sif a4sila a4silin a4silis +a4sin4 as4ings asionar4 a4sir 1a3sit ask4e asl4 as4ly as4met as1mi 2aso a2soc +aso3li a4som a4sore a4sori as4pas as3pe as3ph as5pira aspi4ran as4pr 4asse. assem4i +as2sh assis4 associ5 asso4l assor4 as4sp 4astad astat6in astau4 as4tele as3tell as3ten. +as3teri as6teria. as3tero astho4 2as3ti astil4 as4tin as4titic astna4 as3t4o aston3 as3tr +as4tray as3tu a2s1u 4asu. asu3a asu3i as4un 4asur a3sus 4asv a4syli 2at. +a2ta a4tab at3abi atag4 ata5la atalo4 atani4a ata3ra atas4 a3tax at4ch atchet4t +a2te a4teb at3e3ch at3ego at3en. at3ena atenar4y aten4te a3teri at4erin ater3n a3terna +a5ternit at5erniz a6tersi a4terso ate4v a2th 4ath. ath3em a4th3e3te a4this. 3athist 4athoc +athomor4 a3thy. 3a3thyr 4ati. at1ic atica4 at3icis 4atico a4ticoe a4ticu a4tida at3ies +a2t1if 4atig at3iga ati2l 6a6tilise. 6a6tilize. a4tilo 4atim a4time at3inat 4at3inis 6atinize +4atino atir2 a4tire at3iris a3tise a5t4iti at3itu ati4us ativ3i a3tiz at4ja 2atl +at5li atmos5 a3to 4ato. 4atoa a4tob a4tocu a4togl a4togr a4toh a4tois a4tola +a4toli a4tom a5toma a5tome at3omis at3omiz a5tona ato3nis 4atook a4topa a6tophi atopho4r +4atora a4tosp a4totr at2r a4tra atra4p a3t4re 4atri. a4triate atri4cle 4a4trico at5rics +a3tricu 4a4trid a2t3ril a2t3rim 3atriz a4troc atro4n3 a5tron. 4a4t5rophy 3atrou a3try 4ats +ats4k at4sp at4su a4tt at3te atter6ie at4tho a2tu atu4an atuar4 at3uat at3ue +a4t1ul a3tum atu3ra at3ural a4turat 4aturis 6aturiza aturn4 4atus. at4wai a2ty 4au. +aub2 auc4e a4ud au4dato aud2i au3dib audo4 audu3 aud3ul au3e au4fi aug4h +augi4 3augur 4auh au3i aul2 auld4 auli4e aulo4m aume4 aumer4 aumi4 aumon4 +4aun4 au5na aun5de aun5dr auni4 au4nit aupa4 au1r auran4 auri4o auriti4 au4rous +4aus. au4sa aus5ativ 4ause au3sib auspi4ce auta4m 3au1th au3ti auti4e au4to. autu4 +4av1ag ava3li a4vanc avar4y a2vas av5asa a3vat a4vata a2ve 4ave. av4ed ave2l +a4velo ave4no av3erag aver4an aver5i ave4sa 4avi a3v4ia av4ic a4vidl avi4et a4v3ig +avi2o avi4o4le av3ish a4viz av4o2 a4voir 4avon avo4r avor3i a3vou a3vu 4aw. +a3wa 3away 4awb a2wh aw3i aw4k awl4e awl5er aw4ly awm4 a3wo aw4pe +a2w3r aws4e aw3ye 4axa axa4l ax4eni ax3i axi4b 4axim axim4e 4axo ax4yl +2ay 4ay. ayac4 ay2an4 a4yar4 a3yat ay3l aymo4 ayn4 ays4t ay3t2 ayth4 +ayy4 az2 a2za az3ard aze4d a5zell a1zi 4azi. a4zic a3zie a3zine az3ing +azi4r4 a4zl. azo4la a4zom a3zy. a4zygou 1b 2b' 2b. 3b4a. baa4 ba3ali +4bab babel3 b3abil ba6bilis ba4br bach3e ba4cla bac3t bac4ulif b4a3da badar4 b4adic +ba4din baen4 ba4gat 3b4ah bah4n 3bai bair4 ba4je bak4erl bak4l bal3an4 ba4lata +bali4o balis4te ba4lit ballas4 balle4 bal4lo. bal4lup bal4mi 4balu ba4m b2an 3ban. +ba3na4 banda4n ban4der. ban4e ban3i ba4ni4a ban4il 4bano banse4 bant4 ba4p bapos4 +bapt4 3bar. 4baran bar4bl bar4cl bar2i bar3ic ba4rin ba3riz bar4my bar3og barris4 +bart4 bas4a ba4sani bas4es. b4asi ba4sil. 2basis bas3k bas4king bas4sis bas4tron 3b2a2t +4batae 4batean bate4s bathe4 bati4e 4batis. bat4s batter6i 4batto 4bauchee baw2d baxillar6 +ba3ya ba4za 4bazit 2bb2 4b4b. b3b4a b5bab bbal2 bba4si 4bbe b4bed bbe4s +b4besi b4bev 4b3bi bbi4a bbi4na bbi4t bbit4i 4b3b4l b5bli b3bo 4bbu 4b3by +2b1c bc4i4 bcres4 bcun4 2b1d2 4b4d. bde4m b3di bdisti4 b3do b3du b2e +2b4e. bea4h be2a4n3 3bear beas4 beat4r bea3v be4bi be4br be4ce 2b4ed 4bed. +be3da bede4v 3bedie be2dr 3bee bee4f 4befa befal4 bego4 begoni4 be3gu be4han +3bei2 be3ia 4belai be4lan 4belar 4beld4 4beles 4belet be4lia. 3bell belle4 bellig3 +4bellik 4beme bemi4 4benda ben3ed be3nev3 ben4i be3nig be4nis 4beno 3benz b1era +b3eral 3berc 4bercr berdi4 b4ere be3rea b4erg4 bergi4 3b4eri be4ri. ber4im beri4o +be4rios berlin4 3bern b4ero 4berose b4ert. ber3ti ber4tie ber4tit b4eru 4b4es. 4besias +be4sier 4bes4n be3sp be3stow bet1i be4ton be3tr be3tw be4v bev3e bev4er. 4bevi +bevil4 be3w 3bey beyo4 be4ze 2bf bfoun4 2b1g bga4 bgen4 2bh bhav4 +b3hor bhyoi4 b2i 3b4i. 3bia 4biae bial6iza bia4n bi4anc bi4arr bia4t bi4b3 +bib4a bib4it 2bic b4ich b4ici 3bicu 3bidd 3bidi bid3in 3b4ie biel4 4bieta +2bif biform4 bi2g bi4gl bigo4 big5ot 4biki 3bil1 4bila bi4land 4bilen bi4les +bil2g bi3lin bi3lise bi5lisi 4bi3l2o 4bilyn 4bin' 3bina bin2d bin4e bine4t bin4ga +bini4e 4binog 4bino4s bi4nou 4binso 3bi1o bio5e bioe4c bi4ol. 4biotr bi3p bipa4ro +3biq bir2 bir4c bir4l birm4 b4is bis4e bish3 bis4p b3ited 3b4itio b3itiv +b3itor bi4tram b4i2tu 3bitua 3biu biv4i biz4e 2bj b4j. b3je b3ju 2bk2 +bk4c b2l2 4b4l. blag4 4blah 3b4las blas5p blas4ty 4blat 4blau b4laz 3b4l4e1 +ble2a ble2m 4blem. blem3at ble4nit ble4p bler4 ble4sk 4bless 4blet 4bl4i b3lic +b4lica. b3liga bli4gato 2blik 5blin6d b4ling bli4ni b3lish 4bloi 4blol blou4 blri4 +blu4e 4blum blun3d 4blut 3b4ly 2b1m bman4i b3m4e bmer2 bmi2 2b1n 4b3ne +4bni b3no bnubi4 bo2 3bo. 3boa4 boan4e 4boant boas4 bo4b 3bod1 bod2h +bod3ie b4oed boeti4 b4oh 3boi bois4 bok4s bo3la bol4e bo4ley 3bolic 3bolish +b3o3lit bo3lo bo3lu bomba4b bom4be bombo4 3bomi b2on2 2bonai bonar4 bonav4 bon3i +bonse4 bo3nu 3boo 3bor. bo3ra bo4rab borac4 bor4al b3orat borbi4 bor3d bor4ic +4borin. bor3o. bor3ou borre4 3bort bor4ty 3bo4s bos3ci bos4si bos3w b4ot botan4 +bot4e bo4th 3bou boun4c boun5t bou4r bous4t bo3va boxyl3 3boy 2b1p bpe4t +bpro4b 2bq b2r2 4br. 3bra 4braca bra4ce bra4che 4brado brail4 bra4ne brank4 +brant4i bra4r bras2 bras4e bras4si brau4n 4brawo 4brd bre2 brea4t bre4co brel4o +bre4m 4brep bres4c bre4th bre4to 4brev. bri4b b4rici 3bri2d brid3i 3brie 4brifa +4brifuge bri4g brig3an 6brillato brind4 4brio. 4brioi 4brion 4brios 4briu bro4a bro3g +b3roga broge4 broid4 broi5de brok4 brom2 bro3mi bromi4n 4bron. bro4ph bro4sy broth3 +4brua brun4 bru3ne bry1 4bryc 2b1s2 4b4s. b4sb b3s4c bscon4 b3se 4bsh +bsi4 bsin4t bsis4 bsist3 4b3so bsor4 bsorb5en 4b3s4t bstra4 bsur4 2b1t2 bt3ab +bte2 bter4m bti4 b4u. bu4be bubin4 bub4o bu4chi buco4l budge4 bu4gou buil4 +build3 4buj 2bul bullar4y 3bullie bul4lo bulu4 bume3ni b4un4a 3b2und bun4dis bu4ne +bun4ger bun4t4i 3bur bu5ra bu1re bu4ria buri4at bur5ie bu3ris bu3riz bur1y 3b4us +busi4e buss4 bust2 bus5tib bus3y 4butan b3utar3 3butio b3utiv b3uto but4s 2b1v +2b1w 3b4y. by4b b4ye 2byl4o 2byr by3ri b5yrin byr4l bys4e bys4sa bys4t +byte4 by4z 2bz bze4 bz4i 4c'd 4c't 2c. 1c2a 3ca. 4caa. 4caaa +cab3a3li ca4bell cab3ine cab4o 3cac cacci4 cach3i ca3ci ca4cit ca4co cac3o5d caco4p +2cad4a cadav5 2cade cade4mi ca3den cael4 caeni4 c4ag cagel4 cag2o ca3gon. 2cah4 +cahi4 3cai 3cal. ca3lad calde4 cal4di ca4len ca4li. cali4fa cali4g calit4 cal4lin +cal4mi 4calog cal3or cal4pi 4calus ca4ly. ca4mak 4cambo 4camen cam3er 4cam4et cami4e +ca3nar canari4 can3c4 can3d4 4canedi can3k4 ca5noe can5ol cano5p4 4canor cant4a can4tic. +can4u 4caoni ca3pa cap1i 4capl 4capod. capon3i cap4r car1 car4an carbor4 ca3ree +car5eo ca3res4 care4u cari4sa carmi4n car3oli car4ter. car4tes car4tho carti4e car4v ca2s +cas4a cas4ser casso4 cas3tel cas5tle 4c3asty casty6la casu3 2c3asy cat1a catani4 cat3e3c +cat3eg cat4er. cat4eri ca4th cath3e3t ca4ti. 5catio 4catiz cat4j ca5to 4caton 4catoo +4cator' catri4cl catter4y ca3t4u4 ca4turas cau4s cav5er2 ca4v3i c2b2 c4bi 2c1c2 c4c. +ccar4y c3ce ccel3 ccentric6 ccep2 ccept5an ccessar4 ccha1 ccha3r4 c3ci cc4l c4cles. +cco3l ccompa3 ccoun4 ccout4 ccun4 ccu4san 2cd cdi4 cdo2 cdo4t cdou4 cd4y4 +2ce2 4ce. ce5a. 4ceab ce3ani 4ceanog. 3ceas ce3b ce4bri cec4i cecili4 4ced. +ce3da 5ceded 3cedi 3cee ce3f ceg4 ceger4 3cei2 ceip4 3cel. 4celain. 4celeu +3cell ce3lo celo4n 4celot 5cels cel4t 4cely ce3m 4cem. ce4met 3cen 5cenc +4cend cend3a cend5ent. cen4e 4cened 4cenes 4cenet cen4ic 4cenin4 ce3no cenogra6 ce4not +censur5a cen4tag 4centar 4centati cen3ter cen6tic 3ceo 4ceor 3cep 4cepe ceph1 cephe4 +4cepl 4cepo 4cepr 4c1er. cera4m 4ceran c2erb 3c4erc 3cere cer3em 4ceri4n 3c4er2n +cer4ne cer2o 4ceros cer3ou 3c4ert 4certil certin4 4certina c4e3r4u cervi4e 3ces 4cesa +ces4co 4cesh 4ceso 4cessa 4cesse ces3si 4cest. 4cesu 3cet. ce5tab c3etal ce3tat +cet2i 3cetic ce4til ce4toi cetu4 3cety 4cetylc 4cetylic 4cetylmo 4cetyls 3ceu ce3w +4cfo cge4 cgre4 ch'4 4c4h. c4ha 3cha. 4chab ch3abi 4chaelm 6chaeoc 4chago +3chai cha3l4a 4chalo 3cha4m chan4cy chan3d 3chan4g 4changel 3chanic 4chanici cha4p char4g +char4ti 3chas 3chat chatu4 chaza4 4ch3b4 chcom4 2ch3d4 2c4he2 4che. 3chea4 cheap5 +3check. 4ched ched4di chei4on che5k che3li 4che3ma 4cheme 3chemi che4m3o ch4en. 4chenbe +4chener 3che4no che4p cher4t 4ches. che4te 5chette chet4tin 4chf 2chg 2chh ch2i +3chi. 3chial 3chiat chi4cle chi2co 3chid 4chies 3chiev chi4ge chi4l5i chilo4m 4chilu +4ch3ily 3chim 4chin 5chin. chind4 ch5iness 2ch3ing 3chio chi4oe chirp3 chir4ri 3chise +3chit 4chitar chiv3a chiz5oph 4chk 2chl chle3a 3chlo 4chloi 4chly 4chm chma4 +4chn4 c4ho 4chocy 4choe 4chogy 3chon 4chono 4chony 3ch4or chor4i cho4ry 4chosph +cho2t chot3o 3chow 2chp chr4 4chroi. chro5niz ch3rym 2chs 4cht4 ch3te ch3th +chu4l chur4 chura4 chu4t 4chw4 ch4we. ch3y3d 3chym chy4pr chys4 4chyto 1ci2 +3cia cia4l ci4alite cia4n ci3ar 4ciare ci6ata 4ciatic 2ci3b cic3at ci4chl 4cici +3cicu cic4ulus 4cidas cid3i 3cidif 3cidit 3cidu 4cidur 3cies. ci3est cie3t cif1e +ci4fic 3cific. 5cifical c3ifis ciform4i cig4e4 4cigr cil3ab 4cilat cil3i 5cili3a cil4ie +4cil4is 3cilit4 4cilite 4cilitr 3cilli 5cillu ci3ly 2cim 2cin 3cin. ci3na ci4nac +c4inatio 3cine. 4c3ing 3cini cin4quef 5cinth cioe4 4ci4ol. 3ciou 2cipa 4cipe ci3ph +ci4p3i 4cipic cip4is cip4it. c4i3p4l cip3ro 4ciproci cip4ule 4cish ciss4 4cista 4ciste +2cit cit3ab 3c4ite. ci4thi cit3i3z citur4 3ciz 2c2k1 4ck. c4k3a ckas4 4cke2 +ckel3i ck3er cke4t ck3i ck3l ck5le 4ckm ck3o cko4h 1c2l2 4cl. cla2 +4cla. 4cla4do4 claf4 4clame clam3o 4clamp clan4g 4clarati clari4no cla4ro 4clasi clas4p +class4es clat4u4 c4l4e 3cle. cle2an 2c5lect cle4la cle4m cler4a cli4f4 4clik clim4 +5clinab clin4g5 cli4ni clin4is 3clip cliq2 cli4to 4clium 4cliva 3cl4o 4clogi 4clogu +4clomy 4clonu clo3p clos4t clothi4 clow4 cl4u2 clu4b 4cluc clu4d 4cluse 2cl4y2 +c4lym cly4p 2cm2 4cma 4cme 2cn c1ne cn4i 1co2 3co. co3ad coar4 +c3obit coble4 3coc co4cal cocar4p 4coche 4cocot cod4ic coenter4 co3er coffi4 4cog. +cog1i 2cogn co3h cohol5 3coi co3la co4lan colas4 col4e co4ley co3lit col3l4 +colli4e col2n 5cology co5lom 5colon col5oniz 5color color3i 2colou 3com co3ma co4mato +com4be comed4 com3er com3pi com4t 3con. 2cona con2al 2conci concy4 con4dr conger4 +3conic 4co5nid con4if con4is co5nit co3niu conni2 6connoitr 3cono conspir5a cont2 contan4 +con5ti coo3e cooker4y coo4la coo4p cooper4y co3or3 co3pa co4pag 4cope co4phy cop1i +4copic cop3ie 3co3pis co3po copol5y co4pr 3copy3 co3py. co3q 2cora co4rac cor3al +co4ram co3rat 4corb c4ord cord3an cordel4 cordi4 4cordl core4la cor4ic 4corism cork4e +corn4e 2coro coro3n4 4corp. 3corr cor4rel. 3cor3t cos3tal costi4 costu4 co4su co3ta +cot4er c4otia co4tic co3tin cotin3i co4tit 4coto4s c4ott cotti4e cotu4l cou5ple cour3a +6coustici cous4y cout4e couter4 3cov1 co3v2a co4ve4 cov4el cov3er covet5 covi4 co4w +4cowa cow5h 4coz2 cp4s c1q 4cq. c4quem c4queri c4ques. cr2 cra2 c4rack +2c3racy crad4 cra3n4i 4crano cra4p crap3i crap5u cras5t 3crat. 4c3ra3tes 3cratic 4c3ratiz +crawl3 3cre. cread4 2crean cre3at 3cred1 credit5ab cre6mas cre4natu crene4 cre4p crep3i +2creta cre4te creti4 cre4vi cre4w 4crg cri2 c4ria cri4b 4criba crib3er c4ridi +cri5f c4rin 5crine 4crinou 4crip 4cris cris4e c4risi crit1 5c2rit3i cro3ch cro4dr +cro4f cro4mar c4ron. c4ropi cro4pl cro4po c4rops cros4ci cro4set crosi4 crot4e c4ru +4cru. cru3c4 cruf4 crum4b 5crus crus4e cru3t cruti3 4cry. cry4ly 5crys 2cs2 +4cs. 4csi c4so. 4csp c3sta 2c1t 4c4t. 4cta c4tab ctag4i cta4r3 ctar4y +4c2te c4ted c3t4er c4ter. cter3is cter4o ctex4 c4tg cth4 4cti c4t1ib c3tic +cti2m3i c3tina c4ting cti4nos c4tish cti4vi ctiv6ise. ctiv6isti ct3l 4c3to cto1m ctomor6 +ctori4e ctro3c ctrop4 ctro3t c4ts 4ctu ctur3a ctyl3i cty4log cty4loi ct4z c2u +cuad4 cub2 cu4be cu3b4i 3cue 4cuee c4uf 3c4ui cui4a cuis4 cu1l c1ula +c3ula. cu4lam c4ulare c4ule 3culia cullo4 1cult cul5ta cul4te 4cultie cul4tis 3cultu +1c4um. cu2ma 4cuman c4umb 4cume cumen4is 3cumi cu4mo cum1s 5cumu c4un cun2a +cund4 4cundin cu5n4e cun4h 3cu3n4i cun5n cu4ph 4cupl 1cur curan4 cura3r cu3rat +cu4rativ cur4bl cur4d cur5dl cur4f c4u1ri cu2rin cu2ris cur4l 6currency cu4rum cur4vey +3c4us 4cusan 4cusec cuss4 cus5sin cus3t cu4tanc cutch4 cu2te 3cuted cuti4e 3cutin +cutin3i 3cutio c3utri cuy4 c2v 4cx. 1cy 3cy. cy1a cy4bel 4cyc. cy4cla +4cyl. 4cyla cyme4 cyn3i cy3o cy2p cy3ph 4cypod. cy4s cy4tiu c2z cz4e +4d's 2d. 1da 3d2a. 2d1ab d4aba d2abe d4a4br 3dac da4ces 4dach4 da4di +3dae dae4ni 2dag d3age. da4gr da3gu da4hi dah4l 4dahy 3dai daik4 dail4 +4dair dak4e da3la da4le 4dalid dal4if 4dalir4 da2m2 dam3ag dama4n d5amant damas4 +da4mo damp4ie 3dan. 3dana dand4 3dane d4ang dan3ge 4dani. dani4l 5dantic dan4tr +d2ap 4dapho 3daptab 5dap4te 3dapti dar2 3dar. 2dard d3ardi da4ri 4daris dar4i4us +darmer4 d4art das4tu 3dat dat4c da4til datilo4 da4tol da3tu dau4b daugh3 dau4r +dau4t 3dav dav5er da3vi daw4t 4daxi 3day 2db dblind4 2d1c dcas4 4dcl +dcol4 2d1d2 d4d. d3de d3dh d3di d4dib 4d3d4l ddys4 4d4e. 1dea deaf5e +deal4a de3am de1an de4as dea4th 4deaw de2bit de4bra. de4but 1de1c 3deca deca3d +de2cag de4cane 4decar de4cast de4cat de3ce 4deces de4cile de4cili de4clo decol3 dec3o3ro +de3c4r 2decto 2d1ed deda4 3ded3i 4dedl de3du 1dee deem3 def4 4def. de4fini +def5lag de4flor deform6i de1g4 3de1i 4deico de4im de4k dek4e de5ki 3del. de4la. +de4lano del4at del3eg dele4m de4li. de4lia deli4a. delib3 deli4e de2l3iq de4lis. de4lit +de3lo 3delp del4st de2lug 1d4em dem3ago deman4 dema3t de4mero 3demic dem3ic. 4demicia +de4mo. demon3o demor5 1den d4ena 3dena. de4nar4 d4enb 2denc d4enci 4denes deni4e +de6nol d4ens. den3sa d2ent 2dent. 3dental dentar4 d4ente4 3d4ent4i d4env de3o d3eog +3deol 1d4ep de3pa depau6 de3pic dep6ilato de2pu d3eq 3d4ere der5el de3rid 4derie +der3k4 derle4 3derm der2n d4erne dern3i der4ob de5rogato d4er4ol d4erop der4or. d6er3os +3derou derpi4e d5ership der3t derto4 4dertot 1des d4es. desal4 desar4 des4c descar4 +3desce des3ec de4sei des3ic des5igna 4desn de2so des3o3l de3spon des3ti 3destri 4desy +3de1t de3ta de3te de4ti de4to det2r de4tri 3deu de1v dev3as3 de3ve devel3 +de4ver dev3il de3v4o de4war. 3dex 4deye dez4i 2df dfas4 4dfo4 2d2g dg5ab +d4ge dgel4i dge2o dg1er dge4ta dg5ete dg1i d3gr d3gu dg3y 2dh 4dh. +d1h4e d4hel d4hen 3dhi 4dhib d3hou dhun4 dhy2 3d4i. 1di3a 3d4iac 4diad +3diae di4aln d4iam di4am. dia4n dias6tro 3diat dia4z 2di3b di4bat d1ibl d4ibo +di4bu 3dib3ul di4cam d3icap di3cea dic4ed di1ch d4icin4 d5icine 3dicit 4dic4l diclin4 +3d4ict dic4te 3diculo 3did didy4n d4ie. 2died 3di1en di4erl die3v 5d4iff d3ifi +d4ific. d4ifu 3dig 4digal di2g1i 4digr 4digy di3i di4lem dil3et di4l3i 3d4ill4 +4dillu d2im2 di3mi4 dimin3 di4mis di4mou 2din 3d4in. 3dina 4dinag dina4l di4narc +din4e 3dine. din4gu 3dini 4dinite di3niz din4kl di3o 3dioa di4oc. 4dioco dio4de +3diog dion4 di4or. diora4 d4iori dio3te diother6m d4iph dipha4 di4pla dipo4c dir4 +di4ral 3di1re di4ref di4rel di4ren di4res 4d5iro dirt3 d2i4s1 3d4is. dis4ant dises3 +dish4a dis3i dis5pi diss4 dis3t2 dis5ti d1ita 4ditat dith4 3diti 6ditione. d3ity +3d4ius 1di1v2 dives4 div4i 4divid. 4diviv di3vo 2d2iz 4dja djective6 d4jes d4ji +d4jt 2dk d1l2 2dla d4lac 3dle. 3dled dle4i 3dlel dles4 d4lest 3dlew +2dli 2dlo dlor4 2dlu4 2dly 2d1m 4dm4e dmin3 dmin4d dmis3 4dmo dm4s +2d1n 4d4n. 4d3na dney4l dni4 4dno 1d2o 3do. do1a doac4e 3do3b dob4l +dochei4 do3cr doc3um do3de doder6mi 4dody 3doe dof4 4doff 3dog 4dogr 3doi +4doit do2la dol4g dol3ic do4l3is 2dolit dol4li do3lom dol2or do4lou dol4u 3d4om +domen4 do3mes do4mete dom1i dom3ic 4domid do4mine do4miz 4domou 3don 4donai 4donij +do5nisti 4donit do2nou do4ny 3d4oo doo3d4 3dop dop4a dope4 dophi4 4dopto 3d4or2 +4dorat 4dor4ic dor3if dork4 dor3m dor3ou dort4e 3dos do4sag doss4e doster4 3do2t +do3th 4dotr 4dotu do4u dou4c dous4t 4dout do2v 4dovary 4dowa dow4ie 4downe +4downi 3do4x doz3i 2d1p2 4dqu 1dr2 4dr. dra2 dra4b 4drace. drag3on dra4gr +4drail drala4 drav4 dra4w dr4e 5dre. dre4i dres4se 4drh 3dria dria4n dri4b +4drik d4ril driple6 4droe. droga4 drogen3 3droi 4droll d4rom 4dromal drom3ic 4d5romou +4dromy 4droot drophobi6 drop4o dross3 4drow dru3i dru3p 4drut dry4e 2ds2 ds3b +d3sc 4d1s4e d1sh d4shu 4dsl ds3m ds4mi dso4 dsor4 d3s4p d4spo d1s4t4 +dsth4 d4stin dswor4 d4sy 2dt d4ta. d4tes d2th d4tia d4tis 1du 2d1u1a +dual6iza d4uar du3bi dubi5t du2c d3uca 3duce 3duci 3duct duct4in 3due du3el +du4gou duik4 2dul d3ulen d4ul4i 3dult 5dum. dum4bl d3umbr dume4 3dun dunc4 +4dung du4ni dun4nite 4dup. du4pa du4pe du4pin dup4l 3dupli 3dur 4durol 3d4us +dus4i dus4ta d1v dvan4c dvert3e 4dvi dvi4se 2d1w dwar4 dw4e d2wel4 dwif4 +dwifer4 1dy dya4n 4dydi dy4fe 4dyl. 4dyll. d4ym 3dy1n 4dyno dyo4 d4ys1 +dys5e dy4su dyte4 dz2 4dza4 dzo4 2e. 2ea2 e1a. 4e3a3b e4aba e4abe +eabi4 each1 each3i ea3co4 eac4s e3act e2ad1 eadapt6 eaddress6 4eade ea4d3i e3adj +e3admi e3ador e3ae eaf5en ea4fi ea4fy e4a3ger ea3gl ea4hi eak1 e4ak. eal3a +eal4at eal3er eal3i ea4lis eal3l e2alm eal3o ealth3 ea3ma e4am3er eam3i eam3y +e1an. e3and e4ane ean3er ean3i e3anic eano4r e4ans ean4tr e4apa e4ape e4api +ea4py ear3a ear4at ear4c e2are e4argua ear3in e4armo ear2n ear2t eart3e e4ar4th3 +e2arw ear2y easan4 eas4l eas4t e4ast. east3e easty4la e3ate. eat3en ea4t3er e4ath +eathe4n eath3er ea4thy eat3ie e3at4if e3atio e3ativ ea4to. eator4i e1atr eat3ri e4a3t4u4 +4e2au eaus4 eav3en 4ea4vi ea3w eb2 4eb. e3ba2 e4bara ebarba4r ebe4c e4bel. +e4bend 4eber 4ebic e4bis4 eb4l e4boan ebok4 e2bona eb4or e3br e4braw e4brio +e4bris. ebro4p e4bry ebs4 eb4t3 eb3uli eb3ulo 4ebu4r ebusi4 e4buta 4eby 2ec +e4c' 4e4c. 4eca e2cad eca3de ecag2 e2cago ec5agon. ec3ah e4cali e4calo ecami4 +e4can. e4cana e4cano e4care ecas4t ec3c4 eccar4 ec4clu ecd4 3ecdo4 e1ce e3cel3 +ecenar4 e3cer ecer4n e4chea 3e3chis 3e3chiz ech5ua ech4we eci3a. eci6able e4ciar eci6ativ +ec5ificat ec3ifie ec3ify e4cig e4cilit ec1i3m4 e3cio ecip3r e4cist e3cite ec3i3th ec4k +e4clam e2c5lec e4clina ecli6nato6 e4clino e4clog e4clom e3clu e4co. e2cog e4col. e4colle +ecolor3 e4comme ec5ommend ecom3p ecompari6 e6compen ecompos6e ec3onci e4condi e3co4p e2cor ec3o3ra +e4cord. ec3o3rou e2cosp ecos4s e4cow e1cr e3cra e2crea e4crem ecrep3 e4creto ec4ri +ecrit3 ec3rom ec3st ec4te ecti4no ectiv4iz ecu4bitu ec1ul e4c3ula e3culi e4cuma e3cun +e3cur e4cury e4cus4a e3cute 2eda ed1ag e4dah e4dalu edan4te e3dar eda4tis e4dativ +e4dato 2edd4 ed4dite 4e1de edek4 ede4mo ed2en edentar5 ede3p e2der ed3era e3des. +ed3es3ta e3destr ede2v e4dey 4edgel4 e4dh 2edi e3dia ed1ib e2dica ed3icab ed3icat +edi1e ed6ifica e4dik ed3ime e3dio ed1it e4dita e4ditiv e3diu ediv4 ed4j e2dl +1edn e2dole edo2no e4dony edriv6en e4droe 4edt ed4ta 2e2du ed4ua 5educa 2ee2 +4e4e. e4e3b4 ee4b. ee4c eech3i e2ed1 eed3in e3ed3u ee3h ee3i4 eek1 e4el. +eel3ab ee3lan e4eler e4em. eemo4 e4en. e6encoun e4ened e4ener. een3in ee4no eensbor4 +ee3nu eep1 eep3i ee3ru eesep4 e2est. eet3i ee3va e4eve e4evin ee3w e1ex3 +eexa4 eex4plos 2ef 4e4f. e3fa efal4l e4fana efe4 e2fer ef5ere efic4 3eficia +efici6ary e4fila e4finit ef5i5nite ef4l e4flag ef5lagr e4flora e4flu e3fo eform6it e2frag +efrig3 ef4t eft4il 4e3fu efu3e e2fug efun4 efu4t e4futa 4ega. egaci4 4egal +egam4e eg4an 3eganc e4gano eg4are e4garin egas4 e3gel egel4e ege4m egen1 e2g3end3 +eger4a eger4e eg4gr e3ghe e2gi2 e3gi4a eg3ib eg2ic e3gil eg3ime e3gio eg1is +e3git1 e2gle eg3li eg4my 4egn eg4no e3go e4god ego3i e4goli e4gor. ego3ris +4egos ego3ti e4grad6a egrammat6 4egraphy e4gri. e2gu e3gui e4guin. eg1ul e5gur 2e1h2 +e3ha e3he ehear4s e4hen. e3hi eh3me e3ho ehr4 e3hu ehy2 ehydro3 2ei +4ei. ei4a e3ian e4ib e1ic. ei4ce ei3d4e 4eif eig2 eil4e eil3ing e3illu +e4imar e4imo e4ims e1i2n e4inag ein3au ein4e e5ing. e4inho ein3i e4ins. 4e4i1o +ei4ov eip4i eip4t eir4d eire4 eir4i e4isa e4is4e eiss4l ei3su e3itera eiterat6 +ei2v eiv3er e3ja e4jel e2jud ej3udi ejun4 ejus3 2ek ekam4 eka3t ekate5 +e5kater e3kee ek4n ek4s e4l. e1la el3abl e4lacy e4lae e4laf e3lagi e4lagin +e3lai 4elan el3anch e3land elan4i el3ano e4lano. e4lapi elas3 5elast e4lates elat3in +e4latin. elati5niz e4l3ativ e4latori e4latory e4latur elav4 e4layl el4di el4do. e4le. elea4 +e4lean e3leas e4leat el3eb e3lec ele4ch e4lee e4l1eg el3ega e4lem el3eme 3elemen +e4lena e3lene elen4i e4leno elen4t e4leo eleono4 e4l3ep ele3ph elepi4 el3e4r 4eles +e4lese e3let. el3eto eleton5 e4leu e4lev el3eva e5le4v3e el2f 4elf. elgi4 e1li +e3l4ia e4liar elib3e e4libi e4libl el3ic. el3ica eli4ca. el4iced e3lici el4id. e4lidl +el3igib e4lign 4elik e4lim. e2lin e3lina e3l4ine el3ing eli3on e3lios e4liph elir3 +e4lira e2lis eli4sa eli4sor e4list e3liu eliv3 e2liz el3ki el4labl 4ellan. elle4r +el3li 4ellif ellif5l 4ellit 4ello 4ellu ellu5r 4elm. elme4 e1lon elo4na e3loni +e4lono el3op. el3opa el3oq e3lor 4elot 4e3lov e3low elr4 el3si el4tan el4ti +el4try e1lu elui4 elus6te e3ly 4ely. ely4a 3elyt el3ytr e4lyu e4m. em3ab +emagnet5 e2mago em4al e3man. e2mana em3anat e3manc eman4d e4mane eman4n e3m4ar e4mare +emargi5 e3mas e2mat e3mate em3atoc em5atolo em3atop e6matoriu e6mature. e4mav e4m3b4 ember6m +em5bl emblem3 3embo embod3 5embry e1m2e e4meab e4medie eme4diev e4mel emeli4 eme4lia +e3m4en ementa5r e4m3era e4mere e4merol e4mery e4m4es 4emet4 e4mete emica4 em3id4 4emie +e4mige e4migran emili4a em3im emin4 em3inen e4mingt e2mini e3miou e4mi3p emi5pa emi1r +emi4rus emis4c em3i3s4p em4ite. em4iti emi3v emm4 5emniz emod3u e3mog e4molit emon3e3 +e4mone. emon3is e4moniti emon3ol emo4nu e3moph em4or. emor4a e4mora. e4m3orr e4mory e4mosc +e4moso e4mosp e4mosu emo4te emp2 em3pe emper4e em3p4i 3empir empo3 e4ms e4mu. +em3ula em3ulo emun4 e4mv em4y emy3tho 4en't e4n. e1na 4ena. e2nac e3nade +enadi4 e3nae en5age. e3n4a4l ena2m e2nan en5ancy e4nar4d e3nari 4enary 4enbu 4enc. +en4ces 4encia 4encio 2en2d end6aged en3dam en4d3an en4dato en4ded en3dic 4endre en4dry +end4wr endwrit4 e5neal e3nei 4e4nel enem4 4enen e3n4eo enep4 en3er enervat6i 4enes +e3nes. e4nese en3esi e4nesse enes3t en4eti e3neu eneu4ri e3nev3o ene4w en4fer eng2 +en4gel en5gine en4gle eng3li 4en3gu engue4 4enhairt 4enia e3nia. en4ian e4nias. en3ic +eni4dea e3nign e3nil en3ing enion4 e4nip eni4r en3ish e4niso en3ita en3itu en6izer +4en3k enka4 4enna ennar4 enne3a 4en4nim 4enny e1no 4eno. eno4e 4enol e4nold4 +e4nom. enom4ic enon4i 4enopho 4enor en3orr e4nors 4e4nosin eno3th e3n4ou e2nov 4e3now +enro4 en2se ens4es ensi4n 4ensk ensur4a en4swe e4nt en4tage en5tar 4ente. 4entem +enth4 3enthet en4thou enti6pe enti4r ent4is 4entiv en2tiz en4tox entre3p 4ents en3twi +4e4nu. en4ual en4uf 4enul e3num e1nun en3ure e3nus e4nuses en3v e3ny. enyl3 +enz4 4enzi 2e1o 4e3o. eob3l eob4u e3oc eo3ch eoder4 eo3e eoe6c eo4es +e3og e3ol eo3la 4eo1li eo4logus e5ome e4omin eon4as e4opar eo3po eora4 eor3d +eo3re e2org eo6rient. eo4r1o e3os eo3sin eo3sta eostra4 e3ot eo4t4e eo3th eoti4 +eo2to eox3 eoxi3 4e2pa e3pac4 e3pai e4pana epar2 e4para ep3a3rab epari4 e3pas +epa4tia epa4tic epau6p e3pav e3pay e4pech e4peh epend3 epen4t e4pert e4pet e2pha +epha3la ephe2d ephem3 ephe4u e3phi e4phia 4e4phonis 4ephony e4phos 4ephr ephtha4 ephy4 +ep1i ep3ica ep3ice ep3id ep3igl ep3i3l 4epin. e4pion ep3iso epi3t ep3ita ep3ith +epix4 ep3iz eple4r e2pli ep3lic e4plorat e2poch epol4 ep3o3nem e4positi e4potis e4pp +ep4pes eppli4 epra4n e2pre ep3reca ep3red ep3reh epre4m ep3rese e2prob ep5robat epro4c +epro4l eprom5i ep3si ept2 ep5tib epub3 ep3urat e2put ep3uta e1q e4q. e4qq +eq3uab e4quer e4quie e6quine. e2q3ui3s e2quit er1 e4r' er3ab era3ch e5racio er4ah +e3rai e4raim erak4 1eral 3erali 4eralia era4lo era4ma e5raphica era3pi er4aps e4ra4r +era4s 4er4asi er4ass. er6ators 4eraz er4bage. er4bie er4bly 2er3c 4erca 4erd. er5da +erder4o erdi4e erdit4 erdo4s 2ere 4ere. 4erea e3real er3eb ere2c ere4co eredi4a +er5edu er5ee. ere6forma 3er3eig er3emb e4remou er3en 4erene 6erens eren4tis 4ereo er3er +eres4i er3ess er3est. er3este er3ett er3ex ere4z 4er3ges 4ergia erg3in er4git ergi4u +erha4 2eri 4eri. 4e1ria e3ria. 4er4ib eribe4 4eric er5icu 4erides erid4l eri4dop +e3rien 4erii er4imet 4erinc er3ine 4e1rio er4ion e4rioni e3rior erio3ra erior3i e4rioso +eriot4i e3riou 4erip e5ript eripter6a eri4q er3ir 4erity 4eriu e5rivativ e3rive 4erk +er3l erlan4d erm2 4er3me er4mel. ermen4 er4mer. er3m4i ermon3i er4mor. erna4c ernali4a +ernau4 4erne. er4nen er2ni ern4ie 4ernit 4e1r4o. e3roci erodacty6 e4rogeni e3roic eroid4 +4eroli 4eroll e4rometr e4ron. eronau4 eron4is 4e3room ero4tol 4eroun 4erow 4e4rox erp4 +er3pe 4erpen erpi4er erport4 2err4 erre4fo error3 2e4rs ersar4ia 4erse erse4h erse4p +ers4es ersh4i ers3ib ersi4e ersi4u er3sk 4ersl 4ertas erte4n ert3er. ert4h er4thag +4ertic er3tin er4tish er4tite 4ertiu er4tl er3tw 4eru. e3ruc eru4e 4er3ul 4erum +4erun e3rup er3ur 2erv 4erva. 4erve erv3er. 4ervo 4erwal 4e4rx er4yo erys4 +2es. es4a2 e2sag esalin4 e4salp esal4t e4sam esar4g esar4io 4esb4 es3ca es4cara +es5chea es4cia e4scienc 4esco e4scot e1s4cr e2scu ese2 es3ecr e4seil e3sel esel4l +es3enc e4sentee e4sentl e1s4er e4serva es4es 4es4h e1shi esi2 4esia 4e2sic es3icc +esiccat6e esic3u e2sid eside4 es3iden e3sidi esido4 e2sig es5ignat esil3i esil4l e2sim +es3ima e4sin e4sip esir3o esis4 esis5tiv 4esit es3ita esk4 e4skil e3skin 4esm +e4sn esocepha6 e2sol eso3la eso3li es3olut es4ome e4son4 e5son. es3o3na es4oph e4sorc +e4so3te esp4 es3per e4spi es5pirat espond3 espon4ti ess4abi es2sib ess3ing es4sis es4site +4essn es4sy 1est. 4esta. es5tabli es5tame e4stant e4stau e4sted 4estep e4ster. es3th4 +6esthetiz es4tho e2sti estic4i es3tif es3tig es5tina es4tip es3tit4 2estl 4esto es4tor +e5strai e5strict e4stur es2u 4esuc e4sue esui4 e4sult e2surr es3urre es4us e1sy +esychas4 e4syl. esystem4 e4sz e2t e4t. 4eta. e4tab e5tabul etae3 e3tai e3tak +et5allis et3alo 4et1am etan4 e4tant et1ap eta3ph e3t4ar3 etas4 e4tat. e3tate4 eta4th +e3tati etax4 etch3er e3tea e3tec e4ted etel2 e3tele e3tel4l e4tely e4tem e3tenc +e4tene e3tent 2eteo 4eterm e3tern eter3ni eterog6e e3tes e3tet ethar3 e4thea 4e4thel +e3there e3theri e4thic 5ethn ethod3 e4th1y 4etia e4tiam eti4b et1ic et4ica. et3icis +e4ticl e4ticule et4id e3tim etin4 et3ina eti4p e3tir et2is et5ish e5titio et3itiv +4etiu eti4us e4tm etma4 e4tn e3to 4eto. e4toes e4toid e4toma et3ona 4etone +e4tony e4tope e4topl etor4ic. e4towa e5tox et4raci et4rag e3tran e3trat e3tre4 etrea4 +e4trel et1ri et4rid et4ril e4t3rim et4rio etro5f4 et3rog e3tropi etro3s e3tru e4trum +1e3try et4st et4su e4tt 3ettan et4ten et4tes et4tine. 4ettl 4etto et3ua e3tud +etu4i et3ula e3tum e3tun e3tu4r 4etv ety3le 4e4tz 2eu1 4eu. e4u3b2 euc4e +eu3ci euck4 eu4cy eu2i eul2 e1um. eu4mi eun4e eun4o eunu4 eupa4 euphe3 +4eur eu3ra eu4ram eu4ras eury4l 4eus e1us. eus4p eut4e2 eu3ti e3util eu3to +euton3 eu4zl e2vale ev3ane e2vans evap3 evardi4 e4vart evass4 evas3t 3evate 3evati +e4vatt e3vea e4vei e4v3el. ev5elatio ev3ell evel3o e4vena even4i even6ta e2ven4u ev3er. +e4verat e2vere ev3eren ev4ers ever4to e4ver2y e3vet e4vev eviar4y e3viat e4v3i3d evi4e4 +e2vil evil3i e3vinc 4eving evit4er e3viti eviv3a e2vo e3vo. ev3ocab evol3a ev3ole +e4v3olu e4von e5voro e3vot ev3r evv4 ev3y 2ew e4w. ewal4l e3wee e4wic +ew3ie e3wif ew3ish e4witt ew3l e3wo e2x 4ex. ex3a exac5e exae4 exas4t +3ex3c exci4t ex3e 3exh ex3i exi4an. 4exm exon4a 3ex3p ex5ul e2y e4y. +ey4al 4e5yar ey3de 3eye. eye3l eyk4 eyl4 ey4na eyne4 eyo4g ey3or eyp4 +eys4 ey3se ey3t 2ez 4ez. e4zant. ez2e e4zel ezi4a e3zo e3zu e4z3z +1f 4f's 2f. f2a 3fa. fa2b fab4b fa4b3u 3fa2c fa4ce fa3cie fac5u +4fael faer4 4fage fain4 3fal fald4e falder4 fal4l3e fal4lin falo4n fal4sie falut4 +4famati fa4min 3fan 4fana. fanat3i fa4ne 4fanie fani4l 4fans 3far far3ad far4m3 +fa4ro. 4fars far4sp farth4 fash3 fas3ten fa2t fa3ta fatar4 fa3the fa4tiz 4fato +fat3ua fault3 faus4 fau4v faw4 faya4 fay4al. 2fb 2fc fca4 fcas4 2fd +fe2 2fe. feath3 f4eb fe4bris 2feca fec4ta fed1 feel3 4fees 3fei2 fek4 +fe3li fem3 fem4a fe4mer femi3 femor4 fen2 4fen. 3fend 3fens feof4 f2er. +2fera fer3e fer4es feri4a. feri4as 4f1ero fer4ob fe3roc fer4op 3ferr 4ferse 3fert +4fertit fer3v 3f2es 4fesa fes4sa fessing4 fes3ta 3feu fe3v4 2ff2 4f4f. 4ffa +4ffe f4fed f3fen ffer3 ffer4o f3fet 4ffi f3fic ffich4 f4fie ff4ie. ff3ily +ff5iness ffin3i f4fis 4ffl f3fle f5fle. 4ff3n ffor3e f4fr. f4frai 4ffs f3fu +ffus3ib f4fy 2fg fgh4 fgha4 2fh f4i. 3fi3a 5fiab 4fian. fi3b fi4bo +fi4bu 4f1ic. 4fica. fi4cab 4f3ical 4f3ican 4ficate 6ficatin 5ficatio 6ficato 2fic4e 4f3icen +4fices fich4e 3fici fi3cie 4ficis 4ficit fi4cl 4fics 4ficulti 3fid fi3de4l fid3i +4fido fi4do. fi3du 3fie 5fied 5fiel4 fier4 4fies fi4f fift4 3fi2g fight3 +fig1u2 4fik fi5lad fil3am fi4latu fil3i fil2l fil4m fin2 3fin. fin3ab fi3nal +find5 4fing. fin3ge fin4ial. fin3is fin4nic. fin4nis fi4noi fi2r2 fires4 fish3 3fishe +f3ishly f3ishn 5fist fis4tia fi2t f3it3a fi4te f4iter fi4u 3fix fiz2 f2j +2fk f2l2 4fl. 3fla fla4c fla4ge flag3el 4flagr fla4my fla4s fla3v f4le +3fle. fle4a flen4 fler4 4f5less fleu4ro 4fley 4fli. flich4 4flik flin4 flint3 +4flis 3flo flo1r 4florat flor4i flo4rie flo4rin. floy4 flu1e flu3i flu4t 2fm +2fn f3ne f2o 3foc fo4e 3fol 4fola fo1l4i foli5a fomo4 fon4a foni4 +fonni4 fonta4 fon4tal 3foo fool3 3for2 fo6rab fo4ram. fo4ras fo3rat6 for3b for4c +fo4rea for3ei fore5r 4for4mate for3n4 fos3 fote4 3fou fough4 foun4dr fouri6er. fout4 +fow4 2fp fper4 fr2 4fraf frag4o f4rai fran3c fras4 fra4tr fre2d frel4 +f4re2s fri2 4frid fri4ga frig3e fri3k fril4 fro2 4frob fro4ni4 frost3 frot4ta +f4ru 4fru. frui4 frus3 2fs2 fsa4 fsur4 2f2t 4f4t. 4fte 4ft1i ft3l +f4tm 4fto f5ton 3f4u. fuck4i fue4gi fu3el 4fug fu4gu 3ful 4fulo fu2m +fu3ma 3fun fun4a fu3n4e 3fur fu4rat fu3ri fu6riate. 3fus fu3sil fus2s3 fuss5i +fu4s3t fu2ta 4futab fuz2 fuzz3 4fve 2fw fy1 3fy. 3fyi 5fyin fy4k +f4yo 2g. 1g2a 3g4a. gaar4 ga4ba 4gabo ga3br gac4 4gach gadge4 gad4h +gadi4 gadis6 ga4dit ga5dr 3g4ae 4gaeu gagam4 gag4n gah4 3ga4i gais4 3gal. +gal4a 4galay ga3len g4ali gal4ib 3galis gal5ler gal4lin galma4 ga1lo galo4pi 2gam +gam4a 5gamb gambi4e games4 3gamic g3a3mis g3amou g3amy 3gan 4ganap gan3gl gan4gla +gan3i gan4im 4ganip gan6iser ganis4ti 4gann 4ganof ga4nome gans4e 2gapo ga4py gar3den +g4area gar4it garn4 ga3r4o 5gart gar4ti ga2s ga4se gask4 gas4me ga4so gas4per. +g4ass4 3gas3t 3gate 4gatee 4gatew 4gatha gath5er. gath4i 3gatin 3gatio g3ativi gativ6ism +ga4tiz 4gatorin 4gatu 3gau2 gaus4 gauta4 gauti4 gav4a ga4ve gav3el gay4a 2gaz +2gb 2gc g4c. g3ch g4cy 2g1d gd4i g4dy gdyni4 4g4e. ge1a 4geab +ge2ar 2ged 4ged. ge4dal 3gee 4gef geiss4 gel4a 2gele gel3ic ge4lid ge4lig +4gelik gel4in g4ella. g3ellat g4elli 2gem 4gema gemar4 gem3i ge4mo gemon4is 1ge2n +ge3nar 4genary 3genc 3gene gen3es 4genes. 4genet. gen4fe gen1i geni4al 3genic geni2o +2genis gen3it gen4ite geni4u 2geno g4enoi genom4i 4g3enou gens4e 3gent gen3tle ge4nuse +4g1e3ny 1geo ge4of 3geog ge4ol. 4geole ge2on ge2or ge2ou ger4an 2gere 3geria +germa4no 2gero 1g2es 4gese 3gesi gesi5a ges3tat get4a ge4tar get1i 4geto ge4try +3gett 3geu geus4t 2gf g4fet 2g1g2 ggar4t gge4d g5gedl g3gedn g3ger g3gi +ggi4a gg4l gglom3 gglu3 g3go ggo4t ggran3 gg4s 2gh2 4gh. g3ham ghar4i +ghas4 gh3b gh4es. gh3f gh3h ghi4b gh3in ghi4o gh3l 4ghn g5horn g3hous +ght1 gh4ten 3g4i. 1gi2a gi3al giale4 gian4t giar2 giar4c gia3ri gi4at gia4to +1gib gib4e g1ic g4ici gi4cl 3gid3i 3gien gi1es gi4et gi3ga gigam4 g4ih +gi4le g4iliu 2gim g3imen g4in. gin2a gi3nab g4ind 3ginee giner4 g4ines. 2ging +gin5ger gin4h gini4a g4int 1gio 3gion 4giose giotro4 3giou gipa4 gip5s 3gir2 +4giriti girl3 1gis g1isl giss4 g2ist. gis3te g1i3ta gita4l gi4tall g4ite 1giti +4gitim. gitin4 gius4 3giv 1giz 4gji 2gk g3k4i4 4gko gl2 4gl. gla2 +gla3b gla4d glam3 4gland. g4lar glas2 glas4s glazi4 1g4le 3gle. gle4an 3gled +4glen. 2gles g5less 4gley 2glia gli4b 4glie. g3lig 4glik g4lim 3glion g3lish +4glisti 1glo globi4 4glod 4glog glom3e glo4n glo1r glou4 glo4v 4glu. glu4me +glu3ti 3glyc g4lym 3gly4p 4glyphy glyr4 2g1m 4gma2 gma6tos gmentar5 2g1n2 g4n. +g4na. g4nac. g4nace gna4g g3nal gnar4 g4nard gna4s gnat4a g3nati gnet5ise gnet4t +3gneu gneu4ry g4ni. gni4an gn4ic g3ni4f gnif4ic. gn3ing g4nio4 gnis4 g3nit gniz2a +gn3l gn3m gn4o g4no. g2nol gnom4 gnon4 gno3ra g2ny 1go 3go. 3goa +go4bl go3c g3ocy 4godo goer4 3g2o2g 4gogr 4goh 3goi goid4 go3is gold4i +4golit gol4le go4mer 2gon2 g2on. go1na4 g4onar g4one. 3gonia 3g4onic go3nid 4goni4e +gon4io gon4ism 4gonist 3goniu go3nom gon3op 4gonu 4gony g3ony. 3goo4 gor3at gor3ou +4gosa 4goso goster4 g4ot 3go4th 3gou 4gour. 4gout. go2v1 gover4 govin4 gowa4 +2gp gper4 gpi2 1gr2 g2ra2 gra4ces 4grag. 3gram grama4 3gran granar4 grang5er +grani4t gran4te 2grap gra4pe 3graph. 4grapha. 6grapher 3graphi 5graphic 4graphis gra4py grar3 +gras4 gra4tin gra4tis 4gray. 3g4ree greg4 gre2l 4gressis gre4t 4greth gre4v g2ri +2gric g3ricu 4grif grif5fi grigen4 gri2m grin4d 4grity gri4z g4ro2 groc4 grol4l +4grope groph4 4gropo gro3sc grue4l gruf4 gruff3 grum4p gry4p 2gs2 g4s. g3sp +g4spo 4g1s4t gstar4 2g1t2 4gta g4th gth3e gting4 1gu 3gu. 3gu2a gua3d2 +guar3a guay4 gu4dr 2g4u4e 4gue. 4gued 4guef guel4 gue4la 4gues. gu4gl guia4 +3guid 3guil gu2in gui3na 2gu1l gul4lab gul4p gum4a gu4mis 3gu4n 2guo 4g3uou +4gup 2gur gurd4 g1ure gu4rio 3gus gu4si gus3tat 4guta gu4th gut4s guya4 +4gva 4gve 2g1w 4gwa g4wane 4gwe 1gy 2gy2a gy4bi 4gygu 4gyh 2gyn +gy4ne gyn4i g3yny 4gypt. gy1r gy5ra gy4t 4gze gz4w h'4i 2h. h2a. +4habad ha4baz habi2 ha4bile h3abl ha4col h2ad ha4dar ha4deu had4j had3ow haf4 +ha4gan hag2i hag3ic hag3io h3agis hag4on h3a3gy h4ah ha4han haid4 hail4i 4hairt +ha4it ha4ki hal2 ha3lami hal4an ha6lange. ha4lar h2ali hal3ic h3aliti hal5mi ha1lo +ha4loc ha4lone ham3it hamma4 hamme4 ha4my h2an2 ha2nat handel4 han3er h4ang han4ge +hang3er han4i han5ic hani4l h3anis ha5nisti h3a3niz han4k han3n ha4no. h5anol h3anous +ha4nov 4hansh hao2 ha3ot hap3er ha4p3l h4apu h2ar har3ac ha3ran hard5en. har3d4i +haren4 hare4u har4f har2g har4ga har4ia har4iz har2mi ha3ros4 har2p har4tis hary4 +hass4 h4a2t ha4tiz hauc4 4haud haugh3 hau4l hauli4 5hause ha2v ha4ve havel4 +havi2 hay4a ha2z haz3ar 2hb h3bo h3b4r 2h1c hcas4 4hcl hcom4b 4hcr +2h1d hdra4 hd4u 4h4e. 3h4e4a4d he3an hea4p hear2 3heart heart3i h3east3 heathe4 +hea5then heat3r hea4v heav3i hebe4i hebra3 he4bri he4bro he4cl hec3t hectom4 h4ed +4hed. hed4dit hede4 he4done hed3u hee4n hega4 he4gi he4ia he4il he2in hein4i +he1is he4j 4hek hekho4 hel4ep hel3ico heli4e he3li3o hel4lie hel4lis hel4ly h3elor +helo4t hel2p hely4 he2m he4matei h4eme hemer3 hemilu6 hem4ise. hem4ith he4mon he4m3or +hem4pe he2na he3nes he4nias heni4e hen3is hen3iz henom3 4henu he4o. heo3ri he4os. +h3eosi heos4t he2p hepta4v he2q her4ali her4bal her4by her4d here3a he3redi heres4 +heret6ic. here4v he4ri. h3eries herit3a he3riti herlan4 her4mel hermi4t hernali4 her4ome her2op +her4or hers4e hert4e h3erw h3es. hesan4 he4sho hes3it hess4e hes4sit h2est hes3ter +hes3tr het1 hete4 het4ed h3e3teri he3tis he3t2iz het4tine heun4 4h4ev he3vis hex3 +hexas4 h4ey. 2hf2 4hfu 4hg. h3go h1h h4i. hia4n hian4g hi4ap hi4au +h5iave hi3be hi4bo hibra4 h1ic hi4c4e h3ici h4id hid4it hi4do hi4dy hien4 +h3ier. h3i1es hi3est hif4fer hi4fl h3ify hi4get high3 hight4 h4ih hi4lad hi4li. +hilib4 hi4lin h3iliz hillar4 hiller4y hil4loc hilo4mo h3i3lou h1ily hi4lyr h2im hima4 +hi4mac4 hi4mar him4it h4ina hin4der. hin4derm hin4ea hine4al h3ing. 4hi3no h4inom 4hinu +4hi1o hio4d hi4oed h4iol hi2on hiop4i hi4or hi2p hiprot4 hiq4 hir2 hirel4 +hirst3 his4a hi4se his3el hi4sor hist2 his5tam his3tl his4try h4i2t 4hite hith3er +hi4top hi2v hiv3al hiv4al. hi2z h1k 4hki 4hko 2hl hlag4 h3lan h3lea +hle4b hlep4 hle4t h1li hl4o1 hlor2i hlo5ric hloro3 hlo6rou hls4 2h1m2 4hm. +hma2 hma4g h3man hmel4 h3men hmet6ic. hmi4r 2h1n2 4hn. h4nen hn4i hni4e +h4nol. hnos4 h2o ho4ag4 ho3bo ho4co h4oda h3od3is h5odiz hoen4 ho2g hog3o +h4oi4c h4ois ho4it ho4lam ho4lap ho4l3ar holat6 3hold1 hol5er holes3t ho4ley hol3ic +ho4mas ho4me3s ho4mogr ho4mopho homo3t homy4 ho4my. hon4a ho4nas ho4nau hond4 ho4ne. +ho3nem ho5net hon2g hon4is ho3niz hon4oc ho3nog ho4o 3hood hoo4k hoo4p hooper4 +hoot3e hopes4 hophyl6lo ho4pl h3opoe hor2 h4or. 4ho3ra ho4rab horar4 ho3reo ho3reti +horian4 hor3ic horo4b hor4on hor4s 3horse hors3i ho4ry. hos4e hosi4 hos3p ho4tho +hoto1 h4oug 3houn houp4 3house ho2v hove4 hov3el ho4via 2h1p 4hpa hpem4 +hpri4 2h2r 4hra hral4li hra4sa h4r4e hrea4 hreat3 hren4e hre4no hre4s hr4i +h5rig hri4s hroat3 hro3mic hro4mis hro3n4is h4rops hr4y h3ryma hs2 4hs. hs4e +h3sh h4shu h4si2 hsin4 hsink4 h1s4t h4stag hsti4 h2t h4t. htab4 ht1e4 +h4ten. hten3i h4t3eo ht2er h1th4 htha4la hthe4us h4this h3thy hthyla4 ht3l 4hto +h4ts htu4 h2u hu2a huat4 huf4 huff3i hu4ge hugh4e hu4mis hum4p hump4y +hun4e hunk4e hun4t hur2 hura4d hu4rat hur4c hu1ri hu6rise. hur4l hurs4i hur4t +hus4s hus3t4 hu2t huta4 huz4i h1v 4hv. h4vh 2h1w2 4h2wa hwar4 h3ward4 +hwat4 h3way hw4e hy1 hy4' hya4c hya5li hy4bi hyen4 hy3gi hygro3 hyi4 +h4yli hy2m 4hymi hy3o hy4pre h4yr hy4rh hyr4i hyro4g hyroi2 hy4s2 hys3e3a +hys3i3a 4hyt hyx3 2i. 2i1a i3ab i4abel iabi4 i3ac. 4iacal iace3t ia4chi +iaci4 4iaco iac5o5na i3ad ia3de i3ae iaf4 4iag i2age i4agu 4ia4h i4ai +i4ald iale4u i3alit i2am ia4mi i4amo ia2n ia4na 4ianao ian3at ianchi4 i4anco +4ianh ian3i 4ianii ian4ite 4ianne. 4iano i4ano. ia4nop ianop4s 4iansk iaon4 ia3pa +ia4pl i4app i3arc i2ari i3arie i4arri iar3t 4i3as ias4c ia4sic iass4 ias6trop +i3at ia4tic ia4toa i4atoo ia2tr iat5ric. i4att ia3tu i4aus ia3v iave4 5iavel +i4avo 4iax3 ia3zi i2b i4b. 2iba ib4as i4bata i4bb 4ibbo 4ibe. i3b4el +ibe4la 2iber ib3era iber4o i4b4es ibe4t i4bia i3bi4d ibid3i ib3ila i4b3in i4bio +ib3it. ibi4ta i4b3ite ib3ito i4bium i3bl 4ibla i4bn i3bo 4ibo. 4i4bol 4ibon +i3br ibra4c 4ibran 2ibri i4bria i4b5rio i4bs i4bul ib3ula ib2un ib1ut ib3uta +ib3ute i4by i4c. 2ica. i4caa ica4ba ica3c 4icaca i3cal i4cald 4icam icap3i +3icapp i3cari i4cast. 4icata. 4icch iccu4 2ice 4icef ice3ro i4cest i3cet 2ich +4ich. i1cha i4chag ichar4 4iche. i3che4n ichen4e ichen5o 4ichi ich3ic ich4i4e ichi4l +ich3in ichi3ni i1ch4o2 i4choi i2chom i4chore. 4ichot i1chr 4icht i3chy 2ici 6icia +4icic i4cic. i3cid4 i3cien i2cif i4cila icillar4 4ic3in4a i2c3ip i5cipi i3cis 4ic1it +2ic4k 4ick. 4icke icker4y ick5l 4i4clo. ic3ly ic1n4 4ico. 4icog. i2cola 4i2c5oli +ico4mat icom4e i6como 4icope ico3ti 4icou 4icoy 2i1cr icre3 4i4cri icro1 2ict +4icta icti2m3 ic4tis ictu2 ic2t3ua 2icu1 4ic1ul ic3ula i3cule ic3ulo i3cult ic3ulu +ic4um ic3uo 3icur 4icylat 2id i4d. idacty4 ida4d i4dai i4dak ida4l i4dam +i4dani i4danu 4idasa idau4 4id3d4 ide1a i2dect id5ed idel4e ideli4a i3den ide4na +id3er. id3era 3idesc ide4se i4detr idewa4 id4g idgel4 idger4 i2d2i i4d3ia i4d3ic. +id3ica idi4d id4ie id3if id4il i3d4im i3dine i4d3ing id3ino i4d3io i4d3i3t id3iu +4id4j id3n 4idni i4dobl ido2l idol3a i4domi i4dones i4dophy id3ow i4dri i4drop +4ids i2du1 i3duc id1ul idu4n id3uo idur4 idw4 i4dyd i2dym ie2 2i4e. +4iebr 4iec. 4ie4ce i3ect 2i2ed i4ed. ie4fe ief5l iego3 4ieh 2iel ie3la +iel4d ieman4 iemp4 2ien ie4na 3ien3at ien4e ien4g ie4n3i i4eno 4ieno. ient4a +ien4tag i3enti4 4iento ien4tr 4ie3p iepra4 i1er i4er' ier4c i4erd 4ier4e i4erg +2ieri i4erly i4ern 4iero 4i4ers 4iert i4erwa i4es. ie3se i1est i3est. 4i3et +ie3ta i4eter i4eton i4et4r ie3ty i4eu 4iev iev3er 2iew ie4we i1ex i3ezo +i2f 2i4f. i3fa ifar3 4ifat 2ife i4f1er ifer4e 4iferi i4ff 4iffe if2fi +if4fia 4iffu i3fi i4fi. i5fia 4ificant i4fice i5fie 4ifil i4fing 4i3fl i3fo +i4fo. iform3i i4ft1 i3fu 4ifug if3uga i5fuge i3fy i5fy. i5fyi 2ig 4ig. +igam4e i4gand 3igarc i4gatori i1ge2 igens4 igen4to i2ger ig3era ig3eren ig3ero i4geta +ig4fe igg4 igh4t ight3e ight3i i2gia ig3i5at i3gib ig1il ig1in 4i3gio i4gios +i2g3it4 ig2l igli4 i3gly ig2n 4ign. ign3ab ig3nat 3ignate ign3er ign3in 4ignm +igno3m i5gnon. i2go2 3i3g4oc i5gon. igon4is ig3o3no i3gop igor3a i4gri i2gu i4guat +i3gu2i ig3ul igulat4 i4g3uo ig1u2r 4i2gy i1h iha4n iheret6 ihil3i 4ihin i4hk +i4hs ihun4 i4hz 2i1i2 4ii. i3id i4is. 2ij ijan4 4ije i4jl i4jn +2ik 4ik. i1ka i3kan 4ike ikin4 i5kin. ik4l ik4w 2il. i1la i4labe +i4lade i4laf i4lana ila4ne ila4p3 ilar2 ila3ra i4laru ila4s i3lat i4lato i5lator. +i4latur 4ild il4du i4le. ilea4 il4ed i3leg 4il3er iles4 i4lest ile4tr i5lev +ilev4er ilh4 il1i i4l3ia ili4al. ili2an il5ias ili6ativ il2ib ili6ca. 4ilie il3ien +i4liki i3line il3ing. il3io ilion4 iliora4 il2is 4il4is. 2ilit il3ita il4ite ili4tur +il3iu 4ilius iliv4 i1l2iz iliza6bi i4l4k 4ilk. 2ill ill3abl ill4e 4ille. ille4i +illi2a illin4 4illio illo4c il4lock il4lust. il4mi 4ilni 4ilob ilo4e 4i4logi ilo4mon +4ilop il1oq il5oquis i3lo2t 4ilp ilpa4 il2ti i1l4u il1v il4y ily4a i4lyra +4im. i4maa i4mace 4imach i4machu i2mag 4imak iman4i i4mano 4imaru i5mat 4imato. +4imav 2ime 4ime. ime3l i2mene imenta5ry i5meriz im5etry imf4 imfer4 4imh im1i +4imi. i4m3ia im4ico im3ida imi5la 4im5ing imin3i imi4nu i6minutio imi5ny imi4on im4i4p +i1mis i4miss im3iti 4i4mity imma3t 4imn4 i3mo imo4ch i4moi i4mola imo4nian imo3no +i4moth i4mout impa4l im4pers. im4pha imput3a 4imr imro4 i2mu 4imu. im3ul 4imw +2in. i1na 4i5na. inab4 4inace i4nach 4inad ina4la inal4iz i4nam ina4mo in4ann +i4narch i4nare i3nari inar4is inar4it in3aug inav4 ina4z 2inb incar3 incel4 4inche +in4cor. in4cr. 4inda 4indee inde4fi inde4l in4dermo 4indl indor4se 6indromis ind4wi 2ine +4ine. in1e3a in3eal in3ear in3eat in5ega i4neit 4inel i3nell ine3m in3emat i1nen +i2n3eo inep4 3ine4ph3 in3er iner4s in4er4v i4nese i2nest i4nesw i1n4et i4neth ine4tr +in3ew in3f4 infat3 in4fin. 1i4ng 4inga ing5ab 4ingbu 4ingd 4inge ing3en. 5ingenu +4inghe 2ingi in2gl 4ingla 2ingle 4ingo ingov4 4ingr 4ingtow 4ingu 4ingy inhag4 +4inhar 4inhol 2i2n1i 4ini. in3ia 4inian 4in3ic i4nic. in4ica. in3in i4ning in3io +iniona4 5i5nisc in3ish in3ist in3itiv i3nitr 4i4n3ity i4n3iu 2ink in4ke4 in4ki in3kl +in4ky 2in3l inlan4 in4nag inname4 4inni inno4m i1no 4ino. i2no4c i4nodon i2nog +i4noge in5ogen. inoi4s inoki4 i4noli i3nom 4inomi i3non4 inos4t 4inot. i4nota i4noti +4inour inow4e in4ri. insati4 in4siani insis4 insist3 4insk 3insu insur5a i4n1t 4int. +4inta in4tee in4ter. inter3e intes3 intest4 4inthi in4thod in4tin in4tres intro3 2inu +inud4 4i3nus 3inv4 4invil i2ny 4i3ny4l3 2io 4io. i1o1a i1o3b i1oc io4cel +4iocu i1od io4dep 4iodic io5dize io5do i1oe ioe4co i1og ioga4 6iographa i3oi +i3ol 4iol. io5late. iol5a5ter io4list 4iolou i1om iomer4y io2n ion3a ion4ac ion4ag +ionar4i4a i2o4ne 4ione. ion3i 4ioni. i3onic ion4it iono4my i3op ior2a iora4bi iora4m +io3rati i4ord io4rit i4orm i3os 4iosi 4ioso io3sp io3sta 4ios4to i1o2t io3ta4 +io3tel iotempo4 io3th iother6my iot1i iot4s io3v iovi4 i3ox3 2ip i3pa 4ipala +ipa4n i4par ip3aro i5part ipat4edn i4pathi i2pe ipe3da iper4ac i4phat 4i1phe 5ipheno +i3pho i4phora iphori4 i4phyo 4ip1i i4pia ip4ic ip3i1e ip3ing i5pinn ipis4t ip3it +i2pl i4plac i3ply ipo4ce 4ipoda i4pode i4pody ipol4i i4pom ipor4 i4poro 4ipot +ipow4 4i4pp ip4pel ipri4e i4pry ip4sal 4i4pt2 ip4tal i2pu ip1ul i3pur 2iq +i1qua iq3uef iquet4 iq1ui 2ir 4ir. i1ra 4i3ra. i4rado i3ral 4iram i4rama +iran4 irassi4 ir4at i3ratio ir4cal ir4ch ir2d ir4do ir3dr ire5ar i1rec irec6trix +i4refu irel4i i4rely i3ren iren4t i4r3er iret4 i4rety irev3o ir3g irhi4 ir1i +i3ri. i4ria ir3ica ir3i3de ir3ido iriga4 iri6gibl ir4im i4rin ir3ing i1r2is ir4ites +ir4ius 5i5r2iz ir2l ir2m ir4mand irm5ativ irm6it ir4ni i1ro i5rog i3ron iro4ny +iro4po irov4 irre4f irre4la irri3 5irrit irru4 4ir2s ir4ty. ir3u3l i5run i3rus +i4russi irv4 ir1y i2s 2i4s. 4isa. 2isab isa4me 4isan i4sandr i3s4ant. isar4i +isas3 4isau isa3ve 2is3c iscar4y is4ces is4cio 4iscot iscov3 4isd i3sec 4i3sep +is3er iser3a is3es ises3t iset4i i3seu 4isex ish1 4ishan 4ishc ish4ch i5shev3 +2ishi isho4 ishon3 is1i 4isib 4is2ic is5ido 4isi4e is3il is4iny 4isio i4sior +isi4p i4sise i4sisi is3i4ta is3itiv is3ito 2isiv 2isk is1l is4la. 4islao 4ismi +ismis6sib 4ismo ismolo6 ismome4 4ismu i3so iso5b is4od is4ol iso3la 4isor is3p +ispan4 is4pec ispen6si is4ph i3sphe is4pi i4spie 4is1q isro4 2is1s 4issa2 4isse +is3s4i 4ista is3tak is4tat 4iste. istem4i is3ten. ist3enc ist4er is3teri i4sth is3t2i +ist3ib 4isticha is4tide. is4tif 4istiu is4tiv ist2l 4is3to istoi4 is4tolic is4tom is3tr +3istry is3tu istur2 is1u3a isub4u i5sul is3w is4we is4y i5syl i3sym i4t. +it2a 4ita. itab4 4itac i4taco i4tag 4itai 4i4tak4 ita4l3i i4taly 4i4tam ita3mi4 +ita4ne i3tani ita4n3o 4itante ita4p i3tar ita3riz itar3y 4i3t4as4 i4tasi i3tat 4itato. +i2te i3tell i3tem3i i3tent i4t3eo 2it1er 4itero it4erp 2i2th 3ithel i4them 4ithi +i4this 4ithmi ith3r 2i2ti 4itia. i4t1ic it3ica it3ici 4itics it3ig i4t3il it1im +iti4n it3ish it3ism i4tisti i4tiu i4tiva itiv3i i4tly i3to 4ito. i4tok 4itol +i6tology i4tom i4toph i4tora itori4d 4itoso itpro4 itr4 i4trame 4itre i4trem i4trep +i2tri 4itric it4ro. 4itropy i4try 4its it4sa it4sy i4t3t4 4itt. 4itta. 4ittae +4itte4 ittel4e 4it5ti itti4t ittu4 i4t1ua i3tud itu4de itu3di3 4itu3e 4itui i4tui. +it1ul itulat6 i3tum i4t3uo 2itur itur4a i4turgy itur4n 1i3ty it4y. 4itya i4tyi +i4tyl i4tyo i4tyr i4tys 4itz it4za 2i1u iuli4e i3um iu2mi 4iu4o 4iupo +4iur i4ush i4usi ius4t 2iv 4iv. 4iva. 4ive i4vel iv3ell iv3en. i4ver. +iv3eri ives4t ivest4i iv1i iv3ia i4vid. ivil2 iv5il. ivi3lis i3vine iv3io ivi4p +4i4vis. iv3ise i2vo 4ivor i4v3oro i4vot iv3v i1w iwan4 i4ww 2ix 4ixe +ix3i ixiv3 ixo2 ixo4d ix4yl 2i1y i4y. i3y4a i4ys i4yy 4iza. 2izab +4izal 4izar iz3ard i4zato 4izd i4zel izi2 iz4ie iz4it izz4 iz5zin 1j +2j. ja2 3ja. jac3u ja4de ja4g jama4 ja4mas jame4s 4jang ja4pon4is jargo4 +jargon3 jas4c jas3p 4jav javar4 jazz3 2jd je2 jeal3 je4b 3jec jectiv6is +jeel4 je3j 4jel. jella4 jel4lo 4jem. jemap4 jem4i jen4u jeop3 2jep jepu4 +4jer. jer4a jer4om jeron4 j4es 4jes. 4jesty jes3u3 jeun4 jew1 jh4v jh4w +j2i2 jil4 jim4p jing4 jink4 4jis 2jj j4je 2jk 4jl. 4jli 2jm +4jn. 4jna jo2 jo4b jo4ce jo4i2 4joie join4tr joli4o jon4a jo4p jo3ra +jos4e jo5sep joss4 jo4su jour4no jo3vi jow4 2jp 2jr 2js 4jt. 4jta +ju4a ju5bi 3judg jui4 4jul ju4le ju4lia. ju4lian. ju4li4u jum2 jump3 3jun +jun4a jun4e jun4gi juni4u jun3k4e jun4u 3jur jurid3 jus4r jus4ter ju4ti juve3 +4jvo 2k. 3k4a. 4k1ab kaha4 3kai kain4i kais4 kak4 3kal2 k4ala 4kalah +ka4ley ka1li ka4lia kal4id ka4lis. kalit4 4kalm kam4e kam4i 1kan ka4na kana4k +kang4w kanon4 kan4ti ka3o kao3l kap4i ka4pl kar4s ka4sa kash4e 5kateri 4kath +ka4thy 4kati ka4tol ka4trine ka5za 4kbe kbin4 4kbl k1c k4cy k1d ke4an +keat4 4k4ed keda4 ke4dr 1kee keel4e 3keep3 ke4ge kegel4 keiz4 kem4i kena4 +ke4n3i ken4ia ken4ti k4enz keper4 ke4pl keple4 k1er. k4era 4kerm ker4ni k4err +ker4si k4esi 3keta keth4 k4e4tr k4evi ke5ya 2kf 4kfe 2kh 4kh. kha4k +khani4 khano4 khay4 khe4da khet4 5khov kho4vi khuz4 k4i. kian4g ki4ato ki4bl +ki4d k1ie 4kier 4ki1es k4iew kil1o3 kilom4 4kil4s k1ily k4im k4in' k4ind +3kind. kin3ema 3kinesi k3iness kin2g king5l king4s k4ingt 3kin4i kin4kly k4inl k4inn +kir2 kis2 k1ish k4ist ki2t ki4ty k4iz k1k2 k1l2 klavi4 kld4 4kles4 +kle4sh 4kley k4lid 4klik k4lio k1m kn2 kne2 kn4i kni4fi 3k2no4 knol4 +knot3 k4nu knur4 1ko ko4cytot ko4hi 3koi4 ko4it kold4i 4kolos kone4 koon4 +koop4 ko3pe kopen4 kop4f ko3ra kor4t kov3s k1p2 kpa4t 4kpo kram4 kre4 +kroo4 krot4 2ks2 k4s. k4sar ks3b k4sco k4shea ksnif4 ks4p 4ks4t ks3v +k1t kt4a kth4 ktom4 1ku ku4a kuch4 ku4dr k4um kun4z ku4o k3up +2k1w kwar4 4kwe 4kwo 2ky kydi4 ky4e 3kylo ky4mi kyp4 ky4pr ky4ri +2l' 4l'o l4's 2l. l2a 3l4a. 5laam la3be 4labeg lab3ic 2labl la5bore +la3bori l4a4bri lab5yr la2c lac3ab 3laceo la4ces 5la3chia lach3r l4aci lack4y 4laco +laco4p lac3t 6lacteric 3lactic 4ladel ladi4e ladi4o. lad5is lado4c 4ladol la4dop la3dy +4laeo laes3 lae4v laf4f la4fi 4lafo 4laga4 la4gan lage4 lag3ell la4geo 4lagine +la4gist 4lag4o 3lah. la4hab laim3a lai4n 4laira laish4 4lakl la3lia 4lalist 4lalt +la3mar lam4bi lam4d la5melli la4met 4lamid lam3or3 4lampu l4an. lan4a 4lanac la5natio +l3ancho l4an2d 3land. 4landin 4laned lanel4 4lanes lan4ic lani4e lan4if lanne4 lano4ch +lans4i lanta4g lan4tr lao4 la5od5 lap3ar 4lapax 4laph la4pl lapla4 laps3i lapu4r +1la2r1 3lar. lar2a la4ran 4larbor 4larct lard4er lar2g lar4ge lar3i la4rine 3l4arm +la4ro. 4larop 4larsh 4larus larynge6 la4sa las4e lask4 lasmi4 las5ph las3ty 1la2t +l3a3tal 4latat la4te 4lateli 4lateriu 4latesh lath3er 4lathi 4latho la4thy 3latia l3atil +latil3i la4tim 4latine l5atine. lat3ini 4latinit 2latis lat3it 4l3ativi 4latom laton4 4l1a3tr +l3atro l3atry lat4ur la4ty 4latya lau4dat laudi4o laun5d launt5 lau3si 2lava la4vato +laver4a lavi4e lav3is 4lawa lax3 4layl. lays4 la2z 4laze lazi4e la4zin 2lb +l4b. l3ba lban4 l3be lber4d lbin4 l3bo l6bous lbun4 2l1c2 l4c. l3ca +lcali4 lcas4 l3ce l3ci lcia4 lci4nab lci6nato lci3tr l4cm l3co lco4n lco3ra +l4cose l4cou l4cs l4ct lcu1 2ld l4d. 4lde lde4ba ldens4 lder4al ld4er4o +l4des ldh4 ldi2 l4dia l4d3ish l4dist l4dit ldiv4 ldivi4 ld3l l4dox l4dry +ld4ti l4dup l2dy 2l2e l4e. le4a4d lea4f 4leano4 le2ar lea4s leas3a least4e +leath3 4leati leator4 4leaz le4bel le4bit l4e4bri 1lec 4lec. 4leca le4che lech3er +l4e4chi lech4w 3lecit 3lect lect4a 3lecula 6lecy 4l4ed. l3edi 4ledl 4ledn le2e +lee4l 4leem l5efact le4gad 3le3gal l3egan le1gi 3lego lego5rize 4legy le4ia lei4c +le4ina leit4e lek4 3lel. 4lelik lem3ati l4emb 4lem4e le4met 3lemic lem5ish 3lemma +lemper4 4lenar. 3lenc lend4w len4e le3nec 4leneu 3leng 4lenga len4gl le5ni5e len3is +le4nite 4lenor 3lent 4lentin 4lentu lentur4 4lenty le3o leob4 leo4ch 3leog le4omi +4leph le3pha le4pi. l4epin lepi4p le4pus l3era l4era. ler4al ler4e leres4 lern4 +l4e1r2o 3lero. le4ron 3lert 3l4es 4les. 4lesb 5lescenc 4lesd les4e 4lesee 4lesg +4lesh 4lesk 4lesl 4lesm 4leso le4sow 4lesr lessar4 les4sen less4i 5lessn 4lestin +4lestit 4lesto 4lesv le3ta 4letag le3thal leth4i 3letic 4leti4e le4tom le4try 3lets +4leui 4lev. 4leva l3evat lev3el le4ven 4levil levis4 levit4e lex3 lexi4an 4lexini +3ley l4ey. 4leyar 4leye. 4leys 4leyvo 2lf l4f' 4lf. l3fa lfani4 l4fant +lfa4ti lf4fia lf3h lfi4e lfilar4 l2fl l4fla l3fo l3fu lfu4ra l4fy 2l1g2 +l4g. l3ga2 lga4m lgan4 lgar3 lgar4y l4gea l4gev lgi2 l2gin lg3ing lgi4u +l3go lg4r l3gu 2l1h 4lha 4l3he lh4j l3ho l4ho. 1l4i. l4iae lian4it +li2ar liar3is libe4l lib3er lib4er. 5libera li3b4i4 2lic l4icata 3licen l4i3che l3icho +li4cic li4cid. 3licio liclin4 l4icn lico4t li4cr lic4te 5lic3ul l3idar l4idas l3idat +li4dea lid3i lidi4as 3lidif 4li4dil 3lidit li4dom l2ie l4ie4b lief4 4liem lie4n +l3ien3a li4ery li1e4s 4lifat li4fe lif4f li4fl lig3am 3ligat lig3ere 2ligib 5ligino +3l4ign lig3nan li3g4o l3igop lig2u l4ihi 4lihu 3l4ik 4likar 4liko lil4i lilit4 +3liloq 4limani. lim4bl limenta5r l4i4mi lim4ic limit5ab limo4g lim4pl l4imu l2in 1lin. +3lina. li4nall li4nant 4linar 4linas li4natu 5lindric 3lin3ea li4nen 4linet 2ling 3lingt +lingto4 3lingu li4nid lin3iz linoi4 linos4 li4nosi 3linq l4ins lin4sh lin4t lint3i +linu4 3liog 4liog. li4ol. lio3r liorat6i 3liot l4ip lipa4t li3pe li4pec lipe4d +4lipha 4lip4i li4pol liptic4 lipu4r li4pus 4liqua 6lique. lir4a 4lirat li5re lir3i +lir4ty 3lis. li4sa. li3sad lisar4 li4sato l4isb 4liseu 2lish 4lishl 4lishn 4lis4p +l4iste lis3ten lis3ter 4listine l4it. 2lita l3itan l3itar lit4c 1l2ite l4iter li3t4er. +4lites 1li4th lith3op 1liti 3litica 3litio 4litiv li4tor l4itr l4itu li4tui 5liturg +2l3ity li4ve liv4ed live3l liv3er lix3 l4iy 4lizin. l2j 2l2k 4lk. l3ka +lka1l l4kat l4kaw lk1er lket4 4lki lk3y. 2l1l2 l4l. llab3o llad4er lladi4o +llai4 lland4 llan4i l4lao llap2 llapu4 llas4ti l3lat ll3b ll3d 4lle l4le. +l3lea l3lec l4led l3l4eg lle4in l3le2l llel3i l3l4em l3len lle4no ll4er lle5r4a +l3lero l5lers. l4lese l3let l4leta l4lete. lle3v ll3f ll3g l4l3h l3lia l3lic +llif5lu l3lig llil4 llim4e llinar4 llin4iz lli4nos l5lio lli4ol llipe4 ll4it l4l3m +l4l3n l3lo l4locke llogu4 llo4mi llopa4 llo4pe l4lov llow4el ll3p l4lr4 l4ls +ll3t l3lu llu3c llumin4 l4lv ll3w l3ly. lly4e lly3g 2l1m l4m. l3ma +l4mab lma4to lm4e l4mes lme4t lm3ie l4mil l4ming l2mis 4l3mo lmo5na lmon4dy +lm4sh lmu2d l2my 2l1n2 4ln4e lnia4 1l4o. lo2a 3load l2ob lo4bal lobi4n +l6o3bl 4lock' 4locky 4locya l2od 3lodic 5lodio l3odr l4odro l2oe loes4 loeti4 +l2of log3a3r l4ogen l3oget 3logia 3logic log4n 1logu logu3i 4logy lohu4 loid4 +loi4t loiz4 4lole lol4i l2om 3lom. 5lomatic lom3er lo3mi lo4mic 3lomit 4lomitic +lo4mona lomul4 lomulti4 l2on2 1lon. lon4e 4loned 1long longer4 lo1n4i 3lonia loni4e +l3onis 4lonoi 2lonyl lood3 4lool looz4 l2op lop3in lopi4t l3opm 4loq. l4ora. +lora4d 4lorc l4orch lor4dy l4orem lore4t lo2rh l4oric lori4e lori4n l3oriz loro3e +loro3m lorometh5 loro3p l2o2s lo4se los3in l5osophic 5losophis 5losophiz l4osophy l2ot lo5tha +loth4i4e lotin4 lo2to 4loton lo2tr l4ott l2ou lou4c lou4de lou3i 4lour. lour4d +4lout lout4r lo2v lo4ve l2ow1 loy4d 4loys 2l1p2 lpa4c l4per l4pes. lpe4t +lp3f 4lph4 l4phant l4phar lpha4t lphe4n lphi6a. lphi4d l4phor lp4i l4pier l4pies +lpi4tal l2ple l3po lp3t lpu4 l4py. 2l1r lre4 lr4i lri4o 4lro 2ls2 +4l4s. lsa4my ls3b l4s4c 4lse lsem4 l4sew lshe3v l4sib lsin4 ls4it ls4k +4l3s4p 4l1s4t4 lstaf4 lsth4 l4stin l4stu 2lt l4t. lta4na l4tans l4tant l4tativ +l4taz l3ten lte4riu l2th l3tha lthy4 lth3y. lti3a lt4ib l3tic l2tie l4tily +ltin4 lti3p ltira6c ltis4 l4tish l4tism l4tist. ltiv2 lt4j lt3l ltm4 l3to +l4tol l4tose ltra4bl ltra3m ltu2r ltur3a ltur3i l2u l4u. 4l3u1a lual4 l4uar +2lub lubi4 l3ubl lub4li lu3br 3luce 4lucel lu3ci luct4 luc5ta 4lucti lu2d +lud5ib 2lue lu1en luf4 lu1i lui4a 4lu3id3 lu1l4 l4um. lum4bl 2lume 4luminic +4luminiu 3lumni 4lumnis 4lumny lun2 lu3na lun3de lun4e 2lunt l3unta luntar3 lu3n4u +lu4ny 4luo luop4 4lur. lu3ra lur4b lur4c 3lu3ro lu3so luss4 lus3t lus4t5i +lutan4 5lutato luth4 lu2tis 4lutiz lutton3 4lu4va 4luyl 2lv 4lva l4vable. l3vag +lvan4 lvar4y l3ven l3vet l5vin. l5vini lv4v 2l1w lw4e lx4a 1l2y l4y. +4lya 3lybd 4ly4bi 2lyc ly4cid ly4cina ly4cra l4y4dom 4lyer l4y2g lygen4 l4yk +4lylo 4lyme ly4mene 4lymo 3lymp4 4lymu lyn2 lyn4c l4yny 4lyo 2lyp l3ypl +ly4poi ly3ra 4lyra. lyr3i lyr4m 2lys 3lyse 4lysi lys4t 3ly4ti ly4tom 4lytr +4lyus l4yx 4lyzate 4lyzato 3lyze l4zg l4zi lzin4 lzo4 l4zy 2m. 1m2a +3m4a. maar4 4maas 4maaz 2m1ab mabe4 ma4bin m4abo mace4t 2mach mache4 ma5chine +mack4ere ma2cl mac1r mac3t mac3u m4ad mad3ic mado4 3mae mae4n 4maep ma2g +magal4 mag3a3z mager4 3magg maggluti6 2mag3i 3magn ma3go 2magog magor4 4magr 4maha +maho4 3m4ai4 maid3e maini4 main4ie 3mak 4maka. 4maku 3mal m6al. mal3ap ma4lat +m4ale 4malek 4malge mal4ib ma3l4in mal5le 4malley malli4 4malloy mal4m ma5lou 4mal2t +mal4ti 4malu 4maly 2mamb man3ag manar4 mana4s 2manat manc2 3manci 3mand ma3nen +ma4nes 4manes. m4ang 5mania man5if mani4l man3it 3mann ma4noi mans4l m4ant ma2nu +maph3r map4pe ma3q m4ar2a marbel3 4mares mar3g mar2i mar4ial 4marif mari4o. mar3it +ma3riz ma5rol mar4shi mar4st 4marty. 4maru mar3v4 mar2y. m4as 3mas. masal4 mas4ce +mas4e ma4sic ma4sor 3mas3t mas4th mas4tl ma3s2u 4masv 3mata 4matal mat4c 3ma3ter +ma4ter. m3ateu ma4this 4mathy ma4tik. m4atin mati4nal 3matio ma3tis 4matod ma2tog 4matogl +ma6toph matopho4 4matopod ma6tosc 4matose 2matou ma2tri ma3tu ma4tura maug4 maus4e max3 +maz4a ma4zl 2mb m4b. 4mba mbal4i mbardi4 mba4t 4mbe mbel3 m4bem m3ber +m4berie mbia4 mbian4 m3bic mbid4 mbi3en m4bies m4bik m2b3ing mbis4 mbi4v mb4l +mblem3a m5blin mbm4 mb4o mbo5na 4mbr mb4sa m3bu mbus3t mbus5ti mbut4 mbys4 +2mc mca4 mc4h mck4 mcma4 mc4o m4da. 4mdo me2 4m4e. meal3 meam4 +me3b 3mech me3co 2m4ed 4med. me4dan 3me3des 3medi med3ic me3die 4medied 4medil +4medis med4it. m5e5dy me3f meg2 3meg3a1 megam4 3m4ei meion4 mel3anc 3melia me5lie +4melik 3melio melli4a mel2t memo3 memor4 1m2en men2a me3nab men3ac men4ag 3mend +me3ne 4meness mene4u 4menh me3nia meno4m menos4 mens4 men4sc mensu3 mensur4 men4sw +3m4ent 4mentac men4tate men2te ment3er me3nu4 me3o meog4 4meon 3meop 4meosi 3meo3t +me3p me4pa meral4i 3merc merd4 merdi4 3mere 4merel mer3et 5mer2g 3meria 3meric +4merici m4eride mer4im mer6ob meroblas6 mer4og mer4ol 4merol. m3eron 4merso m4eru mer5us +4meryv 4mesb 4mesd mes3en 4mes4i mes4n me4s1o mest4 4mesta 4meste 3mesti mestic4 +4mestr 1met1a me4ta. met4abl me4tai 3metal 4me4tar met2as m1e3te me4ten 3meteo m4etes +1meth 4meth. 3metha meth4i 4methr meth6ylam 3metic 4metin me4toe me4ton 4metop 5metre +3m4etri 4metrid 4metris me4tru mew4 me3wa mex4ia 2mf mf4e mfer4o mfoun4 2mg +2mh 3m4i. 1mi3a 3m4ia. mia4m mian3a mianop4 4miar 3mias mi3b m1ica mi5chel +mi4chen4 m3icil micker4 3micro m4id. mid2a m5idal m3idat mi4da4z mid3ic m4idn mi4done +2mie4 m4ient mi1es mif4f 3miga 4miges m4igra mi4la. mi4lag mil4de mi3let mil4h +1m2ili mili4a. mili4al 4milie 4milis m4ilk 3mill milli4e mil4te 4mily mimed4 mime4t +mi4mi. mim5ic mi4mis min2 m4in. mi3na m4ind 3mine. mi3nee m3ineer mi4nei mines4t +m4inia mini4fo 3minio m4i4nit mi3niz min5ne5 mi3no mi1o m4iolo mi4ona 4mioni m4iot +m3ip mi3pe 4mipl miq4 3mir. mir2a mi4ram mi4ri mi4russ m2is 3m4is. mis1a +m4isco mi4see 4mises 2mish mi4si mis5le 1miss 4misso mis4sy. mis3ta mister4 mi4tal +mit2er 4mith m4itic m3itiv mit3iz 1m4itt m4iu m3iv4 mivi4 m2iz 4mko mk4s +2m1l2 m3le m3li mli4n 2m1m2 m3ma mma4da mman2 m4mandab mmar2 mmari4o mma6top +m4md mmeas6ure mme4da mmeli4 mmem3 mme4n m3m4i mmi6nato mmi4p mmis4a mmi4t m4mk +mmoni4a. mmu1 m3mul mmu4ne 2m1n2 m4n' m3na mnar4y mnav3 4mne m4nem m4ner +m2n3in mnon4 mnosper4 1m2o m4o. mo2a 4mochore mo4choro mo4chron mocli4 mo4coo 2mocr +5mocrac 5mocratis 5mocratiz 3mocy 3mo2d mo4d1e mod3ul 4mody. moer4 mo4gena mo4g5e5niz mo4ges +mo4i 4moi. moid4 moig4 moi4t 4moix 4moki mok4s mo3la 4mola. mo3lin4 4moliti +4mollit 4molog. 4mologue mol4or 5moly moma6 4momi 3mon mon2a 4monas. 4monb mon4dia +mo4ne 4monen mon3e3t 4monf mo4niani 4monid. 4monl monni4 mo3noe mon3olo mon3os 4monto +mon4tro mon3u mo4num 4monym moo4s 4moot 4mopau 3mophi 4mophoni mo2r m3or4ab mor3al +mo4rar 4morat mo4rax morbi4 4moredn moreli4 m4org 3moria mo4ries 4morin morit4 m3oriz +mor6iza 4moro mo3ros 5morp m3orrh 3mos 4mosac mos4e mosil4 4mosite 4mosm 4mosor +mo4sp m4ost mo3sta 4mosur mo4sy mo4tes 4mothy 4motis moto2 motor5i m6otropis mot4tle. +moun4te 3mou4s 4mousine mous4se 4mout. mo2v mo4vi movi4e 4moyi 2m1p m4pab mpac4 +mpa4i mpais4 mpan4d mpan3e mpani4a mpa5no m4pantl mpa4nus mpa3rab mpar4te mpa4s m5pa1t +mpa4tr m4paz mpe4dit mpe4l m4pen. m2per. mper6ato mpe3ria m3pet mpe3tr mph2 mphan3g +mphi4m mph4y m4phy. m2pi mp4ic mp3ie mp4ie. m3pig m3pile mpin4 m3pir mp3is +mp4le mp5les m4plev mpoti4 m4pous m4pout mpo4v5 mpress6in mpri4 mprin4 mpro3m mps4es +4mpt mp4ter mp5tu mptuar4 mp4u2 mpug4 mput3ab m4pv m2py mp3y. 2m1r mro4d +2ms2 4m4s. 4m1s4e m4spo m1s4t4 2mt2 m4tis mt4s 1mu muci4 mu4cl 4muel +2mul m4ulc mul4i mul4ler mul4lit 3muls m2ul3t4 multi3 3m4um 3mu1n2 mund4 mun4e +mun4ga. muni4f mun4is m4ur mu3ra mur3d4 mu4re murmu4 3m4us mus3t 3muta muth4i +mu4tis 2m1v 4mvi 2mw mwal4 mw4e 1my 2mya4 myal4i my4an my3c my4cer +my4col. 4myda my4do my1e my4log my4los 4myne my1o 4myr my4ri myr3ia myro4 +mys3 mys4i mys4u my4ti mz4e m4zl n2' 2n. 3n4a. 2nab naba4l n4abase. +4nacen 3n4aceo 4nachl na4cho 4nacif nac4r 2nact 2nad nad4de 3nadia nadi4e nadi4r +3nado. 3naea 4naec 3naem n3aero naes3 naeth4 2nag n4agena n3ager na5go n4agu +n4ah 5nah. 4naigret na4is n4aj nak2 nal4go na3li3a nal3ie 4nalin na4lit 4nalla +4n2alo n5alogic 5nal5ogis 4nalt 3nalysi 4nalysin name4ne na4met n5a3mid n4amme4 4namy. n2an +nanach5 3nance na4nes nan4ic nank4 n4anna nanom4 nan4tes 4nantiz nan4tr 2nap n4aph5o +napi4 na4pos n4apu nar1 3nar. n4ara n2ar3c n5archis nar4di 4naret nar3i 3naria +nar4iac na4rin nar4ite nar4l 4narou narri4 nar3t n4as. n4asa na4sa. nas5c na4sh +3nasi na4sit n4asm. nass4 n2as3t 4nasth 3nastic 1n2at na3ta nat4ab nata4k nata4l +nat4en 3nathem na3tho nat3ici 4natina nati4u n5atomic 5nato5mis 5natomiz na4tro 3natu natu4a +nat3ura nat4u4ran nat4u4rat 2nau 3nau. naud2 nau3di n3augu 3nauti 4nauto nautog4 nav3i +naxa4 3nay n4az 2nb2 n4b. nbak4 n4bd n3be nbeat4 nbes4 nb4l n5bli +n3bu 2n1c n4c. nca2 ncaco4 ncampho4 ncapsul4 ncar3c n4caria n5ceri nc4es n4ces. +n4cev n2ch n4chate nch3er n3chia nchi4ni n3chi4s nchis4es n3cho ncho5a ncho4lin n3chu +n3cib n3cil ncil3a n3cina n3cip n4ck nc4l nclat4 ncle4 n3c4o ncorre4 ncov4er. +nc4r ncre4v n4cs n4ct nc4tad nct4e ncu4ra n4cx n3cy ncy4cli 2n1d n4d. +nd3age n3dal ndama4 nda4na. n2da4r nd3ard n3dea n3d4ec n4ded. ndeform6 n3del ndel4li +nd3enc nd4ens n3denta nde4ra n3deri n3dero ndes5cent nde3t nd3g nd3ho n3d4ia nd5ibi +ndi6cativ n3dice ndic4to n3dic3u ndi4en n3d4if nd3ing n3dio nd4it nd4iu n4div. n4d4j +n2dl n3dler n3do n4dof ndo4mi ndoo4r ndop4 n4dov n4dq n3d4r n4drat n4ds +nd4sia nd4te n3d4u ndu4a. n4duc. nduct4i n4dunc ndus3 n4d4v nd4win nd4y n4dz +n2e 4ne' 2n4e. ne1a n4ea. 5nealo ne4ap n3eari ne4art ne2as ne4ata n3eate +n3eati 3neau ne2b n4ebe nebro4 ne2c n3ecd 4ne2d n4ed. n3edic ned3u neep4 +5neficen n3efici n3efit ne4fr 4negade neg5ativ ne3gr n3egy 1n4ei neid4 3neir4 neis4 +nek4e 4nela ne4let neli4a ne2lig nel3in n4elv n4ely 4nemari nem4ati nemer4y nem4i +n4emia 3ne3mic ne4mog ne4mone n4en. ne2na 4nene 3nent. ne4ny 1ne3o neo4t4 3neph +4nephore ne5phriti n3eq n3era ne3rad nera4l3 nera4m ne3r4as n4erd n4ere ne3rea n3er3g +n4eri 3neric ner5ist ne3rod n4er4ol ner4ri n4ersv ner4vi n4erw 1nes 2n4es. 4nesbo +nes4co 4nesd 4nesec 4nesen 4nesh 4nesm ne4sot 4nesp 2nesq 3n4ess nes3ti nes3tr +4nesv 4neswe n4et. ne3ta ne4tag n3etar netel4 4neter 3net1i ne4ti. 5n4etic 4netie +n4etn ne4toi ne4top n3e3t4r ne4try net4s n4ett 1neu 4neui 3neuro neu4ry. 3neut4 +neva4d nev4e nevers4 4nevi nevo4c nev3ol newal4 news3 n3ex3 nexami4 nexci4 n4ey. +n4eya n4ez 2nf2 n4f. nfalo4 n4fers nfi2 nf4l n5fla nfu3sib 2ng 4n4g. +n2gab ngal4le ngal4li ng4am ngan4i ngar4i ngar4y n3gat ng3c ngd4 nge4a. n3geal +n4ged n1gel n2gen. ngen4er. ngeni2 n3gere n3gero nger4on nge4t ngh4 n3gi3a n3gib4 +ng2ic ngin4 ng3ing n3giu n2g3iz n4gj n4gk4 4ngl n3gli3o n4gm ngn4 ngna4 +ngol4l n4gour n3gr n4gr. n4gs n4gt ngth3 n4gue n3gul ngu4s n4gv n4gw +n2gy n4gz 2n1h2 nha2 n4ha. nhab3 nhabit5an nhag4i nhas4 nhil4l 4nho nhs4 +nhu4me nhun4 n2i 3n4i. 1nia n4iac nia4g 4ni4ap 4niard ni3ba 2nibl n3ic. +n4icc n4ice n4ici n5icil n4ick n4i2co nic3o3t n3ics n4icu nic3ul 3nicula n4icy +nid2 3n4id. n4ida 3nide. n5idine n4idir n4i4do. ni4dob n4idu nie4l ni4et n4ifer +nif2f nif4fi ni4fin n4ifo nift2 ni5fy nig4i n5igmatic n4ii n4ij nik4 ni3ki +n4ila ni4la. ni4lam 3nile n4i3lin n4ility n4illi n4ilo 4nilw n3im nim3ag nima4te +n4ime 4nimea nimi3ta ni3miz n4in. n4ina nindi6c n4ine 3nine. nin4erti ni4net ninvo4c +nio2 n4ioc 2n3ion niona4t nio4r n4ios 1ni1ou n4i2p nipa4 4niple nipo3 nipre4 +3nipu 3nique. n1is n4is. 2n3ism nis4ma. n4ison nis4p nissari4 n3is3te n3istr n4it. +nit3ab n3ital nitar3 nitar4iu nith4 4nith. ni4thi ni3tho 3nition 3nitis. 1ni3tr 3nitro +nit4s ni4ur ni4use 1n4iv 4niv. 3niva ni2van nive4l 4njo nju4ra 2n2k n4k. +4nka n4kal nka4v n4kb 4nke n3kee nk3en. nker4s nk4e4t n4kf n4kh nk3ho +n4kie nk3ines nk2l n4kp n4ks n3ku n4kw n4ky. n3kyl 2n1l2 nlan2 nlan4d5 +nlar2 nlas4t nlau4 4n3le2 nlev3 n3li2 nlis4 nlo2 n3lu nlu3b n3ly 2n1m2 +n3ma n3me nmemo4ra nmensu4 nmercu4 nmin3i nmo2 nmon2 n3mu 2n1n2 n4n. n3na2 +nnaba4 nnait4 nname4n nnan4 nnar4y nna4ti. nnat3u3 nn4e2 n4ne. nne4ce n4necy n5nel +nne4le nnel3i nner4o n3net n4nh n3n4i n4nian nni4cu n4nime n5nin n4nism nnit4 +nni4v nni2va n4niza n4nk n4nl n3no nno4mi n4ns nn4u n3ny nnym4 n2o +3n4o. 4noam no3be nobli4 n4oce no4cer noco4 n4ocon n4ocr 2noc3u n3ocul no2dal +4nodrome 4noem n4oet 2nof no1g 4noga nogam6e nogen4is no2gr 1noi 5noint noi4sa +4nok no2la 4nold4e 4nolei no1li 4no3lit n3olith 4nomac no5mad3 3nom3al 6nomal. 4noman +no5mer. 4nometa no5me6tri 3nomic nom5ina no3mis n3omou 4n3omy. nomyce4 6nomycet no2n3 non4age +non4ar4y noncu4 no4ne 5none. none4a none4s non5f nong4 3nonic 4nonicit non4it n3oniz +4nono nonos5 nonta4 noo4t 2nop n4op. n5ophob n5opht no4phys nop4l 3nop3o3l 4nopolyl +no4pre nopter4o no4rab no4rary norator4 norm4 nor3ma nor4thin no4ry 4nosce nos4ed no4sic +no1sp 4nosph nos3t n6ostr 4notap 4notau 5no4te n3othei no3tice noti4e no3tis noti4t +no3tiz no2to 1nou 4nouk 4nouro 4nout 3nov. nove2 nov3e4l nov4ell 4nover no4vis +2now nowl3 now3s nox3 2n1p2 np4a2 n5par npat3en npa3tr n3pe npecu4li npe4d +nper3 nphenol4 nphi2 nphil3 npi2 npi4t np4l npo3e npoin4 npom4 npre4fa npri4 +npross4 n3ps npub3 n1q n3qu nquil4la n1r2 n4r. n3ra nra4k nras4 nrav3e +n3re1 nre2co nre4com nre3d nre2e nre4lat nres4t nret2 nri4de 4nro nro4b n4r4r +n4r4w 2n1s2 n4s. nsa4na nsan3i 4n4s3b ns4c nsco4 n3scr n4scry ns3d nsde4 +nsec5utiv ns4ed nse2l nse4la ns3elem n5sen. nse4na nsep3 n4ses ns3f n4s3g n3sh +n3si nsi4d nsist3e ns4i3t n4sit. nsi4ta n4site ns4k n2sl ns4lau ns4lay ns1mi +nsmo4 n3so n4soce nso2l nsol3ab nso3na n4sorb nspar3e n3spi2 nspir5ato nspiri4 nspor6ti +nspro4 ns3r ns3s4 ns4t2 n3ste n3su nsu3a nsubmers6 nsu5li nsur4ab n4suret n4sute +ns3v nsw4 n3swe n4sz 2nt 4n4t. 4nta nta4be nt3abi n4tage. nta4gen ntagi4u +ntag4n ntago3 n3tai nta4le n4talka ntam3i nta4na nt3anc ntan4go ntan4i4 n3tar n4tarc +ntar4ia. ntar4is n3tas n5tatio n6tativ n1te n3tee nte4l3 nt4en n4ten. n3tena nt2er +n2ter. n3tera nter5c nter3es nt4eri n6terman. ntero2 n3tes. nte4t ntev4 nt3g n1th2 +nth4e n4thel n3thi n4this n4thodo n3ti ntiar4 nti3di n4tie. nti3eg nti2er n4ties +nti4fi n4tily nti4nal n4tines n4ting nt4ingt nti4nou ntin3ue nti3p nti4pate ntip4s nti1r +ntiradi6c ntis4 nti3sc n4tish n4tism nt4ist n4tite nti4us n4tiz n3to nto4cr ntomi4 +n5ton ntoni4e nton4is nt4r ntrac5ta ntrar2 ntrion4 n4tro. ntro3s n4trose ntro3v n3try +nt4sa nt4si nt4so n3twin nt4z n1u1a n4ua. nuan4 nu6atel 1n4uc nu4ch nuch3i +3nucl nu4de nud4i nudo4 nu4e nuf4 n3ufa nu1i n3uin nu4is4 3nuk null4 +nul4lar n3ulo 1num n4um. num4bly 4numen 2numi nu4mis. nu4na 1nunc nuniform6 n1uo +nu4p 4nup. nur2 n4ura nur3b nur4l 4nury 1n2us 3nus. nus4c nu4th nuti4l +2n1v2 n4v. n3va nva5les nvar3 n3ve2 nvel6ope. nvermi4 nvers6a 4n3v4i nvict4u nvig1 +n4vt 2n1w nwi4 n3wo n2x nx3i n2y 1ny. 4ny2a n4y2c 3nych3i nyer4 +3nyin n4yl nyla6m ny4li 3nym. 3nym3ic 4n3ymo nyth4 2n1z2 nza4l nzi4a n4zit +n4zk o'2 o'4c o'4d o'4f 2o. oa2 2o1a. o3ab oab6o o3ace oac4er +oach5er o5act oa4d1 o3ag1 oag4r o4ag4y o3a5les oalesc6 o1an oan4er oan3i 4oann +oa6no oa4p o3app oar2 oar3i oar4s oas4t oat5er o2b 4o4b. o3ba 4oba. +ob3abi o4bad. obadil4 obah4 oba4li o4balo 4o4bb4 ob4bes o3bedi obe3li4 obe4lia o3ben +o3bi obil2 obiliar4 o4bing 3obin3i obi4no o4bins obit4e 3o4bj objectiv6 o3b4la o4blem +oble4s obor4 o3bot o3br o4bre o4bs4 ob1ul o4c. o3ca o4cag oca4la o4calu +o4cat. o4catel o4cativ oc4cas. occul4 o3ce 4ocer o4c3er3o o4cess. o1ch ochei4o o3chem3 +o3chet o4chic ochine4 ochle3 o4chop o4chorou o4chosp o4chrois o5chrom ochron4 och3t oci4ab +ocid4 oci4l o4cile 2ocio ocio4n o4cip oc4k oc4l4 o4clam o3co o4cod ocoe4 +ocolor4 ocommuni6 4oconi oco4py oco4q o4cosa oc3rac ocran4 oc5ratis ocre3a oc4ter oc4tu. +oc3ul oc3ume oc3uo o2cura oc3urat ocurato6 ocus5si o3cuti o3cy 4o4d. od2a oda4g +o2dal. o4dam o3dan o4dant ode2 o3dec odec3a odel4s ode4mat o4den. o4depe oder4i +odern3 o4des. o4desis o3dia o4d1ic od4ico odidac4 odi6dacti od1if odif4i o4diga o3dio +odio4d o3d4iu od4j o4doa odoac4 o4doe o2doli o4dolo o4dom odom4it o2domo o4dop +odor3i odor3o o4dosc 3o3dou o4dov o4droma o4dromo odro4s odu2 o4duct. od3ula odwil4 +o4e1a oe1i2 oe5ia oe1l o1e3le o3emp o3enc oendo6c oe3n4i o4eno o3enz oeod4 +o1er o4er4a o3erc oer4i oe5rotic o4er4u o4eso o4ess4 o2et oetas5 o3ethy 4o3et1i +oeti4u oet4s o1ev oev3e o3ex o2f2 o3fa ofa4n o3fe of3fe of3fi offi4e +of4fl of4fo 4offr off3s ofi2 o3fic ofi3ci of3it3 o4fle o3fo o3fu o4ful +o4fy 4og. o2ga o4gal o3game og3amo o4gano og3a3ri o3gas 2ogat og5atori og5atory +o1ge 4oge. oge4l o5gen. ogen4ism o4g3eno o3geo2 o4ges. 3ogeti o4gh 4ogic 1ogis +o3gist og1it 1ogiz o1g2l o2gli o4glie o3glo ogn4 og4nac og4ne o2go o4go. +o4gog o5gol o3goni o4gonis og3ony 3ogous 4ographa o6gress. ogrol4 2o2gu 1ogy 4ogyn4 +2ogyr4 o1h2 o3ha2 o4ham. o3he ohe4a o4hg o4hin o4hm o4hn o3ho oho4l1 +4ohs 4o3hu o4hv ohypo4 2oi o4i. oian4 o1ic. oi4ce oi3ch o4ico o4id. +oi2d3ec oid4er 4oides oid4h oid4ic oid5is oi4do oi3es oig2 oi3ki oi4l oil3a +oile4t oil3i oi2n o3inc oino4 oin4ti o4ir o4is. ois4c o4isi 4o5ism o5isti +oit2 o4it. o3ite. oit4i o4i4ty o4jv 2ok ok4am o1ken ok4es ok4ev o3kina +o3kine o4kn 5okous ok4sa ok4u okur4ti oky4m ol4' o4l. o1la ola4be ola4br +o4lac olack4 o4lalis o4lami o3lan olan4i o4lapa o3lar3 o4larc olar6is. o4larl o4lars +o3las3 olas4c olass4 o2lat ol3atr 4olc olch4 o4l2d ol4d1e o4le. ole1a oleast4 +ole4cr ol4e4d o3lei o3len ole4nod o4l3er o3let o3leu o4l2f ol4fe olf4fi 4olg +o3li. o1lia o5liat ol1ic o3lice ol3ich ol5ick ol3ida o3lidi oli4e oli4f ol3igo +4olik o3lilo o3line ol3ing. o3lini o3li3o o4lip 4ol3ish o3lism o1lit ol3ita o3lit4e +o3lith oliv4e 4olk o4ll olla4gi 4oll4e ol3l4i ol4lingl ollin4i olli4no 4olln ollo4p +ol3ly olmak4e o3lo. ol6ob o5log. ol3oge o4logist ol4ogr o2l3ogy o5lomb o3lomi o3lon. +ol1or olor3is olo4ry 1o3lou o4lour o4lp o4l1s4 ol2t olt5is o1lu ol3ub o4luce +4o2lun3 ol3unt o3lus o4luy 4ol2v ol4va olv3er. olx4 o2ly ol3y3a ol3yc ol3yh +4o4lyl ol3yp o4l1ys4 2om. o4mab o2mac om3achy o2mada o4madh omad3i o4mah o2mal +omal2i o4malle o4malo o4many o3mas oma4tik o4maton ombil4 om4bl ombo4r om4bry ombus3 +o2me 4omely om3ena omene4 omen4i ome3no o3meo om3er5a ome4ri om3eriz o3mest o3me4ta +o4meter o3meth om5e5tris o4metry ome3w o3mia om1ic 4omic. 4omica om3ici o3mid o3mim +omi4mi om1in om5ina. om3inen omin4ic. 4omins omi4se o4mish o4missa o3mist o3miu o1miz +om3l omma6to ommut5ab omni4f omno3 o3m4o omo4geni o6mometr o4monas o4monid o4mony o4mopa +o4mophon omo3th o4mp om3pil omp4l ompress6 ompro3 omp4te om4sh om4ti omy3 omy4t +omz4 on1 o4n. 4ona. 2onab onabor4 on4ace onactu6 on3age on4agen ona4nat o3nanc +ona4ne ona4po onapos6 o5narchia o5narchic 4onard onar4i4a. on4asm o3nasti on3b onback4 on3c +oncer4 on4chat 3oncila 3oncile oncu4m ond4d ond3ent ondur4 ondu5ra o2ne one4ag 4o3neal +one4at one4gat o3nei o3nemat o3neo on3er 2o4nes o5nesi on3est o4net2 o3neur o4nev +on3ey on5fl 4o4ng onge2 onger4o on2gi ong5is onglu3 on3go ongrel3 on3h o3n4ia +o4n3ic on3if on4ife on3ing o1ni1o o3nis. o4n3ish on4iti on3ito o1n4iu on3key onk4i +onk4s 2on3l on3m onma4tu onmerce4 onn4 onni4e onni2v on3oc ono4ce on4ocu on5oh +ono2l o4nol. onoma4t on3omis on3omo o4n3omy ono4phy onopo3 onopter4 6onora onos4 o4nost +onosti4 on3osy on3p4 onpart4i onpre4p onpre6se on3r 4onra onre4fo onre4la ons4 onsa4n +onsel4 onse4n onsid3 4onsk onspir5at ontag4 onta4l ontam3 ontana4 ont2i onti2e onti4f +4ontin onti4s ontortu4 on4tros on2u o3nuc o4nume onuti4 o4n3v onva5le on3w 4onymu +o3nys onza4 2oo2 ood1 ood3i ooe4l oo3ey oo4f oof3i oo3i oo4id ook1 +ook3ie o4ol. oo4lan ooly4 4oom1 oo4n3i oo4pe oop4er' oop3i oo4pl oo4ri. oos3in +oo3sp oos4t o4ot. ootch4i oot3er oo4ti ooz3i o2p o4p. o3pac 4opaeu op3ag4 +o4pagu o3pai o3pa4l o3pan opar6o o3patho op3athy 3o3pau o3pe3a o3pec o4pec. ope3di +opeg4 o3pei o3pell o3pen o4peng op1er 3opera oper4a. 4operag opes4t o3pex op4fr +o1ph oph4e ophe4l opheli4 o3phen o5pher. o5phia o3phie oph5ilis oph3ora o3phori oph3oro +o3phr 4ophrasi o4piab op3ic o4p3ing o3pini o1pis o3pit opi4th o3piu o3piz o3pl +3oplec o4p3li4 o4plo 3opme op3oda o4pody opog4e o3poi 4opol. opo4lat op3olis opoly3 +opo5ly. opol5ym o3pom o3pon o4ponis o4pophy o4popy o3por o4posit o4posp o3pou oppe4 +oppress4 o3pr opra4 opress4 4opresso oprin4 o4prod opro6f op3rol ops4 4ops. opse4 +op3si opsi3a o4pt opter4oi opu1 op1ul o1py. o4pylo o1q oqu4 o5qua 4oque. +o4r. o2ra o3ra. 4orac o4race. o4raceo o3rad ora4da orade4 o4rades o3rae o4rag +or3age 4orah 4o3rai 4o4rak4 ora4l o4ralist o5r4alit o3ram ora4ma or3ange o3rar o4rar. +orargy4 o3ras o4rasm orati4 ora4tis ora4tivi o5rav oravi4a. o3rax orber4 or3bi orbi4e +orbi4f o4rc orca4 or3ches orch4i4er 4orchu 4ord. or4dal ordeli4 or4dit o3re1a orea4l +o4rear o3rece or3eig ore4lat oreli4a o3rell oremon6 o4rence o3rens o4rent o4renz o3resc +o3resis or3est. ores4tr o4reth o3retic ore4v 4org. orga6na. 2orge 2orgi or4gis o3rhi +o2rhy o3ri. 4o3r4ia orib2 o2r1ic 4oric. or4ico o4rid. o4rida ori4dea ori3di o4ridl +o3rie ori4en. ori4f 4orifa ori5ge o3rigi o1ril o5rill o4r3ing o4rinu o1rio o4rip +o2ris or3ish orit4e o4rity o3riu or2m or4mater orm4e ormen4 ormini4 orm3is 4ormu +or4ner orni4a or4n3ie 4orno oro3a o3roc oro3et o4rogl o3roi or4on. oro3n4e oro3ph +2or4os o3rota orote4 oro4ti or3oug orphy5 orpo3 or3r4 orrob3 o4r2s orsa4l or4sen. +ors3in orst4 or3ste o4rt ort5ab or5tent ort3er. orth3e or3th4i or4tier. or4tres or4ty. +o1ru o4r3ul o4rv or3w o1ry ory4da ory4o os2 o4s. os3ab o4sace. os4ad +os4a4g o4salin o4sam os4an o4sanne os4ar osari4o o3sau2 os4ce o4schi os4ciat o1sco +o2s3cul os3e3cu 4osek osem4 os4f osgen4 4os4h o5sho os4ie osi4g osil4l o3sim +osina4 o4si4nan o3sine os3ing os3itiv os3ito o4situ osk4e os3m o3so. o4sod os5om. +o2sop4 os5ophis os3ophy os4or o4soth 4osov os4pa o3spec osper4mi os3pero ospirit4 os3sa +os4sai oss3c ossem4 ossil3 ossin4 oss3t osta4l os3tate os4tax oste3a o5stem os4tend. +os4thy osti4b os3tile ost3m os4tome 4ostomo os4tor os3tu ostu4m os4tut o1s4ty o3su +o4sue osulphu6 osur3g os3we o1sy4 osymme4 o2syne osyphi4 o4t. ot2a 4otag otam4e +o2tan otan4i ot5any ota4p o3tar ota5riz o4tasi o3tat o3tax ote2 o1tei o3teli2 +o3ten o4tenl o4tenoi otepa4 o2ter ot3er. ot4er4a oter6ism o3tes o4testa otes4tiv otet4 +oth5ecat oth3er. o4theral o4thou o2ti ot1ic o4tic. ot5icis o3tif o3til o4ting. o3tini +oti4po o3tist o3tit otiv4is o4t3l oto5f4 o4tog. otoion4 o2tom o5toma ot3o3mis ot3omiz +ot3omy o5tone otone4g oton4g o4tonus o4topy otor5is o4toro o3tra o2tri o6trophe o5trophi +o4trophy o4tropo otru4d o4try ot5ryo o4tt 4otte ottra4 otu3b oturi4e o4ty. ot1yl +oty3le o2u2 4oua oua4c oub4 ou5bl oubt3 ou4ce ouch3i ou4den ou3ette 4ouga +4ouge oug4h ough4t o4ui ou3is 4oul oul4d ou3m 4oun2 oun4cy ound3i oun4dry +ounk4 oun4sl oun3ter oun4ti ou4p oupha4 2our our3ag our4an our4c our4de our1i +our3is our4no. our3ous our4th o4us1 ou4se 4ousia ou4so ous4p ous4to ous4tr out1 +outch2 outre4 4ou3v ou4verne ouw4 o4ux o1v o5vak o3var ovar4y ov4ella o2ven +ove5na oven4i over3e overgent6 over3i o3v4ers ove4t ovet5o o2vi o3via o3vip o3vis +o4visa ov4it 3o3viz o4vk 4o3v4o ovol4t o4vr ov4y o2w 2ow. ow5al owa4n +o3way ow3di owd3l o4w1e owe4l ow3er owg4 ow3i o5witz. 4owo owof4 o4w3r +ows4a ow3sh ow3y ox3a oxam4 oxa4n oxcom4 oxe3m ox3i 4oxidas ox5im ox4on. +o4xu ox3y oxyl3a 3oxys 2oy oy1a oy4ad oycot4 oy4da oysi4 o4zal o4zene +oz2i o3zo1 oz4s 4p's 2p. 1p2a pa4ba pabys4 pa2c pa4ca pa4ce pach4e +pac3it 4pac4r pac4u 3pae pagan3 page4 pag4n p4agulu pagy4 pah4 p4ai pain2 +pain4t pais4t paja4 pa4k4i pa2l pal4ab pal5an pald4 p4ale palet4 3p4ali pa4lik +pal3in p4all p4aloi pan4a panc4 pan3el pan4gler pa4nia pa4nic pan5ici pani4o pan4is +panni4e pan5op pan4ti paot4 3pap pa3pa pa3pe papel4 pa4pet 4paph papi4 3paq +p4ar. par1a 5paras p5aratio par4chi par4din p4a4re 3paren pa3riet 4parina par3iso 5parit +4paro pa3roc pa3rol parot4ic p3arou 5parox 4partee 4pasm pas3qui 3pass pat4edl pa5tel +pa4ters 3path. 3pathic 3pathol 4pa3thy 3p4atic pa4tin pa4toi 3patr patro4 pau2l4 3paus +3pave pavi4e pa4z 2pb pbel4 p4ble 4pbr 2p1c pcervi4 2pd 1pe2 4pe. +4peab pe4ak 3pean pear4l pe4ba. pecas4 4pecha pe3cie pecti4v 2p4ed 4ped. pe4dar +peda4t pe4date 3pede pedes3t 3pedi pe4di. ped3im pe4dio pe5dol 4pee4d pe3f pefoun4 +peg4i 4peha pei2 3pe3ia peip4 peir4 pek4 peki4 4pelet 4pelik pelli4e pe4lo +pel4ter pel4tr pe4nan p4enc4 pend3e pe3nia pen4ic pen4is pen3i3t p4enn 5penny pens4e +pentar4i pen4tho pe3nu 3pep pe4pe pep4i pep3s per3a p4era. 4peralta 4perand percen4 +pere4t 3per3g 3peri pe3rial per3ic per3ig per3il per3im per3in per3ios3 periot4 per3it +4perl. perlu6n p4erm per4mism per3n pernatu6 6persedel 4persedy persh4 pe3rus per3v p2es +pes4car pes4th pes3ti p4et 3pet. 3petalo pe3ten pe4tio pet5iola pe3tra pe4tra. pet4rog. +pe4try 3peu peu3t 4pev 2pex3 3pexi 2pf pfal4 2pg 4ph. pha4co phag2 +3phage. 3phagia phak4 5phalia 3phalic ph5a5lis ph3alit 3phant 4phantu 3p4har phare4 4phareu +phar3is 4phars 3phas 3phat 4phe. 4phea 4phed phe2dr 4phelio 3phem 4phep 4pheret +ph4es 4phese 3phet 4phet. 4phets 4phial phi4b phi4di 3phil. 3phile 3philia 3philic +phi3lis ph5ilism phi4ma phi4n ph5iol 3phis 4phiste 4phistop 4phis4tr phi3th 3phiz phl4 +phle4 4phli 5phloe 1pho 3phob 4phobl 4phobo ph5omo 3phon phon4e 4pho3n4o ph5onou +4phony 3phore 4phori. 3phoria 3phoric 4phorn 3phos 3pho3t4 4photy 4phox 3phra 4phrasi +3phre ph3ro3d phros4 ph3t phu3i phu4ra 3phus 3phy phyc4 4phyg phy3la phy3le +phyl4i 4phyly phyr4 phyro4 4physa 4physis 4physit 4phytou p2i 3pia pi4ag pia4n4 +4pianu p3ic. pi6cable pi4ceo p4ici pi4cie pi4cil p4icl picom4 p4i4cr pi4cy. pid4e +pi3der pid4io 3p4idit p4idol p4idur 3p4ie4c pi1en p4ieno pier4 pi1es pi4ete pi3ez +pif4 pi4fl pi3geo p3iglo pigni4 p3igram p4ii p4ik p6ilatory pi4lik pil3ing pi3lo +pi4mol pinc4 pin3d4 pin4ery pi4net p4ini 3pinio pink3 pi3no p4int pin4ta. 3pi3o +4pioc pi4ole pion4a 4piony p4i2p pi4pag pi4ped pi4perin pi4phor pip3i pipis4 piq4 +p4ir pir3ic piri4ti pir4y 2pis p4is. 3pisc piscar4 4piscope pis4p pistem4 pis3th +3pisti pis4tr pi5tab pi4te pit2er pi4tl pi4to 3pit3om 4pitomic pi5tou pit4r pittel4 +3pitu pi4ty pi4v piza4 p3izo 2p1k 1p2l2 2pl. 3p4la2 pla4co 4placu 4plad +pla3g planc4e 4pland plan5et 4planos 4plap plar4 plas3te 4plasy plat3in plau3s 5ple. +ple4a4 p4lec 3pled plee4 3ple3g2 ple4ga plenar4 4plene. p4lent pleo4c ple4ri 4ples +plev3 4plev. 3plex 4pley pl4i 3p4lie 4plig 4plik pli4nan 4plit 4plj plo4d +4plof 4plog 4plol plum4be plu2mi plur4 ply4m 2p1m 2p1n p2neu 4pno 1p2o2 +poad4 po4cer pochlo6 4pocri pocrin6 3pod. 4po3da4 4podes po3di 3podia 5podic. 4podis +5podiu 4po3do po4dos po4dot po3dy 4pody. podyna4 3poe po4e. poe5i poendo6 po3e4t1 +poet3i po3ge poge4ny po3gl pohepa4 po4i 3poi3e poi3k poin4t po3ken pok4ier 3p4ol. +po3la po4lam pold4 po4les 4poli. polian4 4polis polit2 3polita p3o3liz poll4 pollin4 +4pologa 4pologia 4pologu po5loni po4l3y poly3s 3pomo po6mology pomp4 pon4ac pond3en po3nen +pon4g 3poni po4nia 4ponin. 4ponist 4ponite ponti4 4pony 4popau po4phy 4pophyt pop4l +popla4 p3ople poploi4 pop1u 4popy. po3r4a po4rade 4poree po4res p4ori po4rif po5rife +por4it por5ten 4porto por4tre por4ty 3pos pos3a pos5edl 4posem pos3in 4posio pos3it. +4posph pos3s pos5tasi pos4th 4postol pos4tom 3pota 4potace po3te poth5eca 3potheo poth5es +3poti poti4e po4tor potri4 poun4d3 3pour 4pousl po4ve po4w3 pow4n pox4a 2p1p2 +p4p' 4pp. 4ppa ppal4 ppara4t ppar3e 4ppe ppeli4 ppend6ant ppe4s p4pes. ppet4i +ppe4tr pph4 4p3p4i 4pp4l 4ppo ppo4d ppoin4 ppo5site 4ppr ppro4c 4ppu p4pv +1pr2 4pr. prac3 4prae prai4 pral4 pra4ni praorbi4 4prava 4praw pre1 prec4 +3preci pre5co pre3e pre4ene pre4fac pre3i pre2j prel4 pre3le prem4 pre4mis pre3p +pre4p. preph4 pre4posi pres4o 3press pres4sag pres4u pre3t4r p4ri. pri4b 4prico pri4cy +pri2e pri4es 2prima p5riman4 prin2 pring3 prin6kler pri4nod prin4t pri4s pris3o pri4val +4privat pri4z pro4bl prob5le p4roci 4prodo pro3e pro3i pro6ject. pro3l2 prola4m prolo2 +prolo6gis promp4 pro5no pro4pis propu4 pro1r pro4sp pross4i pro5sto pro1t prov5al provo4 +4prox. pru4c prun4 pru3r 2ps2 4p4s. ps3ab p4sal4m psa4m p4sb ps4est p1sh +p2sib psi4f psi2n ps3ing 4p1s4t p4sv p1sy. 3psyc 2p1t 4p4t. p2tan pt3ana +ptas4 p5tat 4pte pt3ed pt2er pter6ol pter4om p3t2i p4tib pti4f pti1m p4tin +pt3ing pt4is ptiv6ism 4ptl pto4mato p4tru p3tu ptur3a pt4y 1pu pu3a 4pub. +pu3be pub3l pue4 pueri4 puf4 pu4ga pu3gi pugli4 pu4gr pu5iss p1ula pulei4 +p4uli. 4puma pu2mi p4un2 pu4n3is 5punt pupi4 puppe4 pu1ra pu4ram puran4 pur3c +pu1ri 4purim pu4rism pu4rist. puri3t puru3 3pus pu4sio pus3t 3put. 3pute pu4to +4pv. p4va 4pvi 2p1w py4al p4ye py3el pyg4ia. 4pyla 4pylit py1o py4s +pyxi4 2q. 4qaz qi4b 4qq. q4to qu2 2quab q3uabl 4qua3m 3quatic qua3v +4que. 4quelic 3queo 4querr 3ques ques4s 3quet. qu4h qui3a 4quiem q4uin 3quin. +quinar4y 3quip 4quipa 6quipoise q2uis qui4sa 2quita quiv1 4quiv. qui4ve 4quivok 4quivoq +qu4o2 q4wa r2' 4r's 2r. r2a. 2rab raba4r rab4be. ra4bidi ra4bis ra3b4u +r4ac. ra4ca. r4acar racas4s ra3che ra3chi ra4chide 5rachn r3achu r2aci rac3ic 4racid. +4racki 4racl 4racot r4act2a rac4tan r2ad ra4dan radapt4 ra1di r4adic ra3dis r4adism +rado4 4rador ra3dr ra4dul 4rady3 r4afe r4agino 4ragon ra3g4r ragra4 ra4gro r4ah. +4rainer ra3ist r4ak ra5k4l 2ral rala4z r4alite r4allu ra4l3og r4a4lu r4alys r4amba +ram5bl ramel3i 4ramer r4a4mete r2ami 5ramida r3a3midi 6ramini 4ramis ra4mit r4amu ran2 +ranar4y r4and ran3di ran4dies ran4din 4randr ran4ge rang5eri ran4gui r4a3nia ran4if ra3nio +rani4to ran3n 3rannic r3anniz ranopi4 rans3el ran4sur ran4tr ran3ty ran1u ra4ny 3raphe +4raphed 4raphes 3raphis 3r4aphy ra3pis r4apn 4rapody r4apsi 4rapte rap5ul ra3py r4ara +4rarc rar4chat rar6chist rar3ef 4rarg r4ariu 4rarl r2as. ra4sal rasca4 r4ased ra3seo +ra3si 4r4asia r4asin ras4p ras4sie 6rasticho r4as4u rat4en4 rat4er3 ra4tid ra4tin. ra4tivis +r4atiz 2rato ra4toc 4ratom r4atus raud3u raugh4 raus4 raux4 rave2 rav3el ra4ver +rav3er. raver4sa ravet4 rav3it rawa4k rax3 r4axe 4raxel ra5zen razi4 4razzi rb2 +r4b. 4rba rb3ab rbal3a rbar2 rbarba4 r3bea rbe2l rbel3iz rbe4ri rber4n r4bes +r3bic r4bicide rbicy4 r3bid rbi4fi r2bing rb3ing. rbit4 r4bles rb5less. r4bn r3b4o +rbo3liz rbo4rac rbo6real. rbrat4 r3bu rbulk4y rbu3ri rbut4t 2r1c2 r4c. r3ca rca4b +r4canto rcap3i rcat6as r4cea r4ced r5cede r3cel rcelo4 r4cem rcen4ta rcep4te r3cera +rcer4eb r4cest r4cf 4r2ch2 r3cha r4ch3er. rcher4o r3chest r3chet r3chi rchid4 rch3m +r3cho r3ci r5cib rci3c r4ck rcle4 r3co r4cog rcollec4 rcor4i rcor4n4 r4cq +r4c3t rc4te r3c4u rcu2m3 rcuti4 2rd r4d' r4d. r4dal. r5dam r2dan rd4ancy +rde2c rdec3o3 r3del rdeli4a rdel4li rde4mo rdeni4 rdepend6a rder4or r1di r3dia rdi4en +r3dio rd3ise r4d3ism rdit4e r3diu rdi4vo rd3iz rdli4l r4dm r4dn r4dop rdo4sa +rdo5ta r4ds r3d4u r2e 4r4e. 4reab re3add re3adm 4re3ado re1al 3reali re1an +4rearm reas3i re4ast reast6e reas5y rea4th r6ebrate. rebu4 recas4 re3co4r re2cre rec3rea +1rect 4rectc 4rectd 4rectex rec6trix. re4cus4 2r4ed 4red. red2e rede4m re2dic red3ica +re4dit 4reditam re2dol redoni4 4reem re5endo ref4 ref5era ref5f refu2 4reful re6fuse. +4reg. reg3im regis3 reg4l reg5n 4rego re4gol re4gory re1i2 rein3a re4ist. reit4er. +rek4 re4lati re5latin re5latio re3lea re5len4 4relet re4ley rel3ish re4lude re6ludin 4rely. +re3mat r4emen re4mene re5mic remi4e re4mif 4remous r3emp r4en' r4en. 3rena. 4renai +re4nar renatu4 r4enb r4ene ren4eq 4renes r4eni re4nif r4eno ren3ov r4ens ren4tag +r4ente 5renthes ren4tist 4renz. re3o reo4e 2reot reo4tr re3pa repen4 rep3it 4replei +reposito6 rep5roba re3quit rer4 r3er. rerat4e r4ere rerec3o reren4 r4eri r4eroo res5ag +resar4i resel4 4resh r4esi res4im resin3 res4m re3spe res4see ress3ib res6so. res4to +re5stric res4try re3ta re5tabu retal3 3retar re3tel re5tem re3ten ret4er re4ters re3th +4rethy re4tic. ret2r re3tra ret3ro re3tu re3u2p 4reux re1v rev3ale revic2 rex3 +rexa4 r3exe r3ext re4za 2rf2 r4fab r4fer. rfer4ent r4fie rfi4l rflo4 rfo3ra +rfu2 r4fv r4fy 2r1g2 4r4g. r3g4a r4gab r4gag4 rgans4 rga4s r2ge2 rge3m +r3gen r3geo r3gery r3get rgia4 rg4im r2gi2n rg3ing rgini4 rg4l rglar4y r4gn +r3go rgon3is rgon3iz rgo4p rgo4t r4gret r4gual rguer4 r4gues rgu4mi 4rh. rha4b +rhag4o rhas4 rhe3al rhel4 rhen4ic rhepa4 rhe4um rh4i 4rhil rhi3z rhod4 rhon4i +rhu4me rhumer4 rhy2 rhya4 2rhyd r4hym 3rhyt 1r4i. ria4ch 4riad ria4da ri2ag +3riah 1rial 4rialisa 4rialla ri3a4m riam4e ri3an rian4it ri4ano ri3ar 4riat. 2riatr +2riba rib3al ri4bel ribe4r rib3er. rib3i r4ibo ribra4 r4ib2u r4icc ricente4 ri4chi +2rici ricid5a 4riciu ri4cles r4i4clo ri4coc r4icol ri6com r4icop ri4cy. 4ridae ri4dean +r3i3dec 3r4idic 3ridio 4r4idiu ri4doph r4i4ed rie4f ri3e4l ri1en 3rienc 4rientee ri3er +ries4 3rietal 2riev 4r4ifican ri5fy ri2g rigen4t rig3er righ4 rigi4l 3rigin 4rigin. +ri3gl ri3i ri3ka ril2 4ril. ri1li riliter6 riliza6b ril6let. rilli2 rilli4u 4rillo4 +ri4lo. ri3loc r4ima. 5riman4d r4imin rim6inan rim3it r4in. r2i3na r4inch rindi4a rin4dy +rin4e rine4p ring5hal 4ringn rin4io rin6kler. r4in4o ri4nodo ri4nou rint5er. r4inth rin4ti +4rinus ri3o2 r4iola. r6iolate r4ion. rion4is r4ior 4riosov rio4t1 riot3o ri2p ripho4 +riphthon6 ri4phy riple6g rip5lica ri4pol4 ri4pur ri3q r3irr ris4c 4risch ris5en 4risiu +5risiv riso4p ris4p 4risp. r4iss r2ist rister4 risti4ch ri2t ri3tal 4rites ri5tes. +ri4tiat rit3ic ri4tist r4itos rit4s ritur4 rit4y r4iup r4i2v ri3val riv5ativ riv3el +riven4 riv3er riv3et 4rix riy4 2riz ri4ze riz4zer r4ji 2r2k r4k. rka4n +r5kat rk1er r3ket r3kin. r5kins 4rkp rkpa4 rkt4 r1l2 r4l. rlan4di rlan4t +rlas4 r3le r4le. r4led r4ler r4lest r4leto rle4tr r4levi r4leye r4leyv 4rli +rl4in rl3ish r4lk4 r3lo rlunar4 rlus4 r1m r4m. 4rma rm3ab rmace4 r4maes +r4mald r4malg r4mallo r3man. rmaph3 r4mater. rma6toc rma4tog rma4top rm5atory rme3at rme3c +rm5edl rme4la r3men r2mer r4mest rm4et rm3h 4rmi r3m2ic r3mid2 r2ming rmini4f +rm4i4p rmi4tia rm4iv rm3l r4mn r3mo rmoe3 rmo4rie r3mu r5myl rmyster4 r4n. +r1na r4nabl rna4cl r3nad rna4l rnal4li r4nanc r4naro rnar6y rnat3u r3nau rnau4t +4rne r3nea r4nee rne4g r3ne4l rneli4 r2ner r4n3er. r4nesb r3nest r3net r3ney +4rnh r1ni r3nia r2n3ib r3nic r4nies r2n3in rn4io rn3ist r3n4it r4nite r2niz +r4nk r1no rnop4 r4nove rnt4 r1n2u r4nup r2ny ro3al r4oan ro4an. roar3 +rob3ab r4obe. ro4bile ro4bin rob5ing 4robiu ro3bl r6obla ro4ble rob5lem rob3or roc4e +roce4l ro4chos r2oci rocio4 4rocit ro1cr rocre3 r2od ro4dan roden4 r4odi ro3dis +3rodit r4oed roe3l 6roetha rof3f ro5fil roge4a rogen3i ro4geu rog4i 4roglu r4ogy +ro1ic 3roica roi5der rok4e rola4mi 4roles ro1li4 rollo4 ro3ly ro5lyse r4ome. ro3mel +rom2i romi4na romonta4 rom4p romp4t ron2 ro1na ro3nau rone4g ron4em ron4er r3one4t3 +ron4gr r2oni ron4ism ro3nist ron4ten r4onti r4oo rook4s 3room. roo4n ro4o4t 3root. +r4opae ro5par roparie4 ro3pel 4ropia ro5pin. ro3pis ro3po 5ropolita ro4posi 3ropous r4ops +4ropsi ro3py 4roq ro5rati rorato4 rore4b 4rors r2os ros4a ro4san. ro4sann ro1sc +ro5shi rosi4e ro4sot ros3per ros4s ros4te ro4sy. r2ot rotam4 rote4l rot4er4 5roteri +4rotesi rotes4ti ro4thes ro4tic rot3id4 4ro3tis ro4tonu rot3s rot4tag roturi4 rot4y4 ro4u +rou3b r4ousi 4rouss. rous4t ro2v rov5al. rov3el rov5en. ro4vo4c rox3 4rox. 4roxi +ro3zen rozi4 2r1p2 rpass6i r3pedo rpentar4 r4per. rpe4ti rph2 rphy5r rp4i r2p3ing +rp5ing. rp4l rpla4s rploi4 r4pn rpo3r rpo4ri rpo4s rpos4t rpre4te rpri4e rpro4m +rp4s rp3t2 rpu4ris r1q rqu4 rques4 2r1r2 r4r. 4r3r4a rr4e rre4co rrec4tit +rre4for rre4fu rre4i r2reo rre4pa rresol6 rre4th rrev3o rrh4 rrhe3a rrhon4 r3ri +rri2a rric3u rri4en rri4o rris4te rritual6 r4rk r4rm r4rn r3ro rrob3o rro4da +rrog4 rro4l rrol4l rron4 rror3i r4rs r3ru rrubi4 rru3g rru4p rrur4 r4rv +r3ry 2r1s2 4r4s. rs3ab r3sal rsal4t rsar4ia. rs3b rs4c rs3d 4r2se r3se4a +r3sec rse3cu rsel4 r3sen rse4no rse4ph rser4 rs4es. rse4u r3se3v rsever6at r3sey +r3sh r4shie r4shy r2sib r3sic4 rsica4 rs3ing rsis4 rsist6 r3s4it r2sk4 r3ski +r3so2 rson3at rspo4 4rs4t rst4e r3su rsu5an rsuggest6 rs3v 2rt 4r4t. 4rta +rt5abi r4tage. r3tar rtar3i r4tase r3tat 4r2te r3tea r3teb r4ted r3tee r3te4l +r3tem r3tere r3teri r3terl r3tes4 r3tex r4tf rth4a r4thei rth4erly rth2i rth4in +rtho4gr r4thors rthusi4 r3thy rt1ib r3tic r4ties r3tif rtil2 rti3lis r4tily r4tines +r4ting r3tins rt4inv r4tipl r4tism r4tist. r4tistr r3tit rt4j r4tles rt5let r4tly +r3to r4toma r4topl rto4te r4tress r4troo r4ts rt4sho r3tu rtub4 rtur4be r3twi +rtyr3i r2u2 ru3a ruant4 ru3be ru3bi ru3ci ru4cin ru3e2l rue4li ru3en r4ug +ru3ga ru3id ru3in r4uk ru3ma rum4bi rum5bl ru3me ru3mi 4rumn rum4ph run4e +run4s run4t ru3o rup2 3rupt ru3ra rur4e ru3ri r4us rushing6 3rusp ru3ta +rut5is 4rutz r1v r4v. rva4d rvato6ry r2ve rv4el r3ven rven3i r3ves rves4t +r3vet r3vey 4rvi r5vi5en r4vies r3vil r3vin. rvi4p rvisi4 rviso6 rvis4u 4rvy +r1w r4w. 4r3wa rwet4l r3wi 4rxe rx4y ry1a rya4t ry4di r2y2g ryg3i3 +4rylas ryllo4 ry4loc ry4lyl ry3ne 5rynga r5ynx ry1o ryopi4 ry2p ry4ph rys4e +rys4i ry4so rys4ton ry3te rytel4 ryth4i 3rythro 6rythrops rz2 4rzu 2s. 1sa +3s4a. 2s1ab sa4bat sab4o 3sacch sa3che sa4cl s4acr sa3cral sacros4 s3act s4adda +s4ade sa4dom s4age sa4gi sag4n s4ah4 saha4 3sai sail3 4saim 4saise 3s4ak +sa4lar sal4at s4a4le sal4id sa3lie s4alin sali6na. 4salind sa3line sal4ish sal3iv 4salmi +sal4mon. salti4e sal4ty sa3ma sambi4 sa4men 4sami sa4mo sa4my. 3s4an. sa4n5at 3sanc +3sand san4di san4dy san4gl sanhe4 san4in san3it 4sanite san4tr sa4n4u s4aph sap4i +sa3pie s4ar. sar4a sar4ce sard4 4sarea. sar4gu sar4iae sar4ios 4sarm sa3ro sar2y +s4as. sa4si sas3s4 3s2at sa3ta sa4tir 4satl satra4 sat1u 3saur s4ava sava4g +sa4vel sa4v3i2 sa3vo4 4savu 5saw. 3say 2sb s4b. s3ba sban4 s3be sbehav6 +sb4j s3bo sbor3o 4s3bu s2c2 4s4c. sc4a scag4 scal4d sca5len sca4lig sca4ly +scan4t sca4p sca4r scar3ab scar4c scar2f scar4p scas4 s1ce s4ced s4cene s4cen4i +scerp5 scet3 sch4 2sch. s4cha. s4chal s4che s5cheat schil5l s4cho s3cib scic4ulu +s4cio. s4cion sci3p4 s4cist scit4 sci5ta sc4l4 scle1 scler4 4scly 4sco. scocar4 +scof4 4scog sco4le 4scom 1scop 3scope 3scopic 4scopis 4sco3py s4coto scov3e sc4r +scra4 scro4 4scrys 2scue 2s3cula scu4riu scu4ru 2s1d s4d. s3da s2e 4s4e. +3se2a. sead4 seak4 sear4 seas4 3seat se4aw secer4 se3cl se2co secon4 3sect +sec3ul se4cy 2se2d s4ed. sed3en sedil4 sed3im s3edn 3s4ee 2sef4 sefa4 s4e2g +seg4n seg1r 2seh se4hen 3se2i 4seik sek4 3sel. se4la. se4lagi s3eleme selemen4 +selen4 4seles se5leu 3s4elf sel4ic seli4e 4seline 1sell 5selle. 4sellen 2sely4 sem1 +sem4a semain4 semal4 se3man se5mati sem5b 3sembl 2sem4e semer4 3sem3i3 se4mi. sem4ic. +semi5p semis4 semit4is sem4m sem4or 1sen senar4y sen5ato 2senc 4sene sen4h 3s4eni +sen6ic. 3seno se4nol se4nou 3sens sen4ti. 4sentis 4sents s4e2p sep3a se4pal sepa3r +se4pho sepho4r 3sept se3q ser2 2s3er. sera4d se5raphic ser3at s4erd ser4e 3s4eri +se3ria ser3ic 3s4erl sermon3 se3rol 4ser3p s4err s4ers 1sert 4sertico 4sertl s4e5ru4 +3serv 5servab 4servas serv3er 4ser3vo 2ses s3es. se4sa s4esc ses4o ses3q 3sess +s3est. 3s4et 4seta 4seterr seti4 4seto 4se4tr s4eu 3seur 3seus 3seve sev3en +sevi4 4sewo 3s4ex 4sexp 1sey 2sf2 s4f. s3fe sfea3 s3fi2 s3fo 2s1g2 +4sga s3gr s2h 4s4h. 3sha. 3shad shad5i shad3o sha4ga sha4ko sh4al sha4man. +sh4ap shar2 sharmo3 sharmon4 sharp3 4s4hc sh4chi shdraw4 shea4 4shead s4hed sheel4 +4shei s5heim shel4li 4shen shep3 4sh3es 5shev3e she3vi s4hf s4hi 3shi. shic4 +4sh3ier 4shies shim4i 4sh3ines sh4ino sh3i2o 3shi4p 1shir s4hk 4sh1l 4shm shmi4 +4shn4 1sho2 sh4od 4shol shoot3 sho4p sho4r 4shors short3 s4hp s4hr shriv4er +4s4ht 5shug 4shum 4s4hw s4hy shys4 1si 3s4i. 3si2a2 s4ia. si3ac s4iaca +4siad s4ian3 si3b siber4 si3ca 2sicc s4ich sicil4 sicili4 sico4t 3sicu sic3ul +si2d 3side. si4dec sidel4 side4n s3ident sid3er 3sidera s2ie 3s4ie. sie4n si4era +2si1es 4sies. siev4e si3f si4fe siga4 3sigh 3signal 3signed 5signi 4sih siha4 +s4ij sik4i 3sil. si3la 4silar sil4e siler4 si2li sili4ciu sil3i4e 4silin. 4silisc +4silisk sil3iz 4sillu sil4ty 2si5ly s2im 2sima s4imac s3imal sime4ne sim4ply 2s1in +3sin. 3sina sina4m 4si4nant 4sind 3sine. 4sing s3ing. sin4gan s4ingh sin3gle s3ingly +s4ingst s4ingt s4ini sin3if sin4in sini4s sin4it s4inn si4nou 4sins sin4th 4sinth. +sinus5 3sio2 4siod sio3p 4sioru 3sip si4pr s4i2r sir3ou 3s2is sis4a 4sish +sis4p sist3en 4sisth 2s2it si3ta si4tab 3sitio si5to sito4rie sit4s 3situ 4situs +s3ity s4iu 3siv siv3i si2z s2k 2s4k. s4kala ske4 4skee skel3e sk4et +s4kil ski4r s4kl sk4v sky3 sl2 s4l. sla2 slam3 slan4t s4laug 3s2lav +slav3er s4le. slen3 4s3let 2sley sli2 3s4lip sli4v sl4l 2slo 2slu2 s3luc +2sm2 s4m. sma2 sma3g s3man sman4n smel4 s3mer s1mic smi4no s3mis smis4sa +3smith smo2 s4mo4k smold4 s4moo smo4t smoth3 smu2 4smui smut3ab s4my sn2 +4s4n. s4nal sna4p snatu4 s1ne sne4f snel4 s4ni4 snif2 snive4 snoo4 s4nou +1so soa4 so3b 4soc. 4socc 4socea 2so2ch so3ci soci3o 4soct 4socu sodro4 +3soe soer4 soev3 s2o2g sogam6e 3soh 4sois sol2 3sol. solal4 so3lat 6solativ +so4lato sold4 sol3di so2li so3lic sol5id. so3lil 4soliti s4olo s4o6lutiv so4luto 3solv +3so2m so3ma s4ome. s4omel s4omen som4i 3s2on so3nan son4ar sond4a soni4e 4sonm +sonni4 so2no soo4t so4ped soper4 s4opha so4phe 3sophic so6phism s3ophiz sop4i so4po +sor2 sor4b sor3c 4sorci sor3d 4soret 4sorg4 so1ri so6riate 4sorit s4orn sor4ta +3sory 3sos sosi4 4sosm 4so3t4er soter6is soth4i sot4s sout4 south3 4sova so2ve +sover3 so3vi 4sowen 2sox s2p 4s4p. spal4l spa4ni span5ic spar3en spato4 spavi4 +s4pb sp4e 3s4pea s4pec3u s4ped s4pee4 spel4l spen4g spens4 4speo spe4r 3s4perm +sper4min sper4mis sper4on s3perou s6persede sph4 s3pha s4phe s5phem sphen4 spher4o s3pho +s4pi. sp4ic spi4cy 4spid spi3de s4pie 4spiec 4spier spi4f s4pil2 spi4li s4pin +sp3ing spion4 s4pis s4pli s4ply s4pn s4pom s4pon spon2d 3spons spoo4 1spor +4spora. 3spori 4sporou spor4tie spro4c spu2 s4pum sput3ab s4py s4q. s3quer squin4 +squit4 2s1r s4r. s4ram sre4c sre2p s4ri. s4ro. sro4b sr4t 2ss s4s. +s4sab s4sais s3sal s3san ssap4 ssar4t s4sc ssect4ib s1sel s3semb ssem4ic s1ses +ssev3 s2s3ho ss2i ssi4a s2sibl ssico4 ss4id s2sie ss3ies ssil3i ss3ingl s3sini +ssir4 s3s4it ssi4us s4s3l ssman4 s4s1n s3so sso4le sso3na ssoni4 sso6riat ssor4t +sso4ru s4sov sspel4 s4spo4 s3su ss3w ssy4r5 s2t 4s4t. st2a2 s4tad staffi4 +4stag. stame4 s4tan. stand3 s4tani sta4p staph3 s4tas. s4tasia 3s4tat. 3s4tatic stat3u +4staur s4taxi st3c ste2 4ste. 3stead ste3at s4ted s4te4g s4teles stel4ic st3ence +sten3i s3tenin ste4no sten3ot ster4na. stern5iz s4terr 4stet. stew5a 2s4tf 2s1th s4tha +s3the s4thea s4them s4thex sth4i sth4l stho4l stholi4 s4thou s4thyo stia4 s4tib +s3tic s5tica 3stick 2s3tid s4tie stif4 s3tifi s3tify sti4g3i 5stigmi s4tih s3tima +3s4timu sti3na s4ting st3ing. s3tini s4tipu 3s4tir s3tis s4tisp 4stl s3tled s4tli +4s4tm stmen4t s4tn4 4sto. stoba4 4stoe s4tof s4togn stoi4a s4tok stol4e stom3ar +3s4tome. 4stomo s3tomy st4on 4ston. 3stone 4stonp sto4pi sto2r s5tor. sto3ral 4storat +s4torb storbi4 s4tord s4tore s4torg s4torm s4toss s4tota stot4in 2stow s4tp st6pra +st2r 4str. stra4l5ia strep3 s4tride s4trol. s4trop. 4stro5phe strot4 stroth4 3stroy 3struc +st1s4 stti4 s4tu2d s3tul s3tuo s4tup s4tur. stur2b 4sture 4s4tw 4stya 3s4tyl +styl4ic s4tyr 1su2 s4u. su3ab su3al su5ant su4b3 succi4na 3sud sudo4 suf3 +sug3ar su5ic su3in sui4t3 3s4ul sul4te 4sulto 3sum sumer4 sun4a sunam4 suni4t +4suno s4u3o su3p su4per. supra3 4surani su3rat sur4d 4sureth sur4gy sur3v s2us3 +3s4us. sus4a 4sush sus4i sus4y 4suter sut4s 4suy su3z 2s1v s4v. s4var +svel4 4s3vi svil4 s4viz s4vp s2w2 s4w. swam4p sw4e sweat3 s4wee swel4 +swell3i 3swer 4s5wic swiv3 2swo sy2b syb5a5 sy4bi 3s4yl syl3l syl4p 1sym +sym4i 3symm sy4mond 1sy2n3 4syn. syph3i syr2 sy4ro 3sy4s3 s2z 4sz. s4z4a +sz4i 4szk 4t's 2t. 1ta 3t4a. 4taa 2tab t4abas ta4ber tabi4a tab3li +5tab5olis tab3u 3taceo tachi4 tach3yp 4tacid ta5cis tac3it ta3cl 4tacol 4tacon t4ad +ta4dl 3tae1 4taeb tae3r2 6taerist taf4fer taf4fr ta2g tage2 t4agn tago3n4 t4ah +3tah. 3tai. 3tail tai5lor 4tainers 4tainf talem4 ta4len ta4lic 4talie ta4ling. ta3lini +taliv4 tal4k 4talkal tal6lan t2alli t4alloc t4allot talo4g t4alp 4taly. t4ameris tam4ie +ta4mis4 4tamm t2an t3anal tanan4 ta4nat 2tanc tan4ce tan2d tand3a ta4nes t4ang +tan4gui 4tani. 3tan5ic tani4e ta4nin tan4iz ta4nom ta4nou 4tansc 4tansi tan4tan. 2tap +ta4pa t4ape t4aph. ta4pi t4app t2a2r2 t4ar. ta4ran taran4ti 4tarct 3t4ar4d tar3g +targu4 3tari tar3ie tar4is. tar4ism tar4ius tark4i tar3n tar4te 4tarth tarvel4 3tary +4taryt 3t4as. tas4c 3tasm tassem4 tas4sie tas4t t2asta 3tastas 4tasth ta3sy ta5tar +t4ath ta4the t4ati 4tatica 3tatiz ta4toc ta4tol ta4tos 4tatrop tat4ta ta4tu 4tatun +4tauc tau4m tavan4 tave4s tawa4 taw5n4 tax3 taxim4 tazo4l 2tb2 4tb. t4bili +tb4l t3bu 2tc tcau4 t3ce 4tch1 tche4 tch3eri tchet4ti tch3i t4chl t4cho +tc4i tci4t t1cr 2t1d2 tdev4 4t4e. 3teac teach3 3te1an 4teat te3ato 3teau +3tebr 1tec te4can te3ce te3chi 3techn t3e3chu 4te4col 3tect 2t1ed tee4l tee3pl +t4eer. tefi4 teg2 te3gi 3tegic teg4n t3egor te4gri teg3um teher4 te2i tei4n +te4k t2el 3tel. 3teleg tel3eo 3telep teler4 4teless tel3ev teli4e tel4lab 3telle +4tello. tel4o 4tely. te2m t4ema 4temen 3tem3iz temp4 tempt3i 4tenac. 3tenan ten3ant +t3enat t4enci 3tend ten4d3a 3tene. 4tenes te4ni te5nia ten3in te4no. te4n4or 3tens4 +4tens. 5tensi ten4tag ten4tee 3tenti ten4tie t4enu ten3ur 4tenus 4teny 3te3o teob4 +4teocr teo4r1 teorbi4 tep4i te4pl 1ter ter5an 3terb 3terc terci4 t4e4re ter5ec +3tered ter4enti ter3est tere4v 3ter5f 4teri. 3te3ria 5terie. ter5ine t4ering 3te3rio ter4is. +ter3ist 3te3riu 4terj. 4terjum t2erl 3t4erm ter4mor 5ternity ter3o teroge6no ter4oma tero2s +ter4os. 3terp t4erpe 3terr 3ters ter3t terte4 3ter3v tervar4i 1t4es 3tesc te2si +tes3im tes4o 3tesq 4tess. test3ab tes5tam 4testan tes3tat 4testr tes5tu 4tesv te4th +3teti 4teto tet1r 3teu2 teuc4 teur3i teu3t te3ve tev4i tewom4 3tex. texam4 +texami4 2tf2 tfal4 4t3fu 2t1g2 4tg. 4t3ga 4t3ge2 tgen3 tgeni4a t2h 4th. +5thaemi tha4lat thal5m tha4lo tha3no thar3g 5thargic 5thart thatch4e 4thau thaz4 4thead +th3eas theat4e 3theci 4theg 3the1i 4theid 4thelb the3m 4the4mo 1then 3theni the4ol. +4thep 3thera 5there. 3therea 4thereg th3erf 3theria th3erin 3therm th3ern th3ery th4es +the4sh thes3p 3thet 4theta thet4e 4thetec th3e3ter 4theth 4theto 4thet4y 3theu 4thexa +th4ey 2thf 4thh 3thiaz 4thica 4thina thin2g 3think 3thi3o thion4 thiop4 3this +4thisc 3thiz 2th3l 4thm thn4 1tho 3thodic 4thof tho4la 4thole tholi4a thol4ic. +5tholica 5tholicis 5tholiciz 5thologis 5thology thon2 4t3hoo th3opo 4thore thor3o 4thorse tho2t +4thour 4thouse 4thov 1thr thral4l thre4 thren4 4throd. thro4n thron3i 4ths 1thu +4thum4 3thus thy4b th1yl3 3thyo 3thyro th2ys 1ti 3ti. 3t4i2a 4tiam. tia4r +ti3ari 2ti3b tib5ia ti4bit ti4biu 4t1ibl 2tic t4icac ti4cas tich3i 3ticia ti4cil +3ticit 4tick 3ticl 3tico 4ticoen 4tict 3tic3u 4ticuf 4ticut tid2 4tidae ti2dal +3tide. ti3ego 3tien tier4i ti1es 4ties. ti3f 3tif. 3ti4fe tif4f tight4y 3t4i2gi +tig3i5a 4tigm t4igr 3tigu ti4j 3tik tik4e 4tilb 3tilen 3til2i 4tilik til6ise. +tilit4 tili4tu til6ize. t4illary til4lit 4tillu t4iln ti3lob tim2 ti3ma 3timab tim3b +3time timet4a ti4mete 3timo timon4i tim3u 4timul 2tin 3t4in. 5ti3nad 3tine. 3tined +t4ingb ting4e tin4gi 4tingl 4tingn tin4gr 5tingu 3tinic t4init tin4j ti4nose 4tinsk +t4in4t 5tinus t4invi 3tio2 4tio3la 4tiolu 4tipas. ti4pater ti3pe ti6peda ti3ph ti4pho +ti3pl ti4pod ti4pot tipri4 tip4sa 4tipul t4iq 4tir. 3tire tiren4 ti4ret tir2i +5tir3ic tir3in 4tiris 4tiriz 3tis. tisa4m ti3san tis4c 4tisec tiser4 2t1isf tish4c +4tishm tisi4 tis4l tiso4p ti3s4p 4tispu tisso4 t2ist tistal4 3tisti 4tistici tis4tr +ti3su ti3sy t2it ti3ta tita4n 4titc tit4e t4itia 3tition tit4is ti3tl tit4li +ti4tol ti3tr 3t4iu 3tiv ti3v2a ti4v3is ti4voc t3i3zen t4jan tj4e tju4 t1k +tk4i4 4tky 2t1l2 4t4l. 4tla t4lal tlan2 tland3 tl4e 3t4le. 3tled. 4tlee +3tlem 4tless 4tley 4tlie 4tlik tlil4 2t1m 4tma 4tm4e 4tmo tmos5p 2t1n +4tn' 4tn4a tna4si 4tne tnton4 1t2o 3to. toas4 toat4 3to3b toba4l to4be. +3toca 3tocr to3crat 3tode 4todu toe4a to4ed 4toest tof4i 3tog 4togly 4togne +4togo 4toh. 4tohm 3toid toi4di toile4 2tok tok4l 4toko t5okou 4to3ky tol3em +tolici4 tolo4n 3tom. 4tomal to4mall tomar3 to4matis to4matiz to4matop 3tome 4tomen tome4r +2tomi 3t4o4mic 5tomic. 5tomica t3omist tomoto4 4tomou tom4s tomu4 2tomy ton2 t4on. +5tona4l to5nalit toneast4 tone4ga to5net 3tonic ton4io 6tonish. 6tonishm tonni4 tonsi4 to2ny +tooe4 4toor to3pa 4topau 4tope. 3toph 4tophel 4topoe to5py 4topy. 3tor 5to5ratio +torbi4t 4tordi to4rea 4torer 4torga to1ri tori4de tori4en tor3iz 4torm. torpo4 torth4 +to3ry 3tos tos4e to3sp 4tosph tos4s tostel4 3tot 4tota. to3tem to3the to2to +totro4 totu4 4toua 4tound. tour4a tovar4 4tovis 4towah 3tow4n 5town. tows4 3tox3 +tox5i 2t1p2 tpeli4 tpelli4 tph4 tpi4 tport4 4tpr t6pran tpre4 1tr2 4t4r. +4tra' 3tra. tracas4 tra3ch t4racid 4tradd tra2ga 4tragalu t4rago 4tragu 3tral t4rame +4tramen tra3mi t4ranc t4rand 3trans 4trans. trans3a t4rapt t4rar 4trarch. trar6chis tras4 +tra5ven 4travi4o4 t4razz t2r4e 3tre. tre4ad 4treal treci4 t4reg tre4i t4re2m tre4ma +2treo tre2p 4treph trep3o3n 5tresc t4ri. 3t2ri3a 4triate. 3t2rib 4trib. trib3a tri4be +3t4rice t5richa 3tricia t4rid. 3t2rie 4trij t4rill trilli4 4trime 2trimo t4rin trinar4 +trion4a t4rios tri4ph tri4pu t2ris trisylla6 t2rit trith4 tri4tia trit3ur t4riu 3trix +triza4b trob4 tro3e trof4i t4rogeny trogo4 t6rograp tro4i tron4e tron4g tron3i 4trony +4troom t4roph 4trophy. 3tropic 4tropis tropos4 4t3ropou 2t3ropy t4ror 4tros. tro3sp 3trot +troth4e trous4e t4rox 4truc tru4de tru4e 4trug tru3i tru5si t4ruv 3try. 2ts2 +4t4s. t4sa. tsan4 4ts3b ts4c t4schl ts4e tsel4 4tsf t1sh t4shor ts4i +t3sky ts3m tsot4 t1s4p 4t1s4t4 tsta4 t4sug4 t4suk t4sus tsut4 ts3v 4tsy +t4sy. t4syn4 2t1t2 t4t' 4t4t. 4t3ta ttak4 ttar4iu t4tb t3ted t4teme ttend3 +tte4r t4tes. t4teso t4tg 4t3ti tti5a tti2d tti4la t5tingl t4tins t4tite tt4j +t4tk t3t4l t4tm4 t4tn tto2n ttori4 ttra4m ttrib3 t4try t4ts ttu4o ttu4p +ttur3 1tu tu1a tuag4 t6ualiser t6ualizer tub2 tu3b4e tu4bel tu3bu 4tuc. tuca4 +tu4des tu2di tud3ie tu3di3n tud3y 2tue t3u3en t4uf4 3tu3i3 tuil4 tu4is tuit4 +2tu1l 4tuln 3tum. 4tumb 3tumi tump3 tun4 tund4 tu4ne tu3nic tun5in tunk4 +tuo2 4tup. tu6rabl tura4m tu6rativ 3turb tur4ber 3ture 4turet4 tur4f 5turgic 3turi +tu3rie tur3is tur3iz tur3o turre4 4turt turti4 3t4us tuss4 tu4ta tu4val tuy4e +2t1v 2tw2 4twa t4wain twee4n 3twine twir4 twis4 twist5 4two twor6thil 4twy +txi4 1ty2 4tya 4tye tyers4 4tyf ty3i t3y3lat tyle4u t3ymo ty4mol. 4tyoc +3typ typo4t 4typu t4ys 4tysc 4tyu 4tyw 2t2z tz4e tzg4 tz4il 4t4zl +tzo4 tzs4 2u. ua2 ua3b 4uac uad1 uadi4 uaf4 uag4i uain2 uaint3 +u1al ual4a ua3ma ua4mas ua4mu ua3na uanan4 u4ane u4a3p uar3an 4uar4d u4are +uarri4an uar3te u1at uat4edn ua4tr 4uau uay4a u2b1 ub2a ubb4 ub5bl ub3c4 +ub3d ubde2 u4be. u4bele u3b4er u5beri ubi4as u3bic u4bin4g 4u4bis u3b4it ubi5ta +ubl4 ub3li ub3m ubor3 ubor4a ub3p u3bri u4bro 4ubs4 u4b2u ub4ul u5bulat +ub4y 2uc u3ca 4ucah ucar4 3ucat ucate4 ucay4 uc3c uccum4 4uce u4cep +u3chu4 uc1ib u3cif ucig4 uci4p u3c2it u4c4k3 4uc4l ucle3 u3co uco3p u1cr +uc4rac uc6ratize uct4a uc4te u1cu ucuro4 ucy4 u4cy. uda3i u4dam u3dan u4dax +ud3d4 u3den u4dene u4dep ud3er. ud4er4a uder4s udev4 udg3eo udge4t u1di u2dian +ud2ib udic4e 4udiciab u2die ud3ied u3dim udi3ni u3dino u3dio u2dis4 ud3ish ud4it +udi4u u3do3 udop4 u4dru u2du ud3ule u2dy 4udz ue4a ueb4 uebe4 u4ed +ue4gia uehon4 ue2li ue4lia u4elo uel4p uen4ce u4ene u4eni u4eno4 uere4 ueri4l +uer2r uer4y u4es2 ues4th ues3tr uet2 ue4tr 2u2f2 4uf. u3fa 4ufa. 3ufac +4uff uff3ab uff3ing uf3fl uf5fle uf4i u3f4l u4flo uf4r u3f4u 2ug u3gal +4ugao ugar4i u3gat u4gh ug4ha ugh4es ugh3i ught2 ugh3te 4ugi ugi4e ugli4a +ugmen4 ug4ne 4u3go u4gout ugre4 u3gu u4gul ugz4 u3ha uhe3 uh4s ui2 +4ui. ui4a. ui4ab ui3al ui3a4n ui4at uiber4 ui4bu u2ic ui4de uid3i 4uidit +ui3e ui4er uie4ti uig2 u2il ui3la uil4d u4ile uil3iz uil4lo. uil2t3 ui3nar +uine4a uin4ty uin4u4 ui3o 4uip ui3po 4uiq 4uir uirel4 uir4ite uirre4 uis2 +u4is. ui4sat uiset4 uis3in u5issa uis4tr ui4tab ui4tr uitz4 u4iv ujer4 u4jt +2uk u1ka 4uke ukem4 u3kh 4ul. u3l4a ula4ca. u4lai 6ularis. 4ulb ul4bl +ul3c 4ulca 4ulchra ul4e 4u3lea 4u5lei uleit4 ulei4u u3len 4uleo u4les u3let +4uleu u4ley 4ulf ulfa4t ul2ger ul2gi ulg3in ul4gy u1li 4uli4a ulian4i u3lic +ul4ie4 uli4m u4lina ul3ing ulin3i ul5ish u3l4it ul4iu 4ull ul4labi ul4larb ul4lard +ul4ler. ull4i ullian4 ul4lite ul4loc ullo4d ul4low uln4 u3l4o 4ulok ulo4mi ulon4 +uloni4 4ulp ulpha4 ul4pie ulpi4ta ul4py 4uls 4ult ult5ant ulti3l u1l4u 4ulu. +ulu4n ul3v ulw4 4uly4 u5ly. u4m. um3ab u5mac u4mag u2mam uma5ro uma4s +u3mat uma6top 4umba um4bie um2bin u1m2e 3umell u3men umen4s u4mer. u6mer6ic. u1mi +u2mic umid3 u3mig u2ming umi3ni umin4is u4mism. um4nis u3mo umoni4 umo4nit umon4o +umon4t u5mor5o um2p umpe4 um4phy ump3i ump3y u4ms4 umt4 u3mu1 umu4le u2my +un1 4una. un5abl un4alas una4mo un4ani un4ary unat4ic. una4tr u4naut unb4 un5bl +2unc uncer4a unde6mon und2i un5dit un4dro. un4dry. un3e une2a uneb4 unek4 u4nep +un4er un5ero uner4r u4nes une4so un4et unf4 unfi4bro unflo4 unful4l ung4a unga4m +un4ger. un4gia ung4l un5gu un4ia4 un4ic u3nic. u3n4if uniflo4 unig3 uni4j uni2m +u4nin un5ing u2n3io u3nip un4iq u4n3ish un4ism u1n4it uni4us u3ni1v u4nj un3l +un3m unmatu4 4unn4 unne4c unob3l unof3 unon4e uno4pr un3p4 u4n3r4 unrav3 unre4co +unremis6 unrep4u un3s4 unsca4 unscru6ta unsepa4 unta4l 3untar untar3y untel4l un3ten un4ter. +un4terj unti4t unti4u un3tr unu4c unuch3 un3v unvict4 unvo2 uny2 unzi4 u1o +4uo. uob4 uodio4 uolan4 u4om4 u2on4 uop4e uopi4 u2or u3o3re uor3idi uo2s +uo2t u3ou u4ov 2u1p u4p. u4pab upat4 u3p4e u4ped uper3 u4peralt upercivi6 +uperlu6 up4ha upha4n uphe3m uphi4 u4p3ing upi4p upl4 u3ple u4plet u4pp uppe4t +uppor4 upre4 up1s u4pt upt3ib u3p4u uqui4 4ur. 4u3ra. u3rac 4urad ura4da +4urae ur3agi 4urale u4ram. ura4ma u4r3anc ura5no ur4ant u3rar2 u3r4as u4rasi u1r4at +u4rb urbabili6 ur4ber. ur2bin urb3ing ur2c4 urd4a urdis4 ur4dish urd4w u1rea 3urea. +u5reo ur3er ures4 u1ret ure4tic ur4fer ur4f3i ur4fr u4rg urg3in u3ria uri4ac +uri4at. u1r4ic uric3u u3rid 4ur2ie u3rien u2ring u3rio uri4ol ur2it uri3ta uriti4u +ur4lies. urmoun4 urmu4r u4rn 4urni urni4e urn4is ur4nov 4uro u3r4o. uroce4 u3roi +u4rol. uro3p uro2t urovi4 urox4 urpo4 urpre4 urr4 4urren urre4t ur4rit ur2s +ursu5a urten4 ur4tho ur4ty u1ru ur4vie ury4d ury4lo u2s u4s. u5sad u3s4an +us4ap us4as us3c us4ch us4cr use3a use4o usep4 us3es u4set us4h1 4ush2a +4usi. us4ia usi3an u3sic us4ie us5ies usil4i4 u3sill u4sin us4it us1n us4o +u3sor 4us3p us4pa usper4 us4po us4ri 2uss2 ussel4 us4seli uss4i ust3ab us4th +ustha4 us4tia us4tivel us4tiven us4tly ustmen4 us3to2 ustom3a us4top us3tr us3tu us4ty +u3s4u usur4e usur2p usyn4 2ut 4u4t. ut2a uta4h u3tal uta4ma u3t4an u4tance +utan4i 3utar3y u3tatio utb4 u4tc4 utca4 utci4 u4te4co u3te3i u3tell ut4em ut4en +ute4or ute4r u2t3er. uter5in uter4me uter4op u2tes ut3g uth4ic uthor3 u4thr utiabili6 +u3tic u3til2 u4tily ut4im u3tina uti6nate. u3tini u3tino 4utio u4tish utj4 utk4 +u4t3l4 uto4mata u3ton utre4m ut4rop ut1s4 ut4sy ut3t uttel4 ut4tit utto2 u3tu +u4tup utura4 ut1w utyr5 u1v u4valu u4ved uvel4 uve3n u4verneu u3vi uvii4 +u4vis u3vu uw4e u2x 4ux. ux3i uxili4 uxle4 uxm4 uxt4 uxu1r uya4n +uyk4 uz2e uz4is uz4ze 2v. 1va 3va. 2v1ab v4aba v4abh 3v4ac va3ca +vac3il vac3u 2vag va4gen vager4 v4agg v4a4gi 5vagina vaha4 3vai vail3a v2al +val4a va1le val4er va3leri valer4y va5lesc vali2 val3ia va3lie val4ise 3vall val4len +valli4 val3or valor3i val3u 4valu. vam4ph vampi4 va4na van4ce van4ch 4vanco 2vane +van1g 4vang. vange4 van4i vani4e van5it va3niz va3no van4u va4pi vapor3i va3ra +vard4 vardi4e va3riet var6iola var4is varle4 vars4 4varts va4ru 2vasa v5asat 5vasc +va4se vas3ec vass4i 2vast v3as3ta vastat6i 4vatar 3vate 4vatina 3vatio vats4 4vatt. +v4ce 2vd 4v4e. 2vea 3veal ve4b ve2bl 2ved v4ed. 4veda v3edl veg1e3 +vehe3 ve2i vei4o 2vel v3eled v3eler ve2li v4elin. v3el3is veli4u v4ella. vel3ler +3velo vel4od vel3op 4veloy vel4t vel3v v4ely4 2vem ve5nan veng3i ven3ie veno4 +ve2n3o2m vens4e 3vent ven4tag ven6tat 4venth ven4tis ven4ua 4vep v4era. ver4an. 4verati +verc4 5vere. ver3ea ver3ei ver3em 2veren 4vereu ve2ri ver4ia 4verie veri3ta ver3m4 +verma4n vermi6no 4verneur 1vers v4ers. 3verte vert3er 3verti ver4tit ver3u 6verwear. v2es +4ves. ve4sac 3vesc ve2si ves3p ves3ti vet3e vet5ou 4veve vey3o 4vh. 3v4i. +v4ian vi4ano 4viar vi4ary vias4 vi4ata vi3b vi4be vi4bi vi4bri vi2car vi4ce +4viced 4vicen 3vich. 5vict victi2 vic2t3u 3v4icu vi2d 4v3iden 3vid3i 4vid4i4v v4ie. +vi4en vie4r vi4erw 3viet viet5i vi4eto vie4w vi3f vi4fe 4v3iga v4ign v4ig1o +vigor3 vi4gou vii4u 3vik vik4i v4ile. vil2i v2ili2a vil3if 3ville 4villed 2vin +v2ina 3vina. vi4nato 3vinci 3vine. vi4net vin4ic vini4f vi4nom v4i3ny4 vi1o vio3l +vio4lis v3i2or5 viot4 vi4pa vi3pe 3viru v2is vis5ag 4visat 3visc v3isec 3visi +vi4sis vis3i4t 3viso vis1u3 vi3ta v4ital vita3m v3itat vitato4 v4ite vitori4 vi2t1r +vi4tra vit4ro vit4ry vit4u vi2v viv3al 4vivis v4iza v4ized 4vizz 2vk 4vki +vli4 2vn 1vo vo4cato voet4 3vog 3voi2 voi4c void3 4voird vo4j 3vok +vo2la vol3at 3volt 4vol4to vol3un 3volv vom3i von4a 4vonar 4vonp vont4 v4oq +vo2r 3vor4c vo4ri 5vorot v3orou 4vos vo2t 4vot. 3vote 4votee 3voti 3vour +vour3i 3vout vo3vi 3vow vowe4 4vowi 3voy 4vp. vra4 v4reu vro4n 2vs +v3ski v3sky 2vt 4vt. 4vty 1vu 6vulgati 3vur 2vv v4va vv4i v3vy +vy4e v4zi 2w. 1wa 4w1ab w4abs wa2g wagi4 3wak wa4kan wak3en wal4k +wallad4 wal4ley wam4pl wa4ne 4wane. wa4ny waq4 war2 war4d warde4 war4er warmon6 +warri4 war4t was4 wash3 wasp3 was5s4 waster4 w4at 3wa3te wat4i wat4ta wat4th +wau4f wavel4 3way. wc4t wd4i wdo4 wdus4 we2 wear2 wea3r4ie wear4ine wea3ry +wea4t weath3 we4b w2ed weep3 4weet3 weev4 weil4 weir4 wel3i wel2l wel4ta +we4ly 4w1er w3eri wern4 w4err wer4s wes4e west1 western5 w4et 4wett. w4ey +wf2 wg4r wgra4 1wh2 4wh. wha4 whan4 whar4 whel2 whi4 who4 why4 +w2i2 w4i. w4ia w4i4c w4i4d wid3o w4iec wield3 wien4 wi3er wi3est wi4f +3wife wi4g wign4 will3in wil4lo. wilm4 4wim wimp4 w4in. win2d win4dr win2g +win3i w4inn w4ins wir4l 1w4ise wis4p5 w4i4t with3 4witt. w4kn w4l. wl3ed +wl4ey wl3ing wl4ings w1m wm4e w2n1 wn4de w4n3er w3nes wnfal4 wn3i wn4ia +wn4ingt wnpa4 1wo2 wok4 wol2 wolf4f wol3l 3wom3 wo4ma won4e won4g won4t +woo4 3wood woozi4er wor4c wor2d wor4sen 3wort wo3ven wows4 wp2 1wr2 wr4e +3wri2 w2s ws4ab ws4er w3s4k wsma4 w3so ws4pe ws4t 2wt wtu4 wuh4 +wum4 wur2 wur4l wut4 wuz4 4ww. 2wy2 wyc5l wydi4 wyom4 w2z x1 +2x. xac4 x4aca xac5er x3ae xa2g xal2 xamer6a xa4m3i xami4nab xa4na x4andro +xap4 xar4 x4ario xas3p xas4ti xato4 x4au x4c. x3ce xchan4 x3ci xci4t3a +xcom4b xcu4 xcub4 2xe2 x4e. x3ec xe3cr xec5utiv xec3uto x4ed x5edl x5edn +xe3g xel4 xe3mi xer2 xe4ra xer4gu xe3ro x3es xhi2 xhil3 xhila3 xhu2 +2xi x3ia xi3b xibi4 xica4l x3id2 xi3di xi4dic xi4din x3ie xi3f x3ig +xig4r x3il xili4a xiliar4 xi4mis x3in x5ine xi4no x3io xi4p x3is xist5ent. +xis4ti x3iv xiv3i x4ix x3le xle4i xm4e xn4t x3o. xochro4 xo4di xo2g +xogen4 xon4ar xop4 xo5r2a xospo4 xo2t x4p. xpan4d x3pe xpec2 xpect6ed. xpecto3 +xpe3d2 xpen4c xper2 xpres4sa x4pt xpun4 x4r. xs2 xt2 x4t. x3ti xt4r +xtra5ve xtre4me xtro3v xu1a xu3b xu4l2 xulian4 xulli4 x5ult xuper4 4xus xy1 +xyb4 xyl3at x4yle xy4s x3y3t y4'l y4'r y2a. y1ab y4abe ya4co yac4t +yaen4 y4ageu 4y4ai ya4j y1al y4ala ya5lin y2am 5yam4a y1an 3yang ya3nid +y4ank yan4ode 1y2ar y4ard 4yaro ya4s yaw4p y4az yb4a yba5r 4ybd y4bele +y4bia 4y4biu yb4o ybrid3 y1c y5cem 3ycep yc3er3 y4ceri4 yce4te ych2 ychasi4 +ychas4ti ych3n y5cho ychor4 y3ci y4cida y4cif y4cinal y4cliu yclos4 yc3n4 ycog4 +yco3p yco3s ycosta4 ycot4t 4ycra ycran4 y4crat yctag4 y1d y4d' y4dad y4dali +y4dam yd4di y2de y3den y3der 4y2d5ia y4dic ydi4o ydi4v yd4l 4y4domo 4y3dr +y4driat ydroc4 ydro3s ydro3t 4y4e. ye4a yeas4 yeat4 y4ed ye3le ye3lo yel4p +ye4m yen2 ye3n4i ye4o y1e4r y4era. yer4e y2erf y4erl yers4e yes3te yet2 +ye4u4 yeus4 3yev y4fed yfire4 4yga y2gap yge2 ygen3 2y2gi yg3i3a y3gie +4ygo ygro3s 4ygy y1h yhisto6 yh4v yh4w y1i y3i4a y4ie yk4e yk4j +ykn4 y2l y4l. y5lae yl3am y3lar4 y3lax 4yld y4le. y3ledo2 4ylem ylen4 +y4lest yl1ic 4ylid4 yl3ism y3lit 4yll yl3la yllar4 yl3li yllo4m yllo4n 4ylna +y3lo y4loch yl4on yl2p yl4ph ylphe4 ylphi4 4ylsu 4yl3t y3lum y3lus yl3v +y3ly 2ym 4ym. 4yma ymbo4 ymbol3 ym4c y3men 4ymer 4y2mi 5y5miz y3mo +ymo4b 4ymol. y4monds ympa3 ymphan3 ym4phe ymp4i ymple4 2yn y1na y4nae yna3mit +y4namy y4n4ar ynar4chi y4nast. yn3c ynde4 y2ne yn4ep yn4et yn1g yng4a 5yngec +6yngologi y2ni ynia4 yn2n yno4e ynos4 3ynou yn1t yntro4 3yny. 4ynya yo3de +yog4i y3oi 5yoke yoky4 yom4i yon2 y3one4 y1op yopi4t 2yp y2pa y4paes +yp4e yper3 yperpu4 y4pes ypeta4 y4peu 4yphag yphe2 yph3il y3pho 4yphon ypho4t +4yp3i yp4ico 3yplo ypo3a ypo3c y4pocr y3pogr ypo4lite ypo3n ypos5tas ypos4to y4poth. +y4pou y4pre. y4pri yp3s yp2ta ypt3an yp3y y3ra. y3rag y2re y5rene. y4rhi +y4ria yriam4 y4r1ic yr4if 5yrint yr4le y4rm yr4ma yrme3 y4rn y1ro y4rod +yro3st yrro4 y2s ysal2 ysca4 yscrin4 ys3e3al ys4el ys4es y3sh ys2i y4siac. +ys3i3al y4sias ys3ic y3sid ys3io 3y5sis y5sit 4ysk ysme4 ys4o ysom4 yss4 +ys4sal ysse4 ys3t ystem3 ystem4l ysthe4u ys4tl ys4toi ys4tone ysto4p ystri6 y3su +y4sur ys4us 3y3sy 2y2t y4t. ytan4 yte4l ytel4l 3y3ten yte4r y4teu y3them +y4th3i ytho4gr yth3op yth3ro yt1i y4til y4tio ytish4 y4tium y3to 4ytom y4tomo +y4tomy ytos4t y3tr ytt4 y3tu yub4 y4uc yu4go. yu4le y1v y1w yw4c +ywon4 2y2x 4yx3e yx3i yxi4a. yxi4d 4yxo 4yy4a 2yz y2za y4zan y4zygy +2z. 1za1 3za. 2z1ab za4ch 4zaf za4g 3zal za4la 4zald zale4 3zan +4zank za4nu za4q 2zar2 z4ar. za2rat zar4ia za4ry zas4 za4st 3zat 4zath +za4u 2zb 2ze. zeal3 ze4bra. ze4da zeg4 3zel. zel4le ze4n zen4e 4zener +zenti4 ze4p z1er zer4a zer4o z4ert zevi4 zg4e 4zgi zh4d z1i 3zi. +3zia. zi4at zib4 zi4be4 4zic. 3z4ie. zi4ery zi1es z4if zi4k 4zilin z4ilo +4z4im 2zin2 3zin. z4in4c zinc3i zind4 zin4e 3zine. z3ing. 4ziot zir4ca zi4r4i +4zirit 4zky z5ky. 1z2l2 4zla 3zle 4zlo 1zo zo1a 4zoam zocer4 zo1i +zoker4 zo4lam zolan4 4zolin 4zolo 3zo2n zonar4 zo4ne zon4if zo1o zoo4i zook4 +2zop 3zor zori4l zos4e 2zot zo3ti zo4tic z3ra zs4c z4so4 zuid4 zu4o +4zwi 3zyg zy2ga zym4 z1z2 z3za z4zed 4zzi z3zl z3zo zzu4 z4zw diff --git a/crates/compose/Cargo.toml b/crates/compose/Cargo.toml index e507559..7f02d33 100644 --- a/crates/compose/Cargo.toml +++ b/crates/compose/Cargo.toml @@ -14,6 +14,7 @@ designcraft-color = { workspace = true } designcraft-doc = { workspace = true } designcraft-fonts = { workspace = true } log = { workspace = true } +miniz_oxide = "0.8" [dev-dependencies] proptest = { workspace = true } diff --git a/crates/compose/examples/hyphgen.rs b/crates/compose/examples/hyphgen.rs new file mode 100644 index 0000000..6156832 --- /dev/null +++ b/crates/compose/examples/hyphgen.rs @@ -0,0 +1,174 @@ +//! Regenerates the bundled English hyphenation data from the Moby Hyphenator II word list. +//! +//! ```text +//! curl -LO https://www.gutenberg.org/files/3204/files/mhyph.txt # Project Gutenberg #3204, public domain +//! cargo run --release -p designcraft-compose --example hyphgen -- mhyph.txt assets/hyphenation [--validate] +//! ``` +//! +//! Writes `en-us.dic` (the word list, front-coded and deflated; see `hyphen::dict`) and +//! `en-us.pat` (Liang patterns trained from the list by `hyphen::patgen`). `--validate` first +//! trains on 90% of the words and reports accuracy on the held-out 10%. + +use std::collections::HashMap; +use std::path::PathBuf; + +use designcraft_compose::hyphen::dict::{Dictionary, hyphenated}; +use designcraft_compose::hyphen::patgen::{self, DEFAULT_LEVELS}; + +/// Mac OS Roman, 0x80..=0xFF (the list's encoding; 0xA5 `•` marks breaks). +const MAC_ROMAN_HIGH: &str = + "ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»…\u{A0}ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ\u{F8FF}ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ"; + +fn mac_roman(bytes: &[u8]) -> String { + let high: Vec = MAC_ROMAN_HIGH.chars().collect(); + assert_eq!(high.len(), 128); + bytes.iter().map(|&b| if b < 0x80 { b as char } else { high[b as usize - 0x80] }).collect() +} + +const BREAK: char = '•'; + +fn is_word_char(c: char) -> bool { + c.is_alphabetic() || c == '\'' || c == BREAK +} + +/// `(lowercase word, mask)` of one token like `Aa•ron's`, or None if it isn't a plain word. +fn token(t: &str) -> Option<(String, u64)> { + let t = t.trim_matches('\''); + if t.is_empty() || !t.chars().all(is_word_char) || t.starts_with(BREAK) || t.ends_with(BREAK) { + return None; + } + let mut w = String::new(); + let mut m = 0u64; + let mut n = 0usize; + for c in t.chars() { + if c == BREAK { + if n < 64 { + m |= 1 << n; + } + } else { + w.extend(c.to_lowercase()); + n += 1; + } + } + ((1..64).contains(&n) && w.chars().count() == n).then_some((w, m)) +} + +fn main() { + let args: Vec = std::env::args().skip(1).collect(); + let validate = args.iter().any(|a| a == "--validate"); + let pos: Vec<&String> = args.iter().filter(|a| !a.starts_with("--")).collect(); + let Some(src) = pos.first() else { + eprintln!("usage: hyphgen [out-dir] [--validate]"); + std::process::exit(2); + }; + let out_dir = PathBuf::from(pos.get(1).map_or("assets/hyphenation", |s| s.as_str())); + let text = mac_roman(&std::fs::read(src).expect("read word list")); + + // key → (lowercase-origin masks, other masks); compound parts only fill gaps. + let mut primary: HashMap, Vec)> = HashMap::new(); + let mut parts: HashMap = HashMap::new(); + let mut entries = 0usize; + for line in text.lines() { + let line = line.trim_end_matches('\r').trim(); + if line.is_empty() { + continue; + } + entries += 1; + if let Some((w, m)) = token(line) { + let lower = !line.chars().any(char::is_uppercase); + let e = primary.entry(w).or_default(); + if lower { e.0.push(m) } else { e.1.push(m) } + } else { + for t in line.split([' ', '-', '/']) { + if let Some((w, m)) = token(t) { + parts.entry(w).or_insert(m); + } + } + } + } + let mut list: Vec<(String, u64)> = primary + .into_iter() + .map(|(w, (lower, other))| { + // Prefer lowercase entries; where spellings disagree (re•cord / rec•ord) keep only the + // breaks they share. + let v = if lower.is_empty() { other } else { lower }; + (w, v.iter().fold(u64::MAX, |a, b| a & b)) + }) + .collect(); + let have: std::collections::HashSet = list.iter().map(|x| x.0.clone()).collect(); + let extra: Vec<(String, u64)> = parts.into_iter().filter(|(w, _)| !have.contains(w)).collect(); + println!("{entries} entries → {} words (+{} from compounds)", list.len(), extra.len()); + list.extend(extra); + let dict = Dictionary::from_entries(list); + let bytes = dict.to_bytes(); + std::fs::create_dir_all(&out_dir).expect("mkdir"); + std::fs::write(out_dir.join("en-us.dic"), &bytes).expect("write en-us.dic"); + let back = Dictionary::from_bytes(&bytes).expect("roundtrip"); + assert_eq!(back.len(), dict.len()); + println!("en-us.dic: {} words, {} bytes", dict.len(), bytes.len()); + + // Training data: plain lowercase ASCII words (+ apostrophes). + let train: Vec<(Vec, Vec)> = dict + .iter() + .filter(|(w, _)| w.chars().all(|c| c.is_ascii_lowercase() || c == '\'')) + .map(|(w, m)| (w.chars().collect(), (1..w.len().min(64)).filter(|&i| m & (1 << i) != 0).collect())) + .collect(); + println!("training on {} words", train.len()); + let mut log = |s: String| println!(" {s}"); + // Optional override for tuning: HYPHGEN_LEVELS="1,4,1,2,20;2,5,2,1,8;…" (min,max,good,bad,threshold). + let custom: Option> = std::env::var("HYPHGEN_LEVELS").ok().map(|s| { + s.split(';') + .map(|l| { + let v: Vec = l.split(',').map(|x| x.trim().parse().expect("number")).collect(); + patgen::Level { min_len: v[0] as usize, max_len: v[1] as usize, good_weight: v[2], bad_weight: v[3], threshold: v[4] } + }) + .collect() + }); + let levels = custom.as_deref().unwrap_or(DEFAULT_LEVELS); + if validate { + let (fit, hold): (Vec<_>, Vec<_>) = train.iter().cloned().enumerate().partition(|(i, _)| i % 10 != 0); + let fit: Vec<_> = fit.into_iter().map(|x| x.1).collect(); + let hold: Vec<_> = hold.into_iter().map(|x| x.1).collect(); + let p = patgen::train(&fit, levels, &mut log); + let s = patgen::score(&p, &hold); + println!( + "held-out: {} words, {} breaks: found {} ({:.1}%), missed {}, wrong {} ({:.2}% of reported)", + s.words, + s.breaks, + s.found, + 100.0 * s.found as f64 / s.breaks.max(1) as f64, + s.missed(), + s.wrong, + 100.0 * s.wrong as f64 / (s.found + s.wrong).max(1) as f64 + ); + } + if std::env::var_os("HYPHGEN_VALIDATE_ONLY").is_some() { + return; + } + let pats = patgen::train(&train, levels, &mut log); + let s = patgen::score(&pats, &train); + println!( + "training set: found {}/{} ({:.1}%), wrong {} — {} patterns", + s.found, + s.breaks, + 100.0 * s.found as f64 / s.breaks.max(1) as f64, + s.wrong, + pats.len() + ); + let mut out = String::new(); + out.push_str("% DesignCraft US English hyphenation patterns (Liang/TeX notation).\n"); + out.push_str("% Generated by crates/compose/examples/hyphgen.rs: trained with DesignCraft's patgen-style trainer\n"); + out.push_str("% from the Moby Hyphenator II word list by Grady Ward (public domain, Project Gutenberg #3204).\n"); + out.push_str("% Released into the public domain (CC0-1.0) by the DesignCraft contributors.\n"); + for line in pats.to_tex().chunks(12) { + out.push_str(&line.join(" ")); + out.push('\n'); + } + std::fs::write(out_dir.join("en-us.pat"), &out).expect("write en-us.pat"); + println!("en-us.pat: {} patterns, {} bytes", pats.len(), out.len()); + for w in ["hyphenation", "typography", "composition", "photographer", "unquestionably", "localization", "blockchain", "smartphone"] { + let c: Vec = w.chars().collect(); + let m = pats.points(&c).unwrap_or_default().iter().fold(0u64, |m, &i| m | 1 << i); + println!(" patterns: {}", hyphenated(w, m)); + } +} diff --git a/crates/compose/src/breaker.rs b/crates/compose/src/breaker.rs index 35392a2..8fd9b7d 100644 --- a/crates/compose/src/breaker.rs +++ b/crates/compose/src/breaker.rs @@ -1,5 +1,12 @@ -//! Line breaking: the paragraph composer (Knuth–Plass total fit) and the single-line composer -//! (greedy first fit). Both work on a paragraph's glyphs and a per-line measure function. +//! Line breaking: the paragraph composer (Knuth–Plass total fit), the single-line composer +//! (greedy first fit) and balanced ragged lines. All work on a paragraph's glyphs and a per-line +//! measure function. +//! +//! Justification uses *prioritised* elastic material (plan: typography §5.2): word spaces first, +//! then letter spacing (every glyph gets elastic width from the paragraph's letter-spacing range), +//! then glyph scaling. The adjustment ratio charges letter and glyph adjustments extra +//! ([`TIER_COST`]), so the composer prefers word-space changes, then hyphenation, then letter +//! spacing, then glyph scaling. use crate::shape::{Glyph, SOFT_HYPHEN}; @@ -15,38 +22,143 @@ pub struct Break { pub forced: bool, } -/// Spacing parameters (from the paragraph's Justification settings), as fractions. +/// Spacing parameters (from the paragraph's Justification and Hyphenation settings), as fractions. #[derive(Clone, Copy, Debug)] pub struct Spacing { pub justify: bool, pub word_min: f64, pub word_desired: f64, pub word_max: f64, + /// Letter spacing, as fractions of the space width added between glyphs. + pub letter_min: f64, + pub letter_desired: f64, + pub letter_max: f64, + /// Horizontal glyph scaling (1 = 100%). + pub glyph_min: f64, + pub glyph_desired: f64, + pub glyph_max: f64, /// Penalty for a hyphenated break (0 = free, larger = fewer hyphens). pub hyphen_penalty: f64, - /// Maximum consecutive hyphenated lines (0 = unlimited). + /// Maximum consecutive hyphenated lines (0 = unlimited) — a hard constraint. pub hyphen_limit: u32, /// Ragged-right stretchability (points) for unjustified paragraphs. pub ragged_stretch: f64, + /// Hyphenation zone (points, unjustified text only): a word is not hyphenated when breaking + /// before it would leave less than this much space at the end of the line. + pub hyph_zone: f64, + /// Optical margin alignment: punctuation hangs outside the measure (counted as extra width). + pub optical: bool, +} + +impl Default for Spacing { + fn default() -> Self { + Spacing { + justify: false, + word_min: 0.8, + word_desired: 1.0, + word_max: 1.33, + letter_min: 0.0, + letter_desired: 0.0, + letter_max: 0.0, + glyph_min: 1.0, + glyph_desired: 1.0, + glyph_max: 1.0, + hyphen_penalty: 275.0, + hyphen_limit: 3, + ragged_stretch: 24.0, + hyph_zone: 0.0, + optical: false, + } + } +} + +impl Spacing { + /// Per-tier (word, letter, glyph) stretch and shrink of glyph `g` as a box. + fn box_elastic(&self, g: &Glyph) -> ([f64; 3], [f64; 3]) { + if !self.justify { + return ([0.0; 3], [0.0; 3]); + } + let natural = g.adv / self.glyph_desired.max(0.01); + ( + [0.0, g.space * (self.letter_max - self.letter_desired).max(0.0), natural * (self.glyph_max - self.glyph_desired).max(0.0)], + [0.0, g.space * (self.letter_desired - self.letter_min).max(0.0), natural * (self.glyph_desired - self.glyph_min).max(0.0)], + ) + } + /// Word-space stretch and shrink of space glyph `g` (only U+0020 is elastic). + fn space_elastic(&self, g: &Glyph) -> (f64, f64) { + if g.ch != ' ' { + return (0.0, 0.0); + } + (g.space * (self.word_max - self.word_desired).max(0.0), g.space * (self.word_desired - self.word_min).max(0.0)) + } +} + +/// Relative cost of using each tier of elastic material (word, letter, glyph). +pub const TIER_COST: [f64; 3] = [1.0, 0.75, 1.0]; + +/// Effective adjustment ratio for `d` points of stretch (`d > 0`) or shrink (`d < 0`), consuming +/// the tiers in priority order. Returns `(r, feasible)`; shrinking beyond all tiers is infeasible. +pub fn tiered_ratio(d: f64, y: [f64; 3], z: [f64; 3]) -> (f64, bool) { + const EPS: f64 = 1e-9; + if d.abs() < EPS { + return (0.0, true); + } + let (mut rem, cap) = if d > 0.0 { (d, y) } else { (-d, z) }; + let mut r = 0.0; + for t in 0..3 { + if cap[t] > EPS && rem > EPS { + let take = rem.min(cap[t]); + r += TIER_COST[t] * take / cap[t]; + rem -= take; + } + } + if d < 0.0 { + return (-r, rem <= 1e-6); + } + if rem > 1e-6 { + // Beyond every maximum: word spaces grow without bound (an H&J violation). + let unit = if cap[0] > EPS { cap[0] } else { cap.iter().sum::() }; + r = if unit > EPS { r + rem / unit } else { INF }; + } + (r, true) +} + +#[derive(Clone, Copy, Debug, PartialEq)] +enum Kind { + Box, + Glue, + Penalty, } #[derive(Clone, Copy, Debug)] -enum Item { - /// Unbreakable width (a glyph). - Box { - w: f64, - }, - /// Space glyph `g`. - Glue { - w: f64, - st: f64, - sh: f64, - }, - Penalty { - w: f64, - p: f64, - flagged: bool, - }, +struct Item { + kind: Kind, + w: f64, + st: [f64; 3], + sh: [f64; 3], + /// Penalty value (penalties only). + p: f64, + flagged: bool, + /// An automatic/discretionary hyphenation point (subject to the hyphenation zone). + auto: bool, + /// Breaks: optical hang of the glyph ending the line. Boxes: hang of the glyph starting one. + hang: f64, + /// Auto hyphenation points: index of the break opportunity before the word (or `NONE`). + zone_from: usize, +} + +const NONE: usize = usize::MAX; + +impl Item { + fn boxed(w: f64, st: [f64; 3], sh: [f64; 3]) -> Item { + Item { kind: Kind::Box, w, st, sh, p: 0.0, flagged: false, auto: false, hang: 0.0, zone_from: NONE } + } + fn glue(w: f64, st: f64, sh: f64) -> Item { + Item { kind: Kind::Glue, w, st: [st, 0.0, 0.0], sh: [sh, 0.0, 0.0], p: 0.0, flagged: false, auto: false, hang: 0.0, zone_from: NONE } + } + fn penalty(w: f64, p: f64, flagged: bool) -> Item { + Item { kind: Kind::Penalty, w, st: [0.0; 3], sh: [0.0; 3], p, flagged, auto: false, hang: 0.0, zone_from: NONE } + } } const INF: f64 = 10000.0; @@ -57,63 +169,152 @@ pub fn is_forced(c: char) -> bool { matches!(c, FORCED_LINE_BREAK | COLUMN_BREAK | FRAME_BREAK | PAGE_BREAK) } +/// Optical margin protrusion of `c` as fractions of its advance: (left edge, right edge). +pub fn hang(c: char) -> (f64, f64) { + match c { + '.' | ',' => (0.0, 1.0), + '-' | '\u{2010}' | '\u{2011}' | '\u{AD}' => (0.75, 0.75), + '\'' | '"' | '‘' | '’' | '“' | '”' | '‚' | '„' | '‹' | '›' | '«' | '»' => (1.0, 1.0), + '\u{2013}' | '\u{2014}' => (0.5, 0.5), + ':' | ';' => (0.0, 0.5), + '!' | '?' => (0.0, 0.2), + '*' => (0.3, 0.3), + '(' | '[' | '{' => (0.1, 0.0), + ')' | ']' | '}' => (0.0, 0.1), + 'A' | 'V' | 'W' | 'Y' | 'v' | 'w' | 'y' => (0.05, 0.05), + 'T' => (0.05, 0.05), + 'O' | 'C' | 'G' | 'Q' | 'o' | 'c' => (0.03, 0.03), + _ => (0.0, 0.0), + } +} + +fn hang_left(g: &Glyph) -> f64 { + hang(g.ch).0 * g.adv +} + +fn hang_right(g: &Glyph) -> f64 { + hang(g.ch).1 * g.adv +} + +/// Advance of the hyphen glyph that would follow `g` (cached per face). +fn hyphen_width(g: &Glyph, cache: &mut Vec<(u32, f64)>) -> f64 { + let id = g.face.id(); + let units = match cache.iter().find(|c| c.0 == id) { + Some(c) => c.1, + None => { + let gid = designcraft_fonts::first_glyph(&g.face, &['-', '\u{2010}']); + let u = g.face.advance(gid); + cache.push((id, u)); + u + } + }; + units * g.sx +} + +/// Push a break inside a word. Ragged text gets the line-end stretch around it +/// (`penalty(∞) glue(0, s) penalty glue(0, −s)`), so hyphenated ragged lines are measured like +/// lines broken at spaces. +fn push_inword(it: &mut Vec, ig: &mut Vec, p: Item, g: usize, sp: &Spacing) { + if sp.justify { + it.push(p); + ig.push(g); + return; + } + it.push(Item::penalty(0.0, INF, false)); + it.push(Item::glue(0.0, sp.ragged_stretch, 0.0)); + it.push(p); + it.push(Item::glue(0.0, -sp.ragged_stretch, 0.0)); + ig.extend([g; 4]); +} + /// Build Knuth items. `item_glyph[k]` = glyph index of item k (penalties: the glyph *before* which the break happens). fn items(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing) -> (Vec, Vec) { - let mut it = Vec::with_capacity(glyphs.len() * 2 + 2); + let mut it: Vec = Vec::with_capacity(glyphs.len() * 2 + 2); let mut ig = Vec::with_capacity(glyphs.len() * 2 + 2); let n = glyphs.len(); + let mut hy_cache = Vec::new(); + let mut last_space = NONE; for (i, g) in glyphs.iter().enumerate() { + let prev_hang = if sp.optical && i > 0 { hang_right(&glyphs[i - 1]) } else { 0.0 }; if is_forced(g.ch) { - it.push(Item::Glue { w: 0.0, st: INF, sh: 0.0 }); + it.push(Item::glue(0.0, INF, 0.0)); ig.push(i); - it.push(Item::Penalty { w: 0.0, p: -INF, flagged: false }); + let mut p = Item::penalty(0.0, -INF, false); + p.hang = prev_hang; + it.push(p); ig.push(i + 1); + last_space = NONE; continue; } if g.is_space() && !g.no_break { let w = g.adv; if sp.justify { - let base = w / sp.word_desired.max(1e-6); - it.push(Item::Glue { w, st: base * (sp.word_max - sp.word_desired).max(0.0), sh: base * (sp.word_desired - sp.word_min).max(0.0) }); + let (st, sh) = sp.space_elastic(g); + let mut gl = Item::glue(w, st, sh); + gl.hang = prev_hang; + last_space = it.len(); + it.push(gl); ig.push(i); } else { // Ragged right (Knuth): glue(0, s, 0) penalty(0) glue(w, -s, 0). - it.push(Item::Glue { w: 0.0, st: sp.ragged_stretch, sh: 0.0 }); + it.push(Item::glue(0.0, sp.ragged_stretch, 0.0)); ig.push(i); - it.push(Item::Penalty { w: 0.0, p: 0.0, flagged: false }); + let mut p = Item::penalty(0.0, 0.0, false); + p.hang = prev_hang; + last_space = it.len(); + it.push(p); ig.push(i); - it.push(Item::Glue { w, st: -sp.ragged_stretch, sh: 0.0 }); + it.push(Item::glue(w, -sp.ragged_stretch, 0.0)); ig.push(i); } continue; } if g.ch == SOFT_HYPHEN { - let hw = g.size * 0.33; - it.push(Item::Penalty { w: hw, p: sp.hyphen_penalty, flagged: true }); - ig.push(i + 1); + let hw = glyphs[..i].iter().rev().find(|g| g.ch != SOFT_HYPHEN).map_or(g.size * 0.33, |p| hyphen_width(p, &mut hy_cache)); + let mut p = Item::penalty(hw, sp.hyphen_penalty, true); + p.auto = true; + p.zone_from = last_space; + if sp.optical { + p.hang = hw * hang('-').1; + } + push_inword(&mut it, &mut ig, p, i + 1, sp); continue; } - it.push(Item::Box { w: g.adv }); + let (st, sh) = sp.box_elastic(g); + let mut bx = Item::boxed(g.adv, st, sh); + if sp.optical { + bx.hang = hang_left(g); + } + it.push(bx); ig.push(i); let next_is_space = glyphs.get(i + 1).is_none_or(|n| n.is_space()); if i + 1 < n && !next_is_space && !g.no_break { if matches!(g.ch, '-' | '\u{2010}') { - it.push(Item::Penalty { w: 0.0, p: 50.0, flagged: true }); - ig.push(i + 1); + let mut p = Item::penalty(0.0, 50.0, true); + p.hang = if sp.optical { hang_right(g) } else { 0.0 }; + push_inword(&mut it, &mut ig, p, i + 1, sp); } else if matches!(g.ch, '\u{2013}' | '\u{2014}' | '/') { - it.push(Item::Penalty { w: 0.0, p: 0.0, flagged: false }); - ig.push(i + 1); + let mut p = Item::penalty(0.0, 0.0, false); + p.hang = if sp.optical { hang_right(g) } else { 0.0 }; + push_inword(&mut it, &mut ig, p, i + 1, sp); } else if hyph_after[i] { - let hw = g.size * 0.33; - it.push(Item::Penalty { w: hw, p: sp.hyphen_penalty, flagged: true }); - ig.push(i + 1); + let hw = hyphen_width(g, &mut hy_cache); + let mut p = Item::penalty(hw, sp.hyphen_penalty, true); + p.auto = true; + p.zone_from = last_space; + if sp.optical { + p.hang = hw * hang('-').1; + } + push_inword(&mut it, &mut ig, p, i + 1, sp); } } } // Paragraph end: fill glue + forced break. - it.push(Item::Glue { w: 0.0, st: INF, sh: 0.0 }); + it.push(Item::glue(0.0, INF, 0.0)); ig.push(n); - it.push(Item::Penalty { w: 0.0, p: -INF, flagged: false }); + let mut p = Item::penalty(0.0, -INF, false); + p.hang = if sp.optical && n > 0 { hang_right(&glyphs[n - 1]) } else { 0.0 }; + it.push(p); ig.push(n); (it, ig) } @@ -124,8 +325,8 @@ struct Node { line: usize, fitness: u8, tw: f64, - ty: f64, - tz: f64, + ty: [f64; 3], + tz: [f64; 3], demerits: f64, prev: Option, hyphens: u32, @@ -138,7 +339,7 @@ pub fn knuth_plass(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing, width: & return vec![Break { start: 0, end: 0, next: 0, hyphen: false, forced: true }]; } let (items, ig) = items(glyphs, hyph_after, sp); - for tolerance in [3.0, 30.0, f64::INFINITY] { + for tolerance in [2.5, 12.0, f64::INFINITY] { if let Some(b) = kp_pass(&items, &ig, glyphs, sp, width, tolerance, tolerance.is_infinite()) { return b; } @@ -146,6 +347,9 @@ pub fn knuth_plass(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing, width: & greedy(glyphs, hyph_after, sp, width) } +/// Upper bound on the hyphen-count states tracked per breakpoint. +const MAX_HYPHEN_STATES: usize = 8; + #[allow(clippy::too_many_arguments)] fn kp_pass( items: &[Item], @@ -159,118 +363,153 @@ fn kp_pass( let m = items.len(); // Prefix sums (before item i). let mut sw = vec![0.0; m + 1]; - let mut sy = vec![0.0; m + 1]; - let mut sz = vec![0.0; m + 1]; + let mut sy = vec![[0.0; 3]; m + 1]; + let mut sz = vec![[0.0; 3]; m + 1]; for (i, it) in items.iter().enumerate() { - let (w, y, z) = match *it { - Item::Box { w } => (w, 0.0, 0.0), - Item::Glue { w, st, sh } => (w, st, sh), - Item::Penalty { .. } => (0.0, 0.0, 0.0), + let (w, y, z) = match it.kind { + Kind::Box | Kind::Glue => (it.w, it.st, it.sh), + Kind::Penalty => (0.0, [0.0; 3], [0.0; 3]), }; sw[i + 1] = sw[i] + w; - sy[i + 1] = sy[i] + y; - sz[i + 1] = sz[i] + z; + for t in 0..3 { + sy[i + 1][t] = sy[i][t] + y[t]; + sz[i + 1][t] = sz[i][t] + z[t]; + } } + let first_hang = items.iter().find(|i| i.kind == Kind::Box).map_or(0.0, |b| b.hang); let mut arena: Vec = - vec![Node { pos: 0, line: 0, fitness: 1, tw: 0.0, ty: 0.0, tz: 0.0, demerits: 0.0, prev: None, hyphens: 0, flagged: false }]; + vec![Node { pos: 0, line: 0, fitness: 1, tw: first_hang, ty: [0.0; 3], tz: [0.0; 3], demerits: 0.0, prev: None, hyphens: 0, flagged: false }]; + let limit = sp.hyphen_limit as usize; + let states = if limit == 0 { 2 } else { (limit + 1).min(MAX_HYPHEN_STATES) }; let mut active: Vec = vec![0]; + let mut best: Vec> = vec![None; 4 * states]; + let mut keep = Vec::new(); for b in 0..m { - let (is_break, pw, pp, flagged) = match items[b] { - Item::Penalty { w, p, flagged } if p < INF => (true, w, p, flagged), - Item::Glue { .. } if b > 0 && matches!(items[b - 1], Item::Box { .. }) => (true, 0.0, 0.0, false), + let it = items[b]; + let (is_break, pw, pp, flagged) = match it.kind { + Kind::Penalty if it.p < INF => (true, it.w, it.p, it.flagged), + Kind::Glue if b > 0 && items[b - 1].kind == Kind::Box => (true, 0.0, 0.0, false), _ => (false, 0.0, 0.0, false), }; if !is_break { continue; } let forced = pp <= -INF; - let mut best: [Option<(f64, usize, f64)>; 4] = [None; 4]; // (demerits, active node, ratio) - let mut keep = Vec::with_capacity(active.len()); - let mut last_removed: Option<(usize, f64)> = None; + best.iter_mut().for_each(|x| *x = None); + keep.clear(); + let mut last_removed: Option = None; for &a in &active { let n = arena[a]; - let l = sw[b] - n.tw + pw; + let l = sw[b] - n.tw + pw - it.hang; let target = width(n.line).max(1.0); - let (y, z) = (sy[b] - n.ty, sz[b] - n.tz); - let r = if l < target { - if y > 1e-9 { (target - l) / y } else { INF } - } else if l > target { - if z > 1e-9 { (target - l) / z } else { -INF } - } else { - 0.0 - }; - let deactivate = r < -1.0 || forced; - if !deactivate { + let mut y = [0.0; 3]; + let mut z = [0.0; 3]; + for t in 0..3 { + y[t] = sy[b][t] - n.ty[t]; + z[t] = sz[b][t] - n.tz[t]; + } + let (r, feasible) = tiered_ratio(target - l, y, z); + if feasible && !forced { keep.push(a); } else { - last_removed = Some((a, r)); + last_removed = Some(a); } - if r >= -1.0 && (r <= tol || forced) { - let bad = (100.0 * r.abs().powi(3)).min(INF); - let lp = 10.0 + bad; - let mut d = if pp >= 0.0 { - lp * lp + pp * pp - } else if pp > -INF { - lp * lp - pp * pp - } else { - lp * lp - }; - if flagged && n.flagged { - d += 3000.0; + if !feasible || (r > tol && !forced) { + continue; + } + if flagged { + // Hyphen limit: a hard constraint. + if limit > 0 && n.hyphens as usize >= limit { + continue; } - if flagged && sp.hyphen_limit > 0 && n.hyphens >= sp.hyphen_limit { - d += 1e7; - } - let fit = if r < -0.5 { - 0 - } else if r <= 0.5 { - 1 - } else if r <= 1.0 { - 2 - } else { - 3 - }; - if (fit as i32 - n.fitness as i32).abs() > 1 { - d += 3000.0; - } - let total = n.demerits + d; - if best[fit as usize].is_none_or(|(bd, _, _)| total < bd) { - best[fit as usize] = Some((total, a, r)); + // Hyphenation zone (unjustified): break before the word instead when that leaves + // less than the zone at the line end. + if it.auto && !sp.justify && sp.hyph_zone > 0.0 && it.zone_from != NONE && it.zone_from > n.pos { + let before = sw[it.zone_from] - n.tw - items[it.zone_from].hang; + if target - before < sp.hyph_zone { + continue; + } } } + let bad = 100.0 * r.abs().powi(3); + let lp = 10.0 + bad; + let mut d = if pp >= 0.0 { + lp * lp + pp * pp + } else if pp > -INF { + lp * lp - pp * pp + } else { + lp * lp + }; + if flagged && n.flagged { + d += 3000.0; + } + let fit = if r < -0.5 { + 0 + } else if r <= 0.5 { + 1 + } else if r <= 1.0 { + 2 + } else { + 3 + }; + if (fit as i32 - n.fitness as i32).abs() > 1 { + d += 3000.0; + } + let hs = if flagged { (n.hyphens as usize + 1).min(states - 1) } else { 0 }; + let total = n.demerits + d; + let slot = &mut best[fit * states + hs]; + if slot.is_none_or(|(bd, _)| total < bd) { + *slot = Some((total, a)); + } } // Emergency: nothing can reach this break and nothing remains active → accept an overfull line. if emergency && keep.is_empty() && best.iter().all(Option::is_none) - && let Some((a, _)) = last_removed + && let Some(a) = last_removed { - best[0] = Some((arena[a].demerits + 1e8, a, -1.0)); + best[0] = Some((arena[a].demerits + 1e8, a)); + } + std::mem::swap(&mut active, &mut keep); + if best.iter().all(Option::is_none) { + if active.is_empty() { + return None; + } + continue; } - active = keep; // Totals after the break: skip glue and penalties up to the next box. let (mut tw, mut ty, mut tz) = (sw[b], sy[b], sz[b]); let mut i = b; while i < m { - match items[i] { - Item::Box { .. } => break, - Item::Glue { w, st, sh } => { - tw += w; - ty += st; - tz += sh; + let x = items[i]; + match x.kind { + Kind::Box => { + tw += x.hang; + break; } - Item::Penalty { p, .. } if p <= -INF && i > b => break, - Item::Penalty { .. } => {} + Kind::Glue => { + tw += x.w; + for t in 0..3 { + ty[t] += x.st[t]; + tz[t] += x.sh[t]; + } + } + Kind::Penalty if x.p <= -INF && i > b => break, + Kind::Penalty => {} } i += 1; } - for (fit, c) in best.iter().enumerate() { - if let Some((d, a, _)) = *c { + // Knuth's pruning: a class is only worth a node if it is within the fitness demerit of the best. + let min_d = best.iter().flatten().map(|x| x.0).fold(f64::INFINITY, f64::min); + for (k, c) in best.iter().enumerate() { + if let Some((d, a)) = *c + && d <= min_d + 3000.0 + { let prev = arena[a]; arena.push(Node { pos: b, line: prev.line + 1, - fitness: fit as u8, + fitness: (k / states) as u8, tw, ty, tz, @@ -282,12 +521,6 @@ fn kp_pass( active.push(arena.len() - 1); } } - if active.is_empty() { - if std::env::var_os("DC_KP_DEBUG").is_some() { - eprintln!("kp tol {tol}: no active nodes at item {b}/{m} (glyph {})", ig[b]); - } - return None; - } } // The final forced break: best node at position m-1. let end = active.iter().copied().filter(|&a| arena[a].pos == m - 1).min_by(|&a, &b| arena[a].demerits.total_cmp(&arena[b].demerits))?; @@ -308,15 +541,15 @@ fn breaks_from_positions(items: &[Item], ig: &[usize], glyphs: &[Glyph], chain: let mut out = Vec::with_capacity(chain.len()); let mut start = 0; for &b in chain { - let (end, hyphen, forced) = match items[b] { - Item::Penalty { p, flagged, w } => { + let it = items[b]; + let (end, hyphen, forced) = match it.kind { + Kind::Penalty => { let e = ig[b].min(n); // A flagged penalty with width = an inserted hyphen (not an explicit '-'). let explicit = e > 0 && matches!(glyphs[e - 1].ch, '-' | '\u{2010}'); - (e, flagged && w > 0.0 && !explicit || (flagged && e > 0 && glyphs[e - 1].ch == SOFT_HYPHEN), p <= -INF) + (e, it.flagged && it.w > 0.0 && !explicit || (it.flagged && e > 0 && glyphs[e - 1].ch == SOFT_HYPHEN), it.p <= -INF) } - Item::Glue { .. } => (ig[b], false, false), - Item::Box { .. } => (ig[b], false, false), + Kind::Glue | Kind::Box => (ig[b], false, false), }; // Trim trailing spaces from the visible range; skip leading spaces of the next line. let mut vis_end = end; @@ -345,14 +578,18 @@ pub fn greedy(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing, width: &dyn F let mut out = Vec::new(); let mut start = 0; let mut line = 0; + let mut hyphens = 0u32; + let mut hy_cache = Vec::new(); if n == 0 { return vec![Break { start: 0, end: 0, next: 0, hyphen: false, forced: true }]; } + let may_hyphenate = |hyphens: u32| sp.hyphen_limit == 0 || hyphens < sp.hyphen_limit; while start < n { let w = width(line).max(1.0); - let mut x = 0.0; - let mut spaces_shrink = 0.0; + let mut x = if sp.optical { -hang_left(&glyphs[start]) } else { 0.0 }; + let mut shrink = 0.0; let mut last_ok: Option<(usize, bool)> = None; // (break position = end glyph, hyphen) + let mut last_space: Option<(usize, f64)> = None; // (break position, line width there) let mut i = start; let mut brk: Option<(usize, bool, bool)> = None; while i < n { @@ -363,33 +600,45 @@ pub fn greedy(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing, width: &dyn F } if g.is_space() && !g.no_break { if sp.justify { - spaces_shrink += g.adv * (sp.word_desired - sp.word_min).max(0.0) / sp.word_desired.max(1e-6); + shrink += sp.space_elastic(g).1; } last_ok = Some((i, false)); + last_space = Some((i, x)); x += g.adv; i += 1; continue; } - let hy = if hyph_after[i] { g.size * 0.33 } else { 0.0 }; - if x + g.adv > w + spaces_shrink && i > start { + let hang_r = if sp.optical { hang_right(g) } else { 0.0 }; + if x + g.adv - hang_r > w + shrink && i > start { // Overflow: break at the last opportunity, else before this glyph. brk = Some(match last_ok { + // Hyphenation zone: break before the word if that leaves little space. + Some((_, true)) if !sp.justify && sp.hyph_zone > 0.0 && last_space.is_some_and(|(_, xs)| w - xs < sp.hyph_zone) => { + (last_space.map_or(i, |s| s.0), false, false) + } Some((p, h)) => (p, h, false), None => (i, false, false), }); break; } x += g.adv; + if sp.justify { + shrink += sp.box_elastic(g).1.iter().sum::(); + } if i + 1 < n && !glyphs[i + 1].is_space() && !g.no_break { if matches!(g.ch, '-' | '\u{2010}' | '\u{2013}' | '\u{2014}' | '/') { last_ok = Some((i + 1, false)); - } else if hyph_after[i] && x + hy <= w + spaces_shrink { - last_ok = Some((i + 1, true)); + } else if hyph_after[i] && may_hyphenate(hyphens) { + let hy = hyphen_width(g, &mut hy_cache) * if sp.optical { 1.0 - hang('-').1 } else { 1.0 }; + if x + hy <= w + shrink { + last_ok = Some((i + 1, true)); + } } } i += 1; } let (end, hyphen, forced) = brk.unwrap_or((n, false, true)); + hyphens = if hyphen { hyphens + 1 } else { 0 }; let mut vis_end = end; while vis_end > start && glyphs[vis_end - 1].is_space() { vis_end -= 1; @@ -414,3 +663,58 @@ pub fn greedy(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing, width: &dyn F } out } + +/// Natural width of a broken line (with its inserted hyphen). +pub fn line_width(glyphs: &[Glyph], b: &Break) -> f64 { + let w: f64 = glyphs[b.start..b.end.max(b.start)].iter().map(|g| g.adv).sum(); + w + if b.hyphen && b.end > 0 { glyphs[b.end - 1].size * 0.33 } else { 0.0 } +} + +/// Balance Ragged Lines: keep the composer's line count but make the lines as even as possible, +/// by composing against the narrowest measure that still yields that many lines. +pub fn balanced(glyphs: &[Glyph], hyph_after: &[bool], sp: &Spacing, width: &dyn Fn(usize) -> f64) -> Vec { + let base = knuth_plass(glyphs, hyph_after, sp, width); + let n = base.len(); + if n < 2 || glyphs.len() > 3000 || base[..n - 1].iter().any(|b| b.forced) { + return base; + } + let ok = |f: f64| -> Option> { + let w = |j: usize| width(j) * f; + let br = knuth_plass(glyphs, hyph_after, sp, &w); + (br.len() == n && br.iter().enumerate().all(|(j, b)| line_width(glyphs, b) <= w(j) + 0.01)).then_some(br) + }; + let (mut lo, mut hi) = (0.3, 1.0); + let mut best = base; + for _ in 0..14 { + let mid = (lo + hi) / 2.0; + match ok(mid) { + Some(b) => { + best = b; + hi = mid; + } + None => lo = mid, + } + } + best +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tiers_are_used_in_order() { + // Word stretch alone. + let (r, ok) = tiered_ratio(5.0, [10.0, 10.0, 10.0], [0.0; 3]); + assert!(ok && (r - 0.5).abs() < 1e-9); + // Word saturated, half the letter tier. + let (r, _) = tiered_ratio(15.0, [10.0, 10.0, 10.0], [0.0; 3]); + assert!((r - (1.0 + 0.5 * TIER_COST[1])).abs() < 1e-9); + // Beyond every tier: unbounded word spacing. + let (r, _) = tiered_ratio(40.0, [10.0, 10.0, 10.0], [0.0; 3]); + assert!(r > 2.0); + // Shrink beyond the tiers is infeasible. + assert!(!tiered_ratio(-25.0, [0.0; 3], [10.0, 10.0, 0.0]).1); + assert!(tiered_ratio(-15.0, [0.0; 3], [10.0, 10.0, 0.0]).1); + } +} diff --git a/crates/compose/src/hyphen.rs b/crates/compose/src/hyphen.rs deleted file mode 100644 index 29afcc3..0000000 --- a/crates/compose/src/hyphen.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! Dictionary-free English hyphenation (ours): breaks between syllables at vowel–consonant -//! boundaries (V-CV "ty-po", VC-CV "hap-pen"), respecting onset clusters ("gra-phy"). -//! -//! A Liang pattern engine with loadable pattern sets is planned (see plan/adr); patterns are only -//! bundled once their licence is confirmed to fit the asset policy. - -/// Hyphenation limits from the paragraph's Hyphenation settings. -#[derive(Clone, Copy, Debug)] -pub struct Limits { - pub min_word: usize, - pub after_first: usize, - pub before_last: usize, - pub capitalized: bool, -} - -impl Default for Limits { - fn default() -> Self { - Limits { min_word: 5, after_first: 2, before_last: 2, capitalized: true } - } -} - -fn is_vowel(c: char) -> bool { - matches!(c.to_ascii_lowercase(), 'a' | 'e' | 'i' | 'o' | 'u' | 'y') || (c.is_alphabetic() && !c.is_ascii()) -} - -fn onset_pair(a: char, b: char) -> bool { - let (a, b) = (a.to_ascii_lowercase(), b.to_ascii_lowercase()); - matches!( - (a, b), - ('c' | 's' | 't' | 'p' | 'w' | 'g', 'h') - | ('b' | 'c' | 'd' | 'f' | 'g' | 'k' | 'p' | 't', 'r') - | ('b' | 'c' | 'f' | 'g' | 'k' | 'p' | 's', 'l') - | ('q', 'u') - | ('s', 't' | 'p' | 'c' | 'k') - ) -} - -/// Common English suffixes that form their own syllable (break before them). -/// Common English prefixes (break after them). -const PREFIXES: &[&str] = &["re", "de", "pre", "un", "dis", "con", "com", "inter", "over", "under", "trans", "sub", "super", "anti", "auto"]; - -const SUFFIXES: &[&str] = &["tion", "sion", "ment", "ness", "less", "ful", "able", "ible", "ing", "ly"]; - -/// Allowed hyphenation points in `word` as char indices (a hyphen goes before that char). -pub fn hyphen_points(word: &str, lim: &Limits) -> Vec { - let c: Vec = word.chars().collect(); - let n = c.len(); - let min_before = lim.after_first.max(1); - let min_after = lim.before_last.max(1); - if n < lim.min_word.max(2) || n < min_before + min_after || !c.iter().all(|c| c.is_alphabetic() || matches!(c, '\'' | '’')) { - return vec![]; - } - if c.iter().all(|c| c.is_uppercase()) || (!lim.capitalized && c[0].is_uppercase()) { - return vec![]; - } - let v: Vec = c.iter().map(|&x| is_vowel(x)).collect(); - let lower: String = word.to_lowercase(); - let mut out = vec![]; - for i in min_before..=n - min_after { - if !c[i].is_alphabetic() || !c[i - 1].is_alphabetic() { - continue; - } - let suffix_at = SUFFIXES.iter().any(|s| { - let sl = s.chars().count(); - n - i == sl && lower.ends_with(s) && v[..i].iter().any(|x| *x) - }); - let prefix_at = PREFIXES.iter().any(|p| p.chars().count() == i && lower.starts_with(p) && n - i >= 4 && c[i..].iter().any(|x| is_vowel(*x))); - let ok = suffix_at - || prefix_at - || if v[i - 1] && !v[i] { - (i + 1 < n && v[i + 1]) || (i + 2 < n && onset_pair(c[i], c[i + 1]) && v[i + 2]) - } else if !v[i - 1] && !v[i] { - i >= 2 && v[i - 2] && i + 1 < n && v[i + 1] && !onset_pair(c[i - 1], c[i]) && c[i - 1] != c[i] - || (c[i - 1] == c[i] && i >= 2 && v[i - 2]) - } else { - false - }; - // Both parts need a sounded vowel: a trailing silent `e`, `ed` or `es` doesn't count - // ("strai-ned" is wrong, "re-strained" is right). - let right: String = c[i..].iter().collect::().to_lowercase(); - let right_core = right.strip_suffix("ed").or_else(|| right.strip_suffix("es")).or_else(|| right.strip_suffix('e')).unwrap_or(&right); - let sounded = right_core.chars().any(is_vowel) && right_core.len() > 1; - let ok = ok && sounded && v[..i].iter().any(|x| *x); - if ok && !out.contains(&i) { - out.push(i); - } - } - out.sort(); - out -} - -/// `word` with `-` at every hyphenation point (tests and diagnostics). -pub fn hyphenate_word(word: &str, lim: &Limits) -> String { - let pts = hyphen_points(word, lim); - let mut s = String::with_capacity(word.len() + pts.len()); - for (i, ch) in word.chars().enumerate() { - if pts.contains(&i) { - s.push('-'); - } - s.push(ch); - } - s -} - -#[cfg(test)] -mod tests { - use super::*; - - fn h(w: &str) -> String { - hyphenate_word(w, &Limits::default()) - } - - #[test] - fn common_words() { - assert_eq!(h("happen"), "hap-pen"); - assert_eq!(h("typography"), "ty-po-gra-phy"); - assert!(h("composition").contains("com-")); - assert_eq!(h("cat"), "cat"); - assert!(!h("restrained").contains("-ned"), "{}", h("restrained")); - assert!(!h("changed").contains('-')); - assert!(h("restrained").starts_with("re-"), "{}", h("restrained")); - assert_eq!(h("NASA"), "NASA"); - } - - #[test] - fn limits_are_respected() { - let lim = Limits { min_word: 5, after_first: 3, before_last: 3, capitalized: false }; - for w in ["typography", "hyphenation", "justification", "Paragraph", "beautiful"] { - for p in hyphen_points(w, &lim) { - assert!(p >= 3 && p <= w.chars().count() - 3, "{w} {p}"); - } - } - assert!(hyphen_points("Paragraph", &lim).is_empty()); - } -} diff --git a/crates/compose/src/hyphen/dict.rs b/crates/compose/src/hyphen/dict.rs new file mode 100644 index 0000000..83a54d4 --- /dev/null +++ b/crates/compose/src/hyphen/dict.rs @@ -0,0 +1,150 @@ +//! Hyphenation exception dictionary: lowercase words with their break points. +//! +//! On-disk format (`assets/hyphenation/en-us.dic`): raw-deflate of +//! `"DCHYPH1\n"` followed by one line per word, sorted by the plain word's bytes. Each line is +//! front-coded against the previous one: a byte with the shared prefix length (in bytes of the +//! hyphenated form), then the rest of the hyphenated form (`-` at every break), then `\n`. + +/// Sorted word list with a break bitmask per word (bit `i` = hyphen before char `i`). +#[derive(Clone, Debug, Default)] +pub struct Dictionary { + words: String, + offs: Vec, + masks: Vec, +} + +const MAGIC: &[u8] = b"DCHYPH1\n"; + +impl Dictionary { + /// Build from `(lowercase word, break mask)` pairs (sorted and de-duplicated here; the first + /// entry of a duplicate wins). + pub fn from_entries(mut entries: Vec<(String, u64)>) -> Dictionary { + entries.sort_by(|a, b| a.0.as_bytes().cmp(b.0.as_bytes())); + entries.dedup_by(|b, a| a.0 == b.0); + let mut d = Dictionary { words: String::new(), offs: vec![0], masks: Vec::with_capacity(entries.len()) }; + for (w, m) in entries { + d.words.push_str(&w); + d.offs.push(d.words.len() as u32); + d.masks.push(m); + } + d + } + + pub fn len(&self) -> usize { + self.masks.len() + } + + pub fn is_empty(&self) -> bool { + self.masks.is_empty() + } + + fn word(&self, i: usize) -> &str { + &self.words[self.offs[i] as usize..self.offs[i + 1] as usize] + } + + /// Break mask of an exact (already lowercased) word. + pub fn get(&self, word: &str) -> Option { + let (mut lo, mut hi) = (0usize, self.len()); + while lo < hi { + let mid = (lo + hi) / 2; + match self.word(mid).as_bytes().cmp(word.as_bytes()) { + std::cmp::Ordering::Less => lo = mid + 1, + std::cmp::Ordering::Greater => hi = mid, + std::cmp::Ordering::Equal => return Some(self.masks[mid]), + } + } + None + } + + /// Iterate `(word, mask)`. + pub fn iter(&self) -> impl Iterator + '_ { + (0..self.len()).map(|i| (self.word(i), self.masks[i])) + } + + /// Serialize (deflate-compressed). + pub fn to_bytes(&self) -> Vec { + let mut raw = MAGIC.to_vec(); + let mut prev: Vec = Vec::new(); + for (w, m) in self.iter() { + let h = hyphenated(w, m).into_bytes(); + let p = prev.iter().zip(&h).take_while(|(a, b)| a == b).count().min(255); + raw.push(p as u8); + raw.extend_from_slice(&h[p..]); + raw.push(b'\n'); + prev = h; + } + miniz_oxide::deflate::compress_to_vec(&raw, 10) + } + + /// Deserialize data written by [`Dictionary::to_bytes`]. + pub fn from_bytes(data: &[u8]) -> Result { + let raw = miniz_oxide::inflate::decompress_to_vec(data).map_err(|e| format!("hyphenation dictionary: inflate failed: {e:?}"))?; + let body = raw.strip_prefix(MAGIC).ok_or("hyphenation dictionary: bad header")?; + let mut d = Dictionary { words: String::with_capacity(body.len()), offs: vec![0], masks: Vec::new() }; + let mut cur: Vec = Vec::new(); + let mut i = 0; + while i < body.len() { + let p = body[i] as usize; + let end = body[i + 1..].iter().position(|&b| b == b'\n').map(|e| i + 1 + e).ok_or("hyphenation dictionary: truncated")?; + if p > cur.len() { + return Err("hyphenation dictionary: bad prefix".into()); + } + cur.truncate(p); + cur.extend_from_slice(&body[i + 1..end]); + i = end + 1; + let s = std::str::from_utf8(&cur).map_err(|_| "hyphenation dictionary: bad utf-8")?; + let (w, m) = parse_hyphenated(s); + d.words.push_str(&w); + d.offs.push(d.words.len() as u32); + d.masks.push(m); + } + Ok(d) + } +} + +/// `word` with `-` before every char whose bit is set in `mask`. +pub fn hyphenated(word: &str, mask: u64) -> String { + let mut s = String::with_capacity(word.len() + 8); + for (i, c) in word.chars().enumerate() { + if i > 0 && i < 64 && mask & (1 << i) != 0 { + s.push('-'); + } + s.push(c); + } + s +} + +/// Inverse of [`hyphenated`]. +pub fn parse_hyphenated(s: &str) -> (String, u64) { + let mut w = String::with_capacity(s.len()); + let mut m = 0u64; + let mut n = 0; + for c in s.chars() { + if c == '-' { + if n > 0 && n < 64 { + m |= 1 << n; + } + } else { + w.push(c); + n += 1; + } + } + (w, m) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn roundtrip() { + let e: Vec<(String, u64)> = ["ty-pog-ra-phy", "cat", "hap-pen", "o'clock", "naïve-té", "naïve"].iter().map(|s| parse_hyphenated(s)).collect(); + let d = Dictionary::from_entries(e); + let back = Dictionary::from_bytes(&d.to_bytes()).unwrap(); + assert_eq!(back.len(), 6); + assert_eq!(back.get("typography").map(|m| hyphenated("typography", m)), Some("ty-pog-ra-phy".to_string())); + assert_eq!(back.get("cat"), Some(0)); + assert_eq!(back.get("naïveté").map(|m| hyphenated("naïveté", m)), Some("naïve-té".to_string())); + assert!(back.get("dog").is_none()); + } +} diff --git a/crates/compose/src/hyphen/mod.rs b/crates/compose/src/hyphen/mod.rs new file mode 100644 index 0000000..23d182a --- /dev/null +++ b/crates/compose/src/hyphen/mod.rs @@ -0,0 +1,327 @@ +//! English hyphenation. +//! +//! Lookup order for each word: +//! 1. the **dictionary** ([`Dictionary::en_us`]) — the public-domain Moby Hyphenator II word list +//! by Grady Ward (~160k words), stored compactly in `assets/hyphenation/en-us.dic`; simple +//! inflections (`'s`, `-s`, `-es`, `-ed`, `-d`) inherit the breaks of their stem; +//! 2. **Liang patterns** ([`Patterns::en_us`]) for words not in the dictionary — our own pattern +//! set, trained from the same list by [`patgen`] (`examples/hyphgen.rs` regenerates both files); +//! 3. a small syllable **heuristic** for words outside the pattern alphabet. +//! +//! Then the paragraph's limits ([`Limits`]) are applied. + +pub mod dict; +pub mod patgen; +pub mod patterns; + +use std::sync::OnceLock; + +pub use dict::Dictionary; +pub use patterns::Patterns; + +static EN_US_DIC: &[u8] = include_bytes!("../../../../assets/hyphenation/en-us.dic"); +static EN_US_PAT: &str = include_str!("../../../../assets/hyphenation/en-us.pat"); + +impl Dictionary { + /// The bundled US English dictionary (decoded on first use). + pub fn en_us() -> &'static Dictionary { + static D: OnceLock = OnceLock::new(); + D.get_or_init(|| { + if EN_US_DIC.is_empty() { + return Dictionary::default(); + } + Dictionary::from_bytes(EN_US_DIC).unwrap_or_else(|e| { + log::error!("{e}"); + Dictionary::default() + }) + }) + } +} + +impl Patterns { + /// The bundled US English patterns (parsed on first use). + pub fn en_us() -> &'static Patterns { + static P: OnceLock = OnceLock::new(); + P.get_or_init(|| Patterns::parse(EN_US_PAT)) + } +} + +/// Hyphenation limits from the paragraph's Hyphenation settings. +#[derive(Clone, Copy, Debug)] +pub struct Limits { + pub min_word: usize, + pub after_first: usize, + pub before_last: usize, + pub capitalized: bool, +} + +impl Default for Limits { + fn default() -> Self { + Limits { min_word: 5, after_first: 2, before_last: 2, capitalized: true } + } +} + +/// Where a word's break points came from. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Source { + Dictionary, + Patterns, + Heuristic, + None, +} + +fn is_apostrophe(c: char) -> bool { + matches!(c, '\'' | '’' | 'ʼ') +} + +fn is_word_char(c: char) -> bool { + c.is_alphabetic() || is_apostrophe(c) +} + +/// Unrestricted break points of one lowercase core (letters and `'` only, no leading/trailing `'`). +fn core_breaks(core: &[char]) -> (Vec, Source) { + let n = core.len(); + if n < 2 { + return (vec![], Source::None); + } + let dict = Dictionary::en_us(); + let s: String = core.iter().collect(); + let from_mask = |m: u64, len: usize| (1..len.min(64)).filter(|&i| m & (1 << i) != 0).collect::>(); + if let Some(m) = dict.get(&s) { + return (from_mask(m, n), Source::Dictionary); + } + // Inflections inherit the stem's breaks (the suffix adds no break of its own). + for suf in ["'s", "s", "es", "ed", "d"] { + if let Some(stem) = s.strip_suffix(suf) + && stem.chars().count() >= 2 + && let Some(m) = dict.get(stem) + { + return (from_mask(m, stem.chars().count()), Source::Dictionary); + } + } + let pats = Patterns::en_us(); + if !pats.is_empty() + && let Some(p) = pats.points(core) + { + return (p, Source::Patterns); + } + (heuristic_points(core), Source::Heuristic) +} + +/// Unrestricted break points of `word` (char indices; a hyphen goes before that char), handling +/// case, apostrophes (`don't`, `’s`), surrounding punctuation and compounds (each letter run is +/// hyphenated separately). No break is ever placed next to an apostrophe or non-letter. +pub fn word_breaks(word: &str) -> (Vec, Source) { + let chars: Vec = word.chars().collect(); + let mut out = Vec::new(); + let mut src = Source::None; + let mut i = 0; + while i < chars.len() { + if !is_word_char(chars[i]) { + i += 1; + continue; + } + let mut j = i; + while j < chars.len() && is_word_char(chars[j]) { + j += 1; + } + let (mut a, mut b) = (i, j); + while a < b && is_apostrophe(chars[a]) { + a += 1; + } + while b > a && is_apostrophe(chars[b - 1]) { + b -= 1; + } + let core: Vec = chars[a..b].iter().map(|&c| if is_apostrophe(c) { '\'' } else { c.to_lowercase().next().unwrap_or(c) }).collect(); + let (pts, s) = core_breaks(&core); + if src == Source::None { + src = s; + } + out.extend(pts.into_iter().filter(|&p| p > 0 && p < core.len() && core[p - 1] != '\'' && core[p] != '\'').map(|p| a + p)); + i = j; + } + (out, src) +} + +/// Allowed hyphenation points in `word` as char indices (a hyphen goes before that char), with +/// the paragraph limits applied to each letter run. +pub fn hyphen_points(word: &str, lim: &Limits) -> Vec { + let chars: Vec = word.chars().collect(); + let (pts, _) = word_breaks(word); + if pts.is_empty() { + return pts; + } + let min_before = lim.after_first.max(1); + let min_after = lim.before_last.max(1); + // Run bounds of each point's letter run (trimmed of apostrophes). + let run_of = |p: usize| { + let mut a = p; + while a > 0 && is_word_char(chars[a - 1]) { + a -= 1; + } + let mut b = p; + while b < chars.len() && is_word_char(chars[b]) { + b += 1; + } + while a < b && is_apostrophe(chars[a]) { + a += 1; + } + while b > a && is_apostrophe(chars[b - 1]) { + b -= 1; + } + (a, b) + }; + pts.into_iter() + .filter(|&p| { + let (a, b) = run_of(p); + let run = &chars[a..b]; + let letters = run.iter().filter(|c| c.is_alphabetic()).count(); + if letters < lim.min_word.max(2) { + return false; + } + if letters > 1 && run.iter().filter(|c| c.is_alphabetic()).all(|c| c.is_uppercase()) { + return false; + } + if !lim.capitalized && run[0].is_uppercase() { + return false; + } + let before = chars[a..p].iter().filter(|c| c.is_alphabetic()).count(); + let after = chars[p..b].iter().filter(|c| c.is_alphabetic()).count(); + before >= min_before && after >= min_after + }) + .collect() +} + +/// `word` with `-` at every hyphenation point (tests and diagnostics). +pub fn hyphenate_word(word: &str, lim: &Limits) -> String { + let pts = hyphen_points(word, lim); + let mut s = String::with_capacity(word.len() + pts.len()); + for (i, ch) in word.chars().enumerate() { + if pts.contains(&i) { + s.push('-'); + } + s.push(ch); + } + s +} + +// ---------- heuristic fallback (words outside the pattern alphabet) ---------- + +fn is_vowel(c: char) -> bool { + matches!(c.to_ascii_lowercase(), 'a' | 'e' | 'i' | 'o' | 'u' | 'y') || (c.is_alphabetic() && !c.is_ascii()) +} + +fn onset_pair(a: char, b: char) -> bool { + let (a, b) = (a.to_ascii_lowercase(), b.to_ascii_lowercase()); + matches!( + (a, b), + ('c' | 's' | 't' | 'p' | 'w' | 'g', 'h') + | ('b' | 'c' | 'd' | 'f' | 'g' | 'k' | 'p' | 't', 'r') + | ('b' | 'c' | 'f' | 'g' | 'k' | 'p' | 's', 'l') + | ('q', 'u') + | ('s', 't' | 'p' | 'c' | 'k') + ) +} + +/// Syllable heuristic: V-CV ("ty-po"), VC-CV ("hap-pen"), keeping onset clusters ("gra-phy"). +fn heuristic_points(c: &[char]) -> Vec { + let n = c.len(); + if n < 4 || !c.iter().all(|c| c.is_alphabetic()) { + return vec![]; + } + let v: Vec = c.iter().map(|&x| is_vowel(x)).collect(); + let mut out = vec![]; + for i in 1..n { + let ok = if v[i - 1] && !v[i] { + (i + 1 < n && v[i + 1]) || (i + 2 < n && onset_pair(c[i], c[i + 1]) && v[i + 2]) + } else if !v[i - 1] && !v[i] { + i >= 2 && v[i - 2] && i + 1 < n && v[i + 1] && !onset_pair(c[i - 1], c[i]) && c[i - 1] != c[i] || (c[i - 1] == c[i] && i >= 2 && v[i - 2]) + } else { + false + }; + // Both parts need a sounded vowel: a trailing silent `e`, `ed` or `es` doesn't count. + let right: String = c[i..].iter().collect(); + let core = right.strip_suffix("ed").or_else(|| right.strip_suffix("es")).or_else(|| right.strip_suffix('e')).unwrap_or(&right); + if ok && core.chars().any(is_vowel) && core.len() > 1 && v[..i].iter().any(|x| *x) { + out.push(i); + } + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + fn h(w: &str) -> String { + hyphenate_word(w, &Limits::default()) + } + + #[test] + fn bundled_data_loads() { + assert!(Dictionary::en_us().len() > 150_000, "{}", Dictionary::en_us().len()); + assert!(Patterns::en_us().len() > 1000, "{}", Patterns::en_us().len()); + } + + #[test] + fn dictionary_words() { + assert_eq!(h("happen"), "hap-pen"); + assert_eq!(h("typography"), "ty-pog-ra-phy"); + assert_eq!(h("composition"), "com-po-si-tion"); + assert_eq!(h("hyphenation"), "hy-phen-a-tion"); + assert_eq!(h("international"), "in-ter-na-tion-al"); + assert_eq!(h("cat"), "cat"); + assert!(!h("changed").contains('-')); + assert_eq!(h("NASA"), "NASA"); + assert_eq!(word_breaks("publication").1, Source::Dictionary); + } + + #[test] + fn case_apostrophes_and_punctuation() { + assert_eq!(h("Typography"), "Ty-pog-ra-phy"); + assert_eq!(h("TYPOGRAPHY"), "TYPOGRAPHY"); + assert_eq!(h("typography,"), "ty-pog-ra-phy,"); + assert_eq!(h("“typography”"), "“ty-pog-ra-phy”"); + assert_eq!(h("typography's"), "ty-pog-ra-phy's"); + assert_eq!(h("typography’s"), "ty-pog-ra-phy’s"); + assert_eq!(h("'typography'"), "'ty-pog-ra-phy'"); + // Compounds: each part separately, never next to the hyphen. + assert_eq!(h("typography-composition"), "ty-pog-ra-phy-com-po-si-tion"); + } + + #[test] + fn inflections_inherit_the_stem() { + assert_eq!(h("ripples"), "rip-ples"); + assert_eq!(h("gradients"), "gra-di-ents"); + assert_eq!(h("restrained"), "re-strained"); + } + + #[test] + fn patterns_cover_unknown_words() { + // Not in the word list: the trained patterns decide. + let (pts, src) = word_breaks("hyperlocalization"); + assert_eq!(src, Source::Patterns); + assert!(pts.len() >= 4, "{}", h("hyperlocalization")); + let (_, src) = word_breaks("zzyzx"); + assert_ne!(src, Source::Dictionary); + } + + #[test] + fn limits_are_respected() { + let lim = Limits { min_word: 5, after_first: 3, before_last: 3, capitalized: false }; + for w in ["typography", "hyphenation", "justification", "Paragraph", "beautiful"] { + for p in hyphen_points(w, &lim) { + assert!(p >= 3 && p <= w.chars().count() - 3, "{w} {p}"); + } + } + assert!(hyphen_points("Paragraph", &lim).is_empty()); + let lim = Limits { min_word: 12, ..Limits::default() }; + assert!(hyphen_points("typography", &lim).is_empty()); + } + + #[test] + fn heuristic_fallback() { + let c: Vec = "happen".chars().collect(); + assert_eq!(heuristic_points(&c), vec![3]); + } +} diff --git a/crates/compose/src/hyphen/patgen.rs b/crates/compose/src/hyphen/patgen.rs new file mode 100644 index 0000000..d87087d --- /dev/null +++ b/crates/compose/src/hyphen/patgen.rs @@ -0,0 +1,240 @@ +//! A small patgen-style trainer (ours): learns Liang hyphenation patterns from a hyphenated word +//! list, level by level. Odd levels add hyphenating patterns, even levels add inhibiting ones. +//! +//! At level `L`, for every pattern length, each inter-letter position whose current value is +//! below `L` is classified as *good* (applying value `L` would fix it) or *bad* (it would break a +//! position that is currently right). A candidate (letters + value position) is selected when +//! `good·good_weight − bad·bad_weight ≥ threshold`; selected patterns are applied to every word +//! before the next length is considered. Used offline by `examples/hyphgen.rs`. + +use super::patterns::{Alphabet, FxMap, MAX_PATTERN_LEN, Patterns, apply, pack}; + +/// Parameters of one level. +#[derive(Clone, Copy, Debug)] +pub struct Level { + pub min_len: usize, + pub max_len: usize, + pub good_weight: u32, + pub bad_weight: u32, + pub threshold: u32, +} + +/// Defaults tuned on the Moby list (see `examples/hyphgen.rs`). +pub const DEFAULT_LEVELS: &[Level] = &[ + Level { min_len: 1, max_len: 4, good_weight: 1, bad_weight: 2, threshold: 20 }, + Level { min_len: 2, max_len: 5, good_weight: 2, bad_weight: 1, threshold: 8 }, + Level { min_len: 3, max_len: 6, good_weight: 1, bad_weight: 4, threshold: 7 }, + Level { min_len: 3, max_len: 7, good_weight: 3, bad_weight: 2, threshold: 2 }, + Level { min_len: 4, max_len: 8, good_weight: 1, bad_weight: 20, threshold: 6 }, + Level { min_len: 4, max_len: 8, good_weight: 3, bad_weight: 1, threshold: 2 }, +]; + +struct Word { + /// Padded codes: boundary, letters…, boundary. + codes: Vec, + /// Correct hyphen before padded char `p`. + hyph: Vec, + vals: Vec, +} + +/// Accuracy of a pattern set over a word list. +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Score { + pub words: usize, + pub breaks: usize, + pub found: usize, + pub wrong: usize, +} + +impl Score { + pub fn missed(&self) -> usize { + self.breaks - self.found + } +} + +/// Train patterns from `(lowercase word, break char indices)` pairs. `log` receives progress lines. +pub fn train(words: &[(Vec, Vec)], levels: &[Level], log: &mut dyn FnMut(String)) -> Patterns { + let mut alpha = Alphabet::default(); + let mut data: Vec = Vec::with_capacity(words.len()); + 'w: for (w, br) in words { + let mut codes = Vec::with_capacity(w.len() + 2); + codes.push(1); + for &c in w { + let Some(k) = alpha.intern(c) else { continue 'w }; + codes.push(k); + } + codes.push(1); + let mut hyph = vec![false; codes.len() + 1]; + for &b in br { + if b > 0 && b < w.len() { + hyph[b + 1] = true; + } + } + let vals = vec![0; codes.len() + 1]; + data.push(Word { codes, hyph, vals }); + } + let mut pats: FxMap> = FxMap::default(); + let mut max_len = 0usize; + for (li, lv) in levels.iter().enumerate() { + let level = (li + 1) as u8; + let hyphenating = level % 2 == 1; + for len in lv.min_len..=lv.max_len.min(MAX_PATTERN_LEN) { + // (packed letters | dot) → (good, bad) + let mut counts: FxMap = FxMap::default(); + for w in &data { + let n = w.codes.len(); + // Positions strictly between the word's letters. + for p in 2..n - 1 { + let v = w.vals[p]; + if v >= level { + continue; + } + let (good, bad) = if hyphenating { + (w.hyph[p] && v % 2 == 0, !w.hyph[p] && v % 2 == 0) + } else { + (!w.hyph[p] && v % 2 == 1, w.hyph[p] && v % 2 == 1) + }; + if !good && !bad { + continue; + } + for dot in 0..=len { + if p < dot || p - dot + len > n { + continue; + } + let s = p - dot; + let key = pack(&w.codes[s..s + len]) | ((dot as u64) << 54); + let e = counts.entry(key).or_default(); + if good { + e.0 += 1; + } else { + e.1 += 1; + } + } + } + } + // Select. + let mut new: FxMap> = FxMap::default(); + let mut selected = 0usize; + for (key, (g, b)) in counts { + if g > 0 && (g * lv.good_weight) as i64 - (b * lv.bad_weight) as i64 >= lv.threshold as i64 { + let dot = ((key >> 54) & 15) as usize; + let letters = key & !(15u64 << 54); + let e = new.entry(letters).or_insert_with(|| vec![0u8; len + 1].into_boxed_slice()); + e[dot] = level; + selected += 1; + } + } + if selected == 0 { + continue; + } + for w in &mut data { + apply(&new, len, &w.codes, &mut w.vals); + } + for (k, v) in new { + let e = pats.entry(k).or_insert_with(|| vec![0u8; len + 1].into_boxed_slice()); + for (a, b) in e.iter_mut().zip(v.iter()) { + *a = (*a).max(*b); + } + } + max_len = max_len.max(len); + let sc = score_vals(&data); + log(format!("level {level} len {len}: +{selected} patterns ({} total); found {}/{} wrong {}", pats.len(), sc.found, sc.breaks, sc.wrong)); + } + } + // Re-express through the public pattern type (TeX strings) so the alphabet matches at runtime. + let tmp = Patterns::from_parts(alpha, pats, max_len); + let mut out = Patterns::default(); + out.add_letters(words.iter().flat_map(|w| w.0.iter().copied())); + for t in tmp.to_tex() { + out.insert(&t); + } + out +} + +fn score_vals(data: &[Word]) -> Score { + let mut s = Score { words: data.len(), ..Default::default() }; + for w in data { + for p in 2..w.codes.len() - 1 { + let on = w.vals[p] % 2 == 1; + if w.hyph[p] { + s.breaks += 1; + if on { + s.found += 1; + } + } else if on { + s.wrong += 1; + } + } + } + s +} + +/// Score `pats` against a word list. +pub fn score(pats: &Patterns, words: &[(Vec, Vec)]) -> Score { + let mut s = Score::default(); + for (w, br) in words { + let Some(pts) = pats.points(w) else { continue }; + s.words += 1; + s.breaks += br.len(); + for p in &pts { + if br.contains(p) { + s.found += 1; + } else { + s.wrong += 1; + } + } + } + s +} + +#[cfg(test)] +mod tests { + use super::*; + + fn w(s: &str) -> (Vec, Vec) { + let mut chars = Vec::new(); + let mut br = Vec::new(); + for c in s.chars() { + if c == '-' { + br.push(chars.len()); + } else { + chars.push(c); + } + } + (chars, br) + } + + #[test] + fn learns_a_tiny_list() { + let list: Vec<_> = [ + "hap-pen", + "hap-pens", + "hap-pened", + "pen-cil", + "pen-cils", + "rab-bit", + "rab-bits", + "kit-ten", + "kit-tens", + "but-ter", + "bet-ter", + "let-ter", + "lit-ter", + "sit-ter", + ] + .iter() + .map(|s| w(s)) + .collect(); + let levels = [ + Level { min_len: 1, max_len: 4, good_weight: 1, bad_weight: 1, threshold: 2 }, + Level { min_len: 1, max_len: 5, good_weight: 1, bad_weight: 1, threshold: 1 }, + ]; + let p = train(&list, &levels, &mut |_| {}); + let sc = score(&p, &list); + assert_eq!(sc.breaks, list.len()); + assert!(sc.found >= sc.breaks - 1, "{sc:?}"); + assert!(sc.wrong <= 1, "{sc:?}"); + // Generalises to an unseen word with the same shape. + assert_eq!(p.points(&"bitter".chars().collect::>()).unwrap(), vec![3]); + } +} diff --git a/crates/compose/src/hyphen/patterns.rs b/crates/compose/src/hyphen/patterns.rs new file mode 100644 index 0000000..1bb588b --- /dev/null +++ b/crates/compose/src/hyphen/patterns.rs @@ -0,0 +1,239 @@ +//! Liang hyphenation patterns (TeX notation, e.g. `.ab1c`, `4t1ion`): parsing and application. +//! +//! The bundled English set is *ours*: trained from the public-domain Moby Hyphenator word list by +//! [`super::patgen`] (see `examples/hyphgen.rs`). Patterns are stored in a hash map keyed by the +//! packed letter string, so applying them to a word costs `O(len × max_pattern_len)` lookups. + +use std::collections::HashMap; +use std::hash::{BuildHasherDefault, Hasher}; + +/// Word-boundary marker in patterns. +pub const DOT: char = '.'; +/// Longest pattern the packed key supports. +pub const MAX_PATTERN_LEN: usize = 9; + +/// Small, fast multiplicative hasher for packed `u64` keys (FxHash-style). +#[derive(Default, Clone, Copy)] +pub struct FxHasher(u64); + +impl Hasher for FxHasher { + fn finish(&self) -> u64 { + self.0 + } + fn write(&mut self, bytes: &[u8]) { + for &b in bytes { + self.write_u64(b as u64); + } + } + fn write_u64(&mut self, i: u64) { + self.0 = (self.0.rotate_left(5) ^ i).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95); + } +} + +pub type FxMap = HashMap>; + +/// Maps characters to 6-bit codes (1 = word boundary, 2.. = letters); 0 = not in the alphabet. +#[derive(Clone, Debug)] +pub struct Alphabet { + ascii: [u8; 128], + other: Vec<(char, u8)>, + next: u8, +} + +impl Default for Alphabet { + fn default() -> Self { + let mut a = Alphabet { ascii: [0; 128], other: Vec::new(), next: 2 }; + a.ascii[DOT as usize] = 1; + a + } +} + +impl Alphabet { + pub fn code(&self, c: char) -> u8 { + if (c as u32) < 128 { self.ascii[c as usize] } else { self.other.iter().find(|x| x.0 == c).map_or(0, |x| x.1) } + } + /// Code for `c`, adding it if new (None when the 6-bit alphabet is full). + pub fn intern(&mut self, c: char) -> Option { + let k = self.code(c); + if k != 0 { + return Some(k); + } + if self.next >= 63 { + return None; + } + let k = self.next; + self.next += 1; + if (c as u32) < 128 { + self.ascii[c as usize] = k; + } else { + self.other.push((c, k)); + } + Some(k) + } +} + +/// Packed key of a code string (≤ [`MAX_PATTERN_LEN`] codes). +#[inline] +pub fn pack(codes: &[u8]) -> u64 { + let mut k = 0u64; + for &c in codes { + k = (k << 6) | c as u64; + } + k | ((codes.len() as u64) << 58) +} + +/// A compiled pattern set. +#[derive(Clone, Debug, Default)] +pub struct Patterns { + alpha: Alphabet, + /// Packed letters → inter-letter values (`len + 1` entries). + map: FxMap>, + max_len: usize, +} + +impl Patterns { + /// Parse TeX-style patterns: whitespace-separated, `%`/`#` start a comment line. + pub fn parse(text: &str) -> Patterns { + let mut p = Patterns::default(); + for line in text.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('%') || line.starts_with('#') { + continue; + } + for tok in line.split_whitespace() { + p.insert(tok); + } + } + p + } + + /// Add one pattern like `a1b`; returns false if it can't be represented. + pub fn insert(&mut self, pat: &str) -> bool { + let mut codes = Vec::with_capacity(pat.len()); + let mut vals = vec![0u8]; + for c in pat.chars() { + if let Some(d) = c.to_digit(10) { + *vals.last_mut().unwrap_or(&mut 0) = d as u8; + } else { + let Some(k) = self.alpha.intern(c) else { return false }; + codes.push(k); + vals.push(0); + } + } + if codes.is_empty() || codes.len() > MAX_PATTERN_LEN { + return false; + } + self.max_len = self.max_len.max(codes.len()); + self.map.insert(pack(&codes), vals.into_boxed_slice()); + true + } + + pub(crate) fn from_parts(alpha: Alphabet, map: FxMap>, max_len: usize) -> Patterns { + Patterns { alpha, map, max_len } + } + + /// Make `letters` part of the alphabet even if no pattern mentions them. + pub fn add_letters(&mut self, letters: impl IntoIterator) { + for c in letters { + let _ = self.alpha.intern(c); + } + } + + pub fn len(&self) -> usize { + self.map.len() + } + + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Inter-letter values for a lowercase word: `out[i]` is the value *before* char `i` + /// (`out.len() == word.len() + 1`). None if a char is outside the pattern alphabet. + pub fn values(&self, word: &[char]) -> Option> { + let mut codes = Vec::with_capacity(word.len() + 2); + codes.push(1); + for &c in word { + let k = self.alpha.code(c); + if k == 0 { + return None; + } + codes.push(k); + } + codes.push(1); + let mut vals = vec![0u8; codes.len() + 1]; + apply(&self.map, self.max_len, &codes, &mut vals); + // Padded position p sits before padded char p; word char i is padded char i + 1. + Some(vals[1..codes.len()].to_vec()) + } + + /// Break points (char indices, a hyphen goes before that char) of a lowercase word. + pub fn points(&self, word: &[char]) -> Option> { + let v = self.values(word)?; + Some((1..word.len()).filter(|&i| v[i] % 2 == 1).collect()) + } + + /// The patterns in TeX notation (sorted by letters), e.g. for writing a pattern file. + pub fn to_tex(&self) -> Vec { + let mut rev: Vec<(u8, char)> = + (0u8..128).filter(|&c| self.alpha.ascii[c as usize] != 0).map(|c| (self.alpha.ascii[c as usize], c as char)).collect(); + rev.extend(self.alpha.other.iter().map(|&(c, k)| (k, c))); + let ch = |k: u8| rev.iter().find(|x| x.0 == k).map_or('?', |x| x.1); + let mut out: Vec<(String, String)> = self + .map + .iter() + .map(|(&key, vals)| { + let n = (key >> 58) as usize; + let letters: Vec = (0..n).map(|i| ch(((key >> (6 * (n - 1 - i))) & 63) as u8)).collect(); + let mut s = String::new(); + for (i, l) in letters.iter().enumerate() { + if vals[i] > 0 { + s.push(char::from(b'0' + vals[i])); + } + s.push(*l); + } + if vals[n] > 0 { + s.push(char::from(b'0' + vals[n])); + } + (letters.into_iter().collect(), s) + }) + .collect(); + out.sort(); + out.into_iter().map(|x| x.1).collect() + } +} + +/// Apply `map` to padded `codes`, raising `vals` (len = codes.len() + 1). +#[inline] +pub fn apply(map: &FxMap>, max_len: usize, codes: &[u8], vals: &mut [u8]) { + let n = codes.len(); + for s in 0..n { + let mut k = 0u64; + for len in 1..=max_len.min(n - s) { + k = (k << 6) | codes[s + len - 1] as u64; + if let Some(v) = map.get(&(k | ((len as u64) << 58))) { + for (j, &x) in v.iter().enumerate() { + if x > vals[s + j] { + vals[s + j] = x; + } + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn liang_example() { + // The classic example from Liang's thesis: "hy-phen-ation". + let p = Patterns::parse("hy3ph he2n hena4 hen5at 1na n2at 1tio 2io o2n"); + let w: Vec = "hyphenation".chars().collect(); + assert_eq!(p.points(&w).unwrap(), vec![2, 6]); + let mut tex = p.to_tex(); + tex.sort(); + assert!(tex.contains(&"hen5at".to_string())); + assert!(p.values(&['h', 'é']).is_none()); + } +} diff --git a/crates/compose/src/lib.rs b/crates/compose/src/lib.rs index 5b5cbaf..268baca 100644 --- a/crates/compose/src/lib.rs +++ b/crates/compose/src/lib.rs @@ -14,8 +14,9 @@ mod cache; pub mod hyphen; pub mod shape; +use std::collections::HashMap; use std::ops::Range; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use designcraft_doc::{ Align, Composer, Document, FirstBaseline, GridAlign, ItemId, ParaProps, SpanColumns, StartParagraph, Story, StoryId, TabAlign, TextFrameOptions, @@ -246,8 +247,22 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo let cols: Vec> = frames.iter().map(FrameSpec::columns).collect(); let mut cur = Cursor { fi: 0, col: 0, last_baseline: None, last_descent: 0.0, pending: 0.0 }; let para_ranges = story.para_ranges(); + let np = para_ranges.len(); let mut list_counter: u32 = 0; - 'paras: for (pi, prange) in para_ranges.iter().enumerate() { + // Keep options: paragraphs are re-laid from a snapshot when a keep is violated, either forced + // into the next column or with a cap on the lines set before moving on (widow control). + let mut snaps: Vec = Vec::with_capacity(np); + let mut info: Vec = Vec::with_capacity(np); + let mut force_col = vec![false; np]; + let mut line_cap: Vec> = vec![None; np]; + let mut restores = 0usize; + let mut pi = 0; + 'paras: while pi < np { + let prange = para_ranges[pi].clone(); + let snap = Snapshot::take(&out, &cur, list_counter); + snaps.truncate(pi); + snaps.push(snap); + info.truncate(pi); let pf = &story.paras[pi]; let (pp, base_chars) = doc.styles.resolve_para(pf); // Bullets & numbering: generated prefix (shaped as its own glyphs, mapped to the paragraph start). @@ -269,23 +284,19 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo } designcraft_doc::ListType::None => list_counter = 0, } - let glyphs = sp.glyphs; + let mut glyphs = sp.glyphs; + apply_desired_spacing(&mut glyphs, &pp); let hyph_after = hyphenation_points(&story.text, &glyphs, &pp); let base_size = base_chars.size; let base_leading = match base_chars.leading { designcraft_doc::Leading::Auto => base_size * pp.auto_leading, designcraft_doc::Leading::Points(v) => v, }; - let spacing = Spacing { - justify: pp.align.is_justified(), - word_min: pp.word_space_min, - word_desired: pp.word_space_desired, - word_max: pp.word_space_max, - hyphen_penalty: 50.0 + 450.0 * pp.hyph_weight, - hyphen_limit: pp.hyph_limit, - ragged_stretch: base_size * 2.0, - }; + let spacing = spacing_for(&pp, base_size); // Paragraph start options. + if force_col[pi] { + cur.next_column(&cols); + } if cur.last_baseline.is_some() { match pp.start_paragraph { StartParagraph::NextColumn => cur.next_column(&cols), @@ -296,9 +307,13 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo if cur.last_baseline.is_some() { cur.pending += pp.space_before; } + let at_top = cur.last_baseline.is_none(); + let start_at = (cur.fi, cur.col); // Rule above / shading track the paragraph's first line. let mut g0 = 0usize; let mut line_no = 0usize; + // Paragraph line number of the first line in the current column. + let mut col_first_line = 0usize; let has_tabs = glyphs.iter().any(|g| g.ch == '\t'); let mut first_line_rect: Option<(usize, f64, f64, f64)> = None; // frame, baseline, ascent, x-span loop { @@ -327,6 +342,8 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo let rest_h = &hyph_after[g0..]; let breaks: Vec = if pp.composer == Composer::SingleLine || has_tabs || rest.len() > 4000 { breaker::greedy(rest, rest_h, &spacing, &width) + } else if pp.balance_ragged && !spacing.justify { + breaker::balanced(rest, rest_h, &spacing, &width) } else { breaker::knuth_plass(rest, rest_h, &spacing, &width) }; @@ -365,20 +382,54 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo } } } - let fits = baseline + desc <= col.y1 + 0.01; + let capped = line_cap[pi] == Some(line_no) && line_no > col_first_line; + let fits = baseline + desc <= col.y1 + 0.01 && !capped; if !fits { + if !capped { + let ctx = KeepCtx { + pi, + line_no, + in_col: line_no - col_first_line, + started_here: col_first_line == 0, + at_top, + remaining: breaks.len() - k, + here: (cur.fi, cur.col), + }; + let action = if restores < 4 * np + 64 { keep_violation(&ctx, &pp, &info, &force_col, &line_cap) } else { None }; + if let Some(action) = action { + restores += 1; + let j = match action { + KeepAction::Force(j) => { + force_col[j] = true; + j + } + KeepAction::Cap(j, n) => { + line_cap[j] = Some(n); + j + } + }; + for k in j + 1..np { + force_col[k] = false; + line_cap[k] = None; + } + snaps[j].restore(&mut out, &mut cur, &mut list_counter); + pi = j; + continue 'paras; + } + } // Next column / frame; re-break the rest of the paragraph there. g0 = s; cur.next_column(&cols); + col_first_line = line_no; moved = true; - let _ = k; break; } let ind_l = pp.left_indent + if line_no == 0 { pp.first_line_indent } else { 0.0 }; let lx0 = x0 + ind_l; let lx1 = x1 - pp.right_indent; let last = k + 1 == breaks.len(); - let (placed, end_x, ratio) = layout_line(&glyphs, s, e, b.hyphen, lx0, lx1, col.x0, &pp, last, b.forced && !last, f.left_page); + let (placed, end_x, ratio) = + layout_line(&glyphs, s, e, b.hyphen, lx0, lx1, col.x0, &pp, &spacing, last, b.forced && !last, f.left_page); let range_end = if last { prange.end } else { glyphs.get(g0 + b.next).map(|g| g.byte).unwrap_or(prange.end) }; let range_start = glyphs.get(s).map(|g| g.byte).unwrap_or(prange.start).min(range_end); let range_start = if line_no == 0 { prange.start } else { range_start }; @@ -411,8 +462,14 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo if b.forced && e < glyphs.len() + 1 { let brk = glyphs.get(g0 + b.next.saturating_sub(1)).map(|g| g.ch); match brk { - Some(story::COLUMN_BREAK) => cur.next_column(&cols), - Some(story::FRAME_BREAK) | Some(story::PAGE_BREAK) => cur.next_frame(), + Some(story::COLUMN_BREAK) => { + cur.next_column(&cols); + col_first_line = line_no; + } + Some(story::FRAME_BREAK) | Some(story::PAGE_BREAK) => { + cur.next_frame(); + col_first_line = line_no; + } _ => {} } } @@ -421,6 +478,18 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo break; } } + info.push(ParaInfo { + start: start_at, + at_top, + end: (cur.fi, cur.col), + lines: line_no, + lines_in_end_col: line_no - col_first_line, + keep_with_next: pp.keep_with_next, + keep_together: pp.keep_lines_together, + keep_all: pp.keep_all_lines, + keep_first: pp.keep_first as usize, + keep_last: pp.keep_last as usize, + }); // Rules and shading for the paragraph. if let Some((fi, bl, asc, _)) = first_line_rect { let ft = &mut out.frames[fi]; @@ -458,6 +527,7 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo ft.decos.push(Deco { rect: Rect::new(x0 + r.left_indent, y, x1 - r.right_indent, y + r.weight), color: r.color.clone(), tint: r.tint }); } cur.pending += pp.space_after; + pi += 1; } // Ranges, content heights and vertical justification. for (fi, ft) in out.frames.iter_mut().enumerate() { @@ -485,10 +555,185 @@ pub fn compose(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &Compo out } +/// Breaker parameters from the paragraph's settings. +fn spacing_for(pp: &ParaProps, base_size: f64) -> Spacing { + Spacing { + justify: pp.align.is_justified(), + word_min: pp.word_space_min, + word_desired: pp.word_space_desired, + word_max: pp.word_space_max, + letter_min: pp.letter_space_min.min(pp.letter_space_desired), + letter_desired: pp.letter_space_desired, + letter_max: pp.letter_space_max.max(pp.letter_space_desired), + glyph_min: pp.glyph_scale_min.min(pp.glyph_scale_desired).max(0.01), + glyph_desired: pp.glyph_scale_desired.max(0.01), + glyph_max: pp.glyph_scale_max.max(pp.glyph_scale_desired), + hyphen_penalty: 50.0 + 450.0 * pp.hyph_weight, + hyphen_limit: pp.hyph_limit, + ragged_stretch: base_size * 2.0, + hyph_zone: if pp.align.is_justified() { 0.0 } else { pp.hyph_zone }, + optical: pp.optical_margin, + } +} + +/// Desired word spacing, letter spacing and glyph scaling apply to every line (any alignment). +fn apply_desired_spacing(glyphs: &mut [Glyph], pp: &ParaProps) { + let ws = pp.word_space_desired; + let ls = pp.letter_space_desired; + let gs = pp.glyph_scale_desired.max(0.01); + if (ws - 1.0).abs() < 1e-9 && ls.abs() < 1e-9 && (gs - 1.0).abs() < 1e-9 { + return; + } + for g in glyphs { + if g.ch == ' ' { + g.adv += g.space * (ws - 1.0); + } else if !g.is_space() && g.adv > 0.0 { + g.adv = g.adv * gs + ls * g.space; + g.sx *= gs; + g.dx *= gs; + } + } +} + +/// Lengths of the composed output and the cursor before a paragraph (keep resolution re-lays +/// paragraphs from here). Only the cursor's frame and later ones can change afterwards. +struct Snapshot { + cur: Cursor, + list_counter: u32, + lines: usize, + decos: usize, +} + +impl Snapshot { + fn take(out: &ComposedStory, cur: &Cursor, list_counter: u32) -> Snapshot { + let (lines, decos) = out.frames.get(cur.fi).map_or((0, 0), |f| (f.lines.len(), f.decos.len())); + Snapshot { cur: cur.clone(), list_counter, lines, decos } + } + fn restore(&self, out: &mut ComposedStory, cur: &mut Cursor, list_counter: &mut u32) { + let fi = self.cur.fi; + for (i, f) in out.frames.iter_mut().enumerate().skip(fi) { + let (l, d) = if i == fi { (self.lines, self.decos) } else { (0, 0) }; + f.lines.truncate(l); + f.decos.truncate(d); + } + *cur = self.cur.clone(); + *list_counter = self.list_counter; + out.overset_at = None; + } +} + +/// Where a placed paragraph sits (for keep resolution). +#[derive(Clone, Debug)] +struct ParaInfo { + start: (usize, usize), + /// Started at the top of a column (moving it can't help). + at_top: bool, + end: (usize, usize), + lines: usize, + lines_in_end_col: usize, + keep_with_next: u32, + keep_together: bool, + keep_all: bool, + keep_first: usize, + keep_last: usize, +} + +/// The paragraph being placed when a line doesn't fit its column. +struct KeepCtx { + pi: usize, + /// Paragraph line number of the line that doesn't fit. + line_no: usize, + /// Lines of this paragraph already in the column. + in_col: usize, + /// The paragraph started in this column. + started_here: bool, + at_top: bool, + /// Lines left to set, including the one that doesn't fit. + remaining: usize, + here: (usize, usize), +} + +enum KeepAction { + /// Re-lay from paragraph `j`, starting it in the next column. + Force(usize), + /// Re-lay from paragraph `j`, moving to the next column after `n` of its lines. + Cap(usize, usize), +} + +/// Keep Options (plan: typography §8): keep with next, keep all lines together, keep first/last +/// lines. Returns how to re-lay, or None to just continue in the next column (also when a keep +/// can't be satisfied, e.g. a paragraph already at the top of a column). +fn keep_violation(ctx: &KeepCtx, pp: &ParaProps, info: &[ParaInfo], force_col: &[bool], line_cap: &[Option]) -> Option { + // The first paragraph of the chain of keep-with-next paragraphs ending in `pi` that sit in this column. + let chain_start = |pi: usize| { + let mut j = pi; + while j > 0 { + let p = &info[j - 1]; + let starts_here = if j == ctx.pi { ctx.started_here } else { info[j].start == ctx.here }; + if p.keep_with_next > 0 && p.end == ctx.here && starts_here { + j -= 1; + } else { + break; + } + } + j + }; + let force = |j: usize| -> Option { + let top = if j == ctx.pi { ctx.at_top } else { info[j].at_top }; + let starts_here = if j == ctx.pi { ctx.started_here } else { info[j].start == ctx.here }; + (!(force_col[j] || top && starts_here)).then_some(KeepAction::Force(j)) + }; + let total_lines = ctx.line_no + ctx.remaining; + // Keep with next: the previous paragraph's last line must share a column with our first lines. + if ctx.started_here && ctx.pi > 0 { + let prev = &info[ctx.pi - 1]; + let need = (prev.keep_with_next as usize).min(total_lines); + if prev.keep_with_next > 0 && prev.end == ctx.here && ctx.line_no < need { + let j = chain_start(ctx.pi); + if j == ctx.pi - 1 && prev.lines_in_end_col > 1 && !(prev.keep_together && prev.keep_all) && line_cap[j].is_none() { + // Move only the previous paragraph's last lines (respecting its widow control). + let keep_last = if prev.keep_together { prev.keep_last.max(1) } else { 1 }; + let stay = prev.lines_in_end_col.saturating_sub(keep_last); + let min_stay = if prev.start == ctx.here { if prev.keep_together { prev.keep_first.max(1) } else { 1 } } else { 1 }; + if stay >= min_stay { + return Some(KeepAction::Cap(j, prev.lines - keep_last)); + } + } + if let Some(a) = force(j) { + return Some(a); + } + } + } + if !pp.keep_lines_together || ctx.in_col == 0 { + return None; + } + if pp.keep_all_lines { + return if ctx.started_here { force(chain_start(ctx.pi)) } else { None }; + } + // Orphan control: at least `keep_first` lines at the bottom of the column. + if ctx.started_here && ctx.in_col < (pp.keep_first as usize).max(1) { + return force(chain_start(ctx.pi)); + } + // Widow control: at least `keep_last` lines at the top of the next column. + let keep_last = (pp.keep_last as usize).max(1); + if ctx.remaining < keep_last { + let need = keep_last - ctx.remaining; + let min_stay = if ctx.started_here { (pp.keep_first as usize).max(1) } else { 1 }; + if ctx.in_col >= need + min_stay && line_cap[ctx.pi].is_none() { + return Some(KeepAction::Cap(ctx.pi, ctx.line_no - need)); + } + if ctx.started_here { + return force(chain_start(ctx.pi)); + } + } + None +} + fn ft_prev_end(overset: &Option, len: usize) -> usize { overset.unwrap_or(len) } +#[derive(Clone)] struct Cursor { fi: usize, col: usize, @@ -620,6 +865,10 @@ fn estimate_slots(f: &FrameSpec, col: Rect, first: f64, lead: f64, size: f64, gl } /// Position glyphs `s..e` within `[x0, x1]`; returns (glyphs, end x, word-space ratio). +/// +/// Justified lines distribute the difference to the measure in priority order: word spaces up to +/// their limit, then letter spacing, then glyph scaling, and anything left over to the word spaces +/// (an H&J violation). With optical margin alignment, edge punctuation hangs outside `[x0, x1]`. #[allow(clippy::too_many_arguments)] fn layout_line( glyphs: &[Glyph], @@ -630,6 +879,7 @@ fn layout_line( x1: f64, tab_origin: f64, pp: &ParaProps, + sp: &Spacing, last: bool, forced_mid: bool, left_page: bool, @@ -673,10 +923,20 @@ fn layout_line( x += line[i].adv; i += 1; } + let has_tab = line.iter().any(|g| g.ch == '\t' || g.ch == story::RIGHT_INDENT_TAB); + // Optical margin alignment: the measure grows by the hang of the edge glyphs. + let (mut x0, mut measure) = (x0, measure); + if sp.optical && !has_tab { + let first = line.iter().find(|g| g.adv > 0.0 && !g.is_space()); + let lastg = line.iter().rev().find(|g| g.adv > 0.0 && !g.is_space()); + let hl = first.map_or(0.0, |g| breaker::hang(g.ch).0 * g.adv); + let hr = lastg.map_or(0.0, |g| breaker::hang(g.ch).1 * g.adv); + x0 -= hl; + measure += hl + hr; + } let natural: f64 = line.iter().map(|g| g.adv).sum(); let extra = measure - natural; let spaces: Vec = line.iter().enumerate().filter(|(_, g)| g.is_space() && !g.no_break).map(|(i, _)| i).collect(); - let has_tab = line.iter().any(|g| g.ch == '\t' || g.ch == story::RIGHT_INDENT_TAB); let align = match pp.align { Align::TowardsSpine => { if left_page { @@ -695,26 +955,22 @@ fn layout_line( a => a, }; let justify_this = align.is_justified() && (!last || align == Align::FullyJustified || forced_mid) && !has_tab; - let mut per_space = 0.0; + // A justified paragraph's last line may have been composed with shrunk spaces: shrink it too. + let squeeze_last = align.is_justified() && !justify_this && !has_tab && extra < 0.0 && !spaces.is_empty(); + // Extra advance per glyph (word spaces and letter gaps) and horizontal scale per glyph. + let mut add = vec![0.0; line.len()]; + let mut scale = vec![1.0; line.len()]; let mut offset = 0.0; - let mut ratio = 1.0; - if justify_this && !spaces.is_empty() { - per_space = extra / spaces.len() as f64; - let space_w: f64 = spaces.iter().map(|&i| line[i].adv).sum::() / spaces.len() as f64; - ratio = if space_w > 0.0 { (space_w + per_space) / space_w * pp.word_space_desired } else { 1.0 }; + if (justify_this || squeeze_last) && !spaces.is_empty() { + distribute(&line, &spaces, extra, sp, &mut add, &mut scale); } else if justify_this && spaces.is_empty() && line.len() > 1 && !last { // Single word: Single Word Justification. match pp.single_word_justify { Align::FullyJustified => { - let gaps = (line.len() - 1) as f64; - let per = extra / gaps; - let mut x = x0; - let mut out = Vec::with_capacity(line.len()); - for (i, g) in line.iter().enumerate() { - out.push(place(g, x)); - x += g.adv + if i + 1 < line.len() { per } else { 0.0 }; + let per = extra / (line.len() - 1) as f64; + for a in &mut add[..line.len() - 1] { + *a = per; } - return (out, x, 1.0); } Align::Center => offset = extra / 2.0, Align::Right => offset = extra, @@ -738,19 +994,103 @@ fn layout_line( offset = 0.0; } } + // Word-space ratio actually used (vs the space width), for H&J highlighting. + let mut ratio_sum = 0.0; + let mut ratio_n = 0usize; + for &i in &spaces { + let g = &line[i]; + if g.ch == ' ' && g.space > 0.0 { + ratio_sum += (g.adv + add[i]) / g.space; + ratio_n += 1; + } + } + let ratio = if ratio_n > 0 { ratio_sum / ratio_n as f64 } else { 1.0 }; let mut out = Vec::with_capacity(line.len()); let mut x = x0 + offset; for (i, g) in line.iter().enumerate() { - out.push(place(g, x)); - x += g.adv; - if per_space != 0.0 && spaces.binary_search(&i).is_ok() { - x += per_space; - if let Some(p) = out.last_mut() { - p.adv += per_space; + let mut p = place(g, x); + if scale[i] != 1.0 { + p.sx *= scale[i]; + p.x = x + g.dx * scale[i]; + p.adv *= scale[i]; + } + p.adv += add[i]; + x += p.adv; + out.push(p); + } + (out, x, ratio) +} + +/// Share `extra` points among word spaces, letter gaps and glyph scaling (see [`layout_line`]). +fn distribute(line: &[Glyph], spaces: &[usize], extra: f64, sp: &Spacing, add: &mut [f64], scale: &mut [f64]) { + let stretch = extra >= 0.0; + let word: Vec = spaces + .iter() + .map(|&i| { + let g = &line[i]; + if g.ch != ' ' { + 0.0 + } else if stretch { + g.space * (sp.word_max - sp.word_desired).max(0.0) + } else { + g.space * (sp.word_desired - sp.word_min).max(0.0) + } + }) + .collect(); + // Letter gaps: between visible glyphs (not after the line's last glyph). + let last_box = line.iter().rposition(|g| !g.is_space() && g.adv > 0.0).unwrap_or(0); + let is_box = |i: usize, g: &Glyph| i < last_box && !g.is_space() && g.adv > 0.0; + let letter: Vec = line + .iter() + .enumerate() + .map(|(i, g)| { + if !is_box(i, g) { + 0.0 + } else if stretch { + g.space * (sp.letter_max - sp.letter_desired).max(0.0) + } else { + g.space * (sp.letter_desired - sp.letter_min).max(0.0) + } + }) + .collect(); + let glyph: Vec = line + .iter() + .map(|g| { + if g.is_space() || g.adv <= 0.0 { + 0.0 + } else { + let natural = g.adv / sp.glyph_desired.max(0.01); + natural * if stretch { (sp.glyph_max - sp.glyph_desired).max(0.0) } else { (sp.glyph_desired - sp.glyph_min).max(0.0) } + } + }) + .collect(); + let (yw, yl, yg) = (word.iter().sum::(), letter.iter().sum::(), glyph.iter().sum::()); + let mut rem = extra.abs(); + let tw = rem.min(yw); + rem -= tw; + let tl = rem.min(yl); + rem -= tl; + let tg = rem.min(yg); + rem -= tg; + let sign = if stretch { 1.0 } else { -1.0 }; + for (k, &i) in spaces.iter().enumerate() { + let share = if yw > 1e-9 { tw * word[k] / yw } else { 0.0 }; + // Left over beyond every limit: shared equally by the word spaces. + add[i] += sign * (share + rem / spaces.len() as f64); + } + if yl > 1e-9 && tl > 0.0 { + for (i, l) in letter.iter().enumerate() { + add[i] += sign * tl * l / yl; + } + } + if yg > 1e-9 && tg > 0.0 { + for (i, gcap) in glyph.iter().enumerate() { + if *gcap > 0.0 { + let w = line[i].adv; + scale[i] = (w + sign * tg * gcap / yg) / w; } } } - (out, x, ratio) } fn place(g: &Glyph, x: f64) -> PlacedGlyph { @@ -802,7 +1142,10 @@ fn prepend_label( *glyphs = pre; } -/// Mark glyphs after which a hyphen may be inserted. +type LimitsKey = (usize, usize, usize, bool); + +/// Mark glyphs after which a hyphen may be inserted (dictionary/pattern points within the +/// paragraph's limits; words with discretionary hyphens break only there). fn hyphenation_points(text: &str, glyphs: &[Glyph], pp: &ParaProps) -> Vec { let mut out = vec![false; glyphs.len()]; if !pp.hyphenate { @@ -814,6 +1157,24 @@ fn hyphenation_points(text: &str, glyphs: &[Glyph], pp: &ParaProps) -> Vec before_last: pp.hyph_before_last as usize, capitalized: pp.hyph_capitalized, }; + // Words repeat a lot: remember their points per set of limits. + static CACHE: Mutex, Box<[usize]>>)>> = Mutex::new(Vec::new()); + let key = (lim.min_word, lim.after_first, lim.before_last, lim.capitalized); + let mut guard = CACHE.lock().unwrap_or_else(|e| e.into_inner()); + let idx = match guard.iter().position(|e| e.0 == key) { + Some(i) => i, + None => { + if guard.len() > 32 { + guard.clear(); + } + guard.push((key, HashMap::new())); + guard.len() - 1 + } + }; + let cache = &mut guard[idx].1; + if cache.len() > 100_000 { + cache.clear(); + } let mut i = 0; while i < glyphs.len() { if !glyphs[i].is_letter() || glyphs[i].len == 0 { @@ -821,17 +1182,19 @@ fn hyphenation_points(text: &str, glyphs: &[Glyph], pp: &ParaProps) -> Vec continue; } let mut j = i; - while j < glyphs.len() && (glyphs[j].is_letter() || glyphs[j].len == 0) && !glyphs[j].no_break { + while j < glyphs.len() && (glyphs[j].is_letter() || glyphs[j].len == 0 || glyphs[j].ch == shape::SOFT_HYPHEN) && !glyphs[j].no_break { j += 1; } + // A discretionary hyphen in a word (or right before it) replaces automatic hyphenation. + let discretionary = glyphs[i..j].iter().any(|g| g.ch == shape::SOFT_HYPHEN) || (i > 0 && glyphs[i - 1].ch == shape::SOFT_HYPHEN); let (a, b) = (glyphs[i].byte, glyphs[j - 1].byte + glyphs[j - 1].len); - if b > a && b <= text.len() && text.is_char_boundary(a) && text.is_char_boundary(b) { + if !discretionary && b > a && b <= text.len() && text.is_char_boundary(a) && text.is_char_boundary(b) { let word = &text[a..b]; // Do not hyphenate the paragraph's last word unless allowed. let is_last_word = !pp.hyph_last_word && glyphs[j..].iter().all(|g| !g.is_letter()); if !is_last_word { - let pts = hyphen::hyphen_points(word, &lim); - for p in pts { + let pts = cache.entry(word.into()).or_insert_with(|| hyphen::hyphen_points(word, &lim).into_boxed_slice()); + for &p in pts.iter() { // char index p → byte → glyph whose cluster ends at that byte. let byte = a + word.char_indices().nth(p).map(|(bi, _)| bi).unwrap_or(word.len()); if let Some(k) = (i..j).find(|&k| glyphs[k].byte + glyphs[k].len == byte && glyphs[k].len > 0) { diff --git a/crates/compose/src/shape.rs b/crates/compose/src/shape.rs index 90c55d5..a935f52 100644 --- a/crates/compose/src/shape.rs +++ b/crates/compose/src/shape.rs @@ -1,6 +1,7 @@ //! Paragraph → styled, positioned glyphs (before line breaking). -use std::sync::Arc; +use std::collections::HashMap; +use std::sync::{Arc, Mutex}; use designcraft_doc::{Capitalization, CharProps, Kerning, Leading, Position, Story, Styles, story}; use designcraft_fonts::{Feature, FontDb, FontFace, ShapedGlyph, feature}; @@ -37,6 +38,9 @@ pub struct Glyph { pub style: u32, /// Unbreakable (No Break). pub no_break: bool, + /// Width of a word space (U+0020) in this glyph's font, size and horizontal scale: the unit of + /// word and letter spacing in justification. + pub space: f64, } impl Glyph { @@ -224,6 +228,54 @@ fn shape_run( flush(seg_start, range.end, &seg_face, out); } +type WordMap = HashMap, Arc<[ShapedGlyph]>>; + +/// Shaped words (font units) by (face, caps, features), then text. +static WORD_CACHE: Mutex> = Mutex::new(Vec::new()); +const WORD_CACHE_MAX: usize = 50_000; + +/// Shape `src` word by word through a cache (like a browser's word cache): the text is split +/// after each U+0020 so repeated words are shaped once. Shaping does not cross word spaces in the +/// scripts we lay out, and clusters stay byte offsets into `src`. +fn shape_cached(face: &FontFace, src: &str, feats: &[Feature], caps: bool) -> Vec { + let map = |c: char| if caps { c.to_uppercase().next().unwrap_or(c) } else { c }; + if src.len() < 2 || !src.contains(' ') { + return designcraft_fonts::shape(face, src, feats, map); + } + let fkey = format!("{feats:?}"); + let mut out = Vec::with_capacity(src.len()); + let mut guard = WORD_CACHE.lock().unwrap_or_else(|e| e.into_inner()); + let key = (face.id(), caps, fkey); + let idx = match guard.iter().position(|e| e.0 == key) { + Some(i) => i, + None => { + if guard.len() > 64 { + guard.clear(); + } + guard.push((key, HashMap::new())); + guard.len() - 1 + } + }; + let cache = &mut guard[idx].1; + if cache.len() > WORD_CACHE_MAX { + cache.clear(); + } + let mut start = 0; + for piece in src.split_inclusive(' ') { + let glyphs = match cache.get(piece) { + Some(g) => g.clone(), + None => { + let g: Arc<[ShapedGlyph]> = designcraft_fonts::shape(face, piece, feats, map).into(); + cache.insert(piece.into(), g.clone()); + g + } + }; + out.extend(glyphs.iter().map(|g| ShapedGlyph { cluster: g.cluster + start, ..*g })); + start += piece.len(); + } + out +} + fn metrics(face: &FontFace, p: &CharProps, auto_leading: f64) -> (f64, f64, f64, f64, f64, f64, f64, f64) { let (size, shift) = effective_size(p); let k = size / face.upem; @@ -266,6 +318,7 @@ fn control_glyph(face: &Arc, p: &CharProps, auto_leading: f64, style: size, style, no_break: p.no_break, + space: face.advance(face.glyph_for(' ')) * k * p.h_scale, } } @@ -289,7 +342,8 @@ fn shape_segment( let src = replacement.unwrap_or(&text[range.clone()]); let caps = p.capitalization == Capitalization::AllCaps; let feats = features_for(p); - let shaped: Vec = designcraft_fonts::shape(face, src, &feats, |c| if caps { c.to_uppercase().next().unwrap_or(c) } else { c }); + let space = face.advance(face.glyph_for(' ')) * k * hs; + let shaped: Vec = shape_cached(face, src, &feats, caps); let n = shaped.len(); for (gi, sg) in shaped.iter().enumerate() { let (byte, len, ch) = if replacement.is_some() { @@ -328,6 +382,7 @@ fn shape_segment( size, style, no_break: p.no_break, + space, }); } } diff --git a/crates/compose/src/tests.rs b/crates/compose/src/tests.rs index 4981ce0..0806731 100644 --- a/crates/compose/src/tests.rs +++ b/crates/compose/src/tests.rs @@ -178,24 +178,372 @@ fn tabs_align_to_stops() { assert!((l.end_x - 100.0).abs() < 0.5, "{}", l.end_x); } -#[test] -fn justified_narrow_column_has_no_extreme_lines() { - let text = "Color holds it all together. A restrained palette of two or three swatches, applied consistently to headlines, rules and backgrounds, gives a publication its voice. Spot inks, tints and gradients are all just named swatches, so a single change ripples through every page."; - let para = ParaAttrs { align: Some(Align::LeftJustified), first_line_indent: Some(12.0), hyph_min_word: Some(6), ..Default::default() }; +const SWATCH_TEXT: &str = "Color holds it all together. A restrained palette of two or three swatches, applied consistently to headlines, rules and backgrounds, gives a publication its voice. Spot inks, tints and gradients are all just named swatches, so a single change ripples through every page."; + +/// Worst word-space ratio (excluding last lines) of `text` in a narrow justified column. +fn narrow_worst(para: ParaAttrs) -> f64 { + let para = ParaAttrs { align: Some(Align::LeftJustified), first_line_indent: Some(12.0), hyph_min_word: Some(6), ..para }; let mut d = Document::new(&NewDocument::default()); let lid = d.default_layer(); - let (_, sid) = - d.add_text_frame(SpreadRef::Doc(0), Rect::new(0.0, 0.0, 170.67, 2000.0), lid, text, ParaFormat { para, ..Default::default() }).unwrap(); - d.story_mut(sid).unwrap().format_chars(0..text.len(), |f| f.over.size = Some(9.75)); + let (_, sid) = d + .add_text_frame(SpreadRef::Doc(0), Rect::new(0.0, 0.0, 170.67, 2000.0), lid, SWATCH_TEXT, ParaFormat { para, ..Default::default() }) + .unwrap(); + d.story_mut(sid).unwrap().format_chars(0..SWATCH_TEXT.len(), |f| f.over.size = Some(9.75)); let cs = compose_story(&d, sid, &ComposeOptions::default()); let mut worst = 0.0f64; for l in all_lines(&cs) { - let s: String = d.story(sid).unwrap().text[l.range.clone()].to_string(); - eprintln!("{:5.2} {}", l.spacing, s); + eprintln!("{:5.2} {}", l.spacing, &SWATCH_TEXT[l.range.clone()]); + assert!(l.end_x <= l.x1 + 0.5, "overfull line"); if !l.last_in_para { + assert!((l.end_x - l.x1).abs() < 0.6, "justified line ends at {} not {}", l.end_x, l.x1); worst = worst.max(l.spacing); } } - // Regression bound; tighter once dictionary hyphenation lands (plan: Moby PD word list). - assert!(worst < 8.0, "loose line ratio {worst}"); + worst +} + +#[test] +fn justified_narrow_column_has_no_extreme_lines() { + // Word spacing only (InDesign's defaults: letter spacing 0%, glyph scaling 100%). The first + // line can't do better than ~2.7: "…together. A re-" is the longest first line that fits. + let words_only = narrow_worst(ParaAttrs::default()); + assert!(words_only < 4.5, "loose line ratio {words_only}"); + // A typical magazine body setup: letter spacing −5…10% and glyph scaling 97…103% absorb the rest. + let full = narrow_worst(ParaAttrs { + letter_space_min: Some(-0.05), + letter_space_max: Some(0.10), + glyph_scale_min: Some(0.97), + glyph_scale_max: Some(1.03), + ..Default::default() + }); + assert!(full < 2.0, "loose line ratio {full}"); +} + +#[test] +fn glyph_scaling_and_letter_spacing_are_applied() { + let para = ParaAttrs { + align: Some(Align::LeftJustified), + hyphenate: Some(false), + letter_space_min: Some(-0.05), + letter_space_max: Some(0.2), + glyph_scale_min: Some(0.95), + glyph_scale_max: Some(1.05), + ..Default::default() + }; + let text = CORPUS.join(" "); + let (d, sid, _) = doc_with(&text, Rect::new(0.0, 0.0, 150.0, 20000.0), para.clone()); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let lines = all_lines(&cs); + let mut scaled = false; + let mut sum = 0.0; + for l in &lines[..lines.len() - 1] { + assert!((l.end_x - l.x1).abs() < 0.6, "justified line ends at {} not {}", l.end_x, l.x1); + sum += l.spacing; + let k = 12.0 / l.glyphs[0].face.upem; + scaled |= l.glyphs.iter().any(|g| g.visible && (g.sx / k - 1.0).abs() > 1e-3); + } + assert!(scaled, "some line uses glyph scaling"); + // Word spaces stay closer to their desired width than with word spacing alone. + let plain = ParaAttrs { align: Some(Align::LeftJustified), hyphenate: Some(false), ..Default::default() }; + let (d, sid, _) = doc_with(&text, Rect::new(0.0, 0.0, 150.0, 20000.0), plain); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let pl = all_lines(&cs); + let plain_avg = pl[..pl.len() - 1].iter().map(|l| l.spacing).sum::() / (pl.len() - 1) as f64; + let avg = sum / (lines.len() - 1) as f64; + assert!(avg < plain_avg - 0.1, "with tiers {avg:.3}, words only {plain_avg:.3}"); + // Desired values apply to every line, including ragged text. + let wide = |ls: f64| { + let (d, sid, _) = + doc_with("Hello world", Rect::new(0.0, 0.0, 300.0, 100.0), ParaAttrs { letter_space_desired: Some(ls), ..Default::default() }); + compose_story(&d, sid, &ComposeOptions::default()).frames[0].lines[0].end_x + }; + assert!(wide(0.5) > wide(0.0) + 10.0 * 0.5 * 2.0); +} + +#[test] +fn hyphen_limit_is_a_hard_constraint() { + let text = CORPUS.join(" "); + for limit in [1u32, 2] { + let para = ParaAttrs { align: Some(Align::LeftJustified), hyph_limit: Some(limit), hyph_weight: Some(0.0), ..Default::default() }; + let (d, sid, _) = doc_with(&text, Rect::new(0.0, 0.0, 130.0, 100_000.0), para); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let mut run = 0; + let mut any = false; + for l in all_lines(&cs) { + run = if l.hyphenated { run + 1 } else { 0 }; + any |= l.hyphenated; + assert!(run <= limit, "{run} consecutive hyphens with limit {limit}"); + } + assert!(any); + } +} + +#[test] +fn hyphenation_zone_limits_ragged_hyphens() { + let text = CORPUS.join(" "); + let count = |zone: f64, composer: designcraft_doc::Composer| { + let para = + ParaAttrs { align: Some(Align::Left), hyph_zone: Some(zone), composer: Some(composer), hyph_weight: Some(0.0), ..Default::default() }; + let (d, sid, _) = doc_with(&text, Rect::new(0.0, 0.0, 110.0, 100_000.0), para); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + all_lines(&cs).iter().filter(|l| l.hyphenated).count() + }; + for c in [designcraft_doc::Composer::Paragraph, designcraft_doc::Composer::SingleLine] { + let (free, zoned, huge) = (count(0.0, c), count(36.0, c), count(1000.0, c)); + // A huge zone leaves only words that start a line (no space to break at) hyphenable. + assert!(free > 0 && zoned <= free && huge * 4 <= free, "{c:?}: {free} {zoned} {huge}"); + } +} + +#[test] +fn discretionary_hyphen_replaces_automatic_points() { + let text = "aaaa bbbb cccc extraordi\u{AD}narily dddd eeee"; + let para = ParaAttrs { align: Some(Align::Left), ..Default::default() }; + let (d, sid, _) = doc_with(text, Rect::new(0.0, 0.0, 120.0, 1000.0), para); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let soft = text.find('\u{AD}').unwrap(); + for l in all_lines(&cs) { + if l.hyphenated { + let last = l.glyphs.iter().rfind(|g| g.len > 0).unwrap(); + assert!(last.byte + last.len >= soft && last.byte <= soft + 2, "{:?}", &text[l.range.clone()]); + } + } + // Hyphenation points of the word itself: none besides the discretionary one. + let lines = all_lines(&cs); + assert!(lines.iter().filter(|l| l.hyphenated).count() <= 1); +} + +/// Story of `n` one-line filler paragraphs followed by `extra` paragraphs, in a 2-column frame. +fn keep_doc(fillers: usize, extra: &[&str], height: f64) -> (Document, StoryId, Vec) { + let mut parts: Vec = (0..fillers).map(|k| format!("Filler {k}")).collect(); + parts.extend(extra.iter().map(|s| s.to_string())); + let text = parts.join("\n"); + let (mut d, sid, fid) = doc_with(&text, Rect::new(0.0, 0.0, 400.0, height), ParaAttrs::default()); + d.item_mut(fid).unwrap().text_frame_mut().unwrap().options.columns = 2; + (d, sid, (0..parts.len()).collect()) +} + +fn column_of_para(cs: &ComposedStory, pi: usize) -> Vec { + all_lines(cs).iter().filter(|l| l.para == pi).map(|l| l.column).collect() +} + +/// Lines that fit in one column of the keep test frame. +fn lines_per_column(height: f64) -> usize { + let (d, sid, _) = keep_doc(60, &[], height); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + all_lines(&cs).iter().filter(|l| l.column == 0).count() +} + +#[test] +fn keep_with_next_moves_a_heading() { + let h = 200.0; + let n = lines_per_column(h); + let body = "Body text that follows the heading."; + let (mut d, sid, _) = keep_doc(n - 1, &["Heading", body], h); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + assert_eq!(column_of_para(&cs, n - 1), vec![0], "without keeps the heading ends column 0"); + d.story_mut(sid).unwrap().paras[n - 1].para.keep_with_next = Some(1); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + assert_eq!(column_of_para(&cs, n - 1), vec![1]); + assert_eq!(column_of_para(&cs, n), vec![1]); + assert_eq!(column_of_para(&cs, n - 2), vec![0]); +} + +#[test] +fn keep_lines_together_moves_the_paragraph() { + let h = 200.0; + let n = lines_per_column(h); + let long = [LOREM, LOREM].join(" "); + let (mut d, sid, _) = keep_doc(n - 3, &[&long], h); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + assert!(column_of_para(&cs, n - 3).contains(&0)); + d.story_mut(sid).unwrap().paras[n - 3].para.keep_lines_together = Some(true); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + assert!(column_of_para(&cs, n - 3).iter().all(|&c| c == 1)); +} + +#[test] +fn keep_first_and_last_lines() { + let h = 200.0; + let n = lines_per_column(h); + // Orphan: one line at the bottom of column 0 → the paragraph moves. + let (mut d, sid, _) = keep_doc(n - 1, &[LOREM], h); + { + let p = &mut d.story_mut(sid).unwrap().paras[n - 1].para; + p.keep_lines_together = Some(true); + p.keep_all_lines = Some(false); + } + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let cols = column_of_para(&cs, n - 1); + assert!(cols.iter().all(|&c| c == 1), "{cols:?}"); + // Widow: a paragraph whose last line would sit alone in column 1 gives it a companion. + let para_lines = { + let (d, sid, _) = keep_doc(0, &[LOREM], 2000.0); + compose_story(&d, sid, &ComposeOptions::default()).line_count() + }; + assert!(para_lines >= 4); + let start = n - (para_lines - 1); + let (mut d, sid, _) = keep_doc(start, &[LOREM], h); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + assert_eq!(column_of_para(&cs, start).iter().filter(|&&c| c == 1).count(), 1, "one widowed line without keeps"); + { + let p = &mut d.story_mut(sid).unwrap().paras[start].para; + p.keep_lines_together = Some(true); + p.keep_all_lines = Some(false); + } + let cs = compose_story(&d, sid, &ComposeOptions::default()); + let cols = column_of_para(&cs, start); + assert_eq!(cols.iter().filter(|&&c| c == 1).count(), 2, "{cols:?}"); + assert!(cols.iter().filter(|&&c| c == 0).count() >= 2); +} + +#[test] +fn balance_ragged_lines_evens_a_headline() { + let text = "Balanced headlines read better than a stub"; + let widths = |balance: bool| { + let para = ParaAttrs { balance_ragged: Some(balance), hyphenate: Some(false), ..Default::default() }; + let (mut d, sid, _) = doc_with(text, Rect::new(0.0, 0.0, 300.0, 500.0), para); + d.story_mut(sid).unwrap().format_chars(0..text.len(), |f| f.over.size = Some(18.0)); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + all_lines(&cs).iter().map(|l| l.end_x - l.x0).collect::>() + }; + let plain = widths(false); + let bal = widths(true); + assert_eq!(plain.len(), bal.len()); + assert!(plain.len() >= 2); + let spread = |w: &[f64]| w.iter().cloned().fold(f64::MIN, f64::max) - w.iter().cloned().fold(f64::MAX, f64::min); + assert!(spread(&bal) < spread(&plain), "{bal:?} vs {plain:?}"); +} + +#[test] +fn optical_margin_hangs_punctuation() { + let text = "Hanging punctuation, quietly. “Quotes” sit outside the measure, as do commas, periods and hyphens."; + let run = |optical: bool| { + let para = ParaAttrs { align: Some(Align::LeftJustified), optical_margin: Some(optical), ..Default::default() }; + let (d, sid, _) = doc_with(text, Rect::new(0.0, 0.0, 120.0, 1000.0), para); + compose_story(&d, sid, &ComposeOptions::default()) + }; + let plain = run(false); + let hung = run(true); + for l in all_lines(&plain) { + assert!(l.end_x <= l.x1 + 0.5); + } + // Some justified line ends with punctuation that now protrudes past the right edge. + let lines = all_lines(&hung); + assert!(lines[..lines.len() - 1].iter().any(|l| l.end_x > l.x1 + 0.5), "no line hangs"); + assert!(lines.iter().all(|l| l.end_x <= l.x1 + 12.0)); +} + +// ---------- golden paragraph corpus ---------- + +/// Original prose (written for this corpus) with a realistic mix of short and long words. +const CORPUS: &[&str] = &[ + "Every printed page is a negotiation between the designer and the reader. The designer proposes an order: a column of type, a picture that interrupts it, a caption that explains the picture. The reader accepts that order only when nothing on the page calls attention to itself for the wrong reasons.", + "Justified text is especially unforgiving. When the measure is narrow, the composer must choose between loose lines with rivers of white running down the column, tight lines in which words collide, and hyphenated lines that interrupt the rhythm of reading. Good composition balances all three considerations across the whole paragraph instead of one line at a time.", + "Hyphenation dictionaries record where conventional syllable divisions fall in thousands of ordinary words: international, responsibility, characteristically, misunderstanding, photographer, extraordinarily, administration, comprehensive, establishment, unquestionably and their many relatives.", + "Magazines often set body copy in two or three columns on a page, with generous gutters and a baseline grid that keeps neighbouring lines aligned. Headlines span the columns, pull quotes break into them, and captions sit beside photographs in a smaller, contrasting typeface.", + "The typesetter of the nineteenth century worked with metal sorts, composing sticks and wedges of spacing material. Many of the conventions we take for granted today, such as the preference for consistent word spacing over consistent line endings, were established by those craftsmen long before computers automated their decisions.", + "Readers rarely notice good typography, but they immediately feel the discomfort of bad typography: uneven spacing, awkward breaks, widowed lines stranded at the top of a column, and orphaned headings left at the bottom of a page without the paragraph that follows them.", +]; + +#[derive(Debug, Default)] +struct CorpusStats { + lines: usize, + overfull: usize, + hyphens: usize, + sum_spacing: f64, + worst: f64, + loose: usize, +} + +fn corpus_stats(align: Align, measure: f64, size: f64) -> CorpusStats { + let text = CORPUS.join("\n"); + let para = ParaAttrs { align: Some(align), ..Default::default() }; + let mut d = Document::new(&NewDocument::default()); + let lid = d.default_layer(); + let (_, sid) = + d.add_text_frame(SpreadRef::Doc(0), Rect::new(0.0, 0.0, measure, 100_000.0), lid, &text, ParaFormat { para, ..Default::default() }).unwrap(); + d.story_mut(sid).unwrap().format_chars(0..text.len(), |f| f.over.size = Some(size)); + let cs = compose_story(&d, sid, &ComposeOptions::default()); + assert!(!cs.is_overset()); + let mut st = CorpusStats::default(); + for l in all_lines(&cs) { + if l.end_x > l.x1 + 0.5 { + st.overfull += 1; + } + if l.hyphenated { + st.hyphens += 1; + } + if !l.last_in_para { + st.lines += 1; + st.sum_spacing += l.spacing; + st.worst = st.worst.max(l.spacing); + if l.spacing > 1.33 + 1e-6 { + st.loose += 1; + } + } + } + st +} + +#[test] +fn golden_corpus_spacing() { + let mut total = CorpusStats::default(); + for &(measure, size) in &[(120.0, 9.0), (170.67, 9.75), (240.0, 10.0), (340.0, 11.0)] { + for align in [Align::LeftJustified, Align::Left] { + let st = corpus_stats(align, measure, size); + let avg = st.sum_spacing / st.lines.max(1) as f64; + eprintln!( + "{align:?} measure {measure:6.2} size {size:5.2}: lines {:3} hyphens {:2} avg {avg:.3} worst {:.3} loose {:2} overfull {}", + st.lines, st.hyphens, st.worst, st.loose, st.overfull + ); + assert_eq!(st.overfull, 0, "overfull lines at {measure}"); + if align == Align::LeftJustified && measure >= 170.0 { + assert!(st.worst < 3.5, "worst justified line {} at {measure}", st.worst); + assert!(avg < 1.65, "average justified word-space ratio {avg} at {measure}"); + } + if align == Align::LeftJustified { + total.lines += st.lines; + total.sum_spacing += st.sum_spacing; + total.worst = total.worst.max(st.worst); + total.loose += st.loose; + } + } + } + let avg = total.sum_spacing / total.lines.max(1) as f64; + eprintln!("justified total: lines {} avg {avg:.3} worst {:.3} loose {}", total.lines, total.worst, total.loose); + assert!(avg < 1.9, "average justified word-space ratio {avg}"); +} + +#[test] +#[ignore = "perf: run with --release -- --ignored --nocapture"] +fn perf_compose_300k_story() { + let mut text = String::new(); + let mut k = 0; + while text.len() < 300_000 { + text.push_str(CORPUS[k % CORPUS.len()]); + text.push('\n'); + k += 1; + } + let para = ParaAttrs { align: Some(Align::LeftJustified), ..Default::default() }; + let mut d = Document::new(&NewDocument::default()); + let lid = d.default_layer(); + let (_, sid) = + d.add_text_frame(SpreadRef::Doc(0), Rect::new(0.0, 0.0, 240.0, 3_000_000.0), lid, &text, ParaFormat { para, ..Default::default() }).unwrap(); + // Cold run (loads hyphenation data, fills the word caches), then the best of a few warm runs. + let t = std::time::Instant::now(); + let _ = compose_story(&d, sid, &ComposeOptions::default()); + let cold = t.elapsed().as_secs_f64() * 1000.0; + let mut ms = f64::INFINITY; + let mut cs = ComposedStory::default(); + for _ in 0..5 { + let t = std::time::Instant::now(); + cs = compose_story(&d, sid, &ComposeOptions::default()); + ms = ms.min(t.elapsed().as_secs_f64() * 1000.0); + } + eprintln!("composed {} chars, {} lines: cold {cold:.1} ms, warm {ms:.1} ms", text.len(), cs.line_count()); + assert!(!cs.is_overset()); + if !cfg!(debug_assertions) { + assert!(ms < 300.0, "composition took {ms:.1} ms"); + } }