Created
April 12, 2022 12:32
-
-
Save pschanely/7df86fdc4150141487d1615a0398b562 to your computer and use it in GitHub Desktop.
Approximate Character Width Computation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from pprint import pprint | |
import re | |
from statistics import stdev, mean | |
# These magic strings are part of ".afm" files, which hold | |
# statistics about a font. | |
helvetica_text = '''C 32 ; WX 278 ; N space ; B 0 0 0 0 ; | |
C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ; | |
C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ; | |
C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ; | |
C 36 ; WX 556 ; N dollar ; B 32 -115 520 775 ; | |
C 37 ; WX 889 ; N percent ; B 39 -19 850 703 ; | |
C 38 ; WX 667 ; N ampersand ; B 44 -15 645 718 ; | |
C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ; | |
C 40 ; WX 333 ; N parenleft ; B 68 -207 299 733 ; | |
C 41 ; WX 333 ; N parenright ; B 34 -207 265 733 ; | |
C 42 ; WX 389 ; N asterisk ; B 39 431 349 718 ; | |
C 43 ; WX 584 ; N plus ; B 39 0 545 505 ; | |
C 44 ; WX 278 ; N comma ; B 87 -147 191 106 ; | |
C 45 ; WX 333 ; N hyphen ; B 44 232 289 322 ; | |
C 46 ; WX 278 ; N period ; B 87 0 191 106 ; | |
C 47 ; WX 278 ; N slash ; B -17 -19 295 737 ; | |
C 48 ; WX 556 ; N zero ; B 37 -19 519 703 ; | |
C 49 ; WX 556 ; N one ; B 101 0 359 703 ; | |
C 50 ; WX 556 ; N two ; B 26 0 507 703 ; | |
C 51 ; WX 556 ; N three ; B 34 -19 522 703 ; | |
C 52 ; WX 556 ; N four ; B 25 0 523 703 ; | |
C 53 ; WX 556 ; N five ; B 32 -19 514 688 ; | |
C 54 ; WX 556 ; N six ; B 38 -19 518 703 ; | |
C 55 ; WX 556 ; N seven ; B 37 0 523 688 ; | |
C 56 ; WX 556 ; N eight ; B 38 -19 517 703 ; | |
C 57 ; WX 556 ; N nine ; B 42 -19 514 703 ; | |
C 58 ; WX 278 ; N colon ; B 87 0 191 516 ; | |
C 59 ; WX 278 ; N semicolon ; B 87 -147 191 516 ; | |
C 60 ; WX 584 ; N less ; B 48 11 536 495 ; | |
C 61 ; WX 584 ; N equal ; B 39 115 545 390 ; | |
C 62 ; WX 584 ; N greater ; B 48 11 536 495 ; | |
C 63 ; WX 556 ; N question ; B 56 0 492 727 ; | |
C 64 ; WX 1015 ; N at ; B 147 -19 868 737 ; | |
C 65 ; WX 667 ; N A ; B 14 0 654 718 ; | |
C 66 ; WX 667 ; N B ; B 74 0 627 718 ; | |
C 67 ; WX 722 ; N C ; B 44 -19 681 737 ; | |
C 68 ; WX 722 ; N D ; B 81 0 674 718 ; | |
C 69 ; WX 667 ; N E ; B 86 0 616 718 ; | |
C 70 ; WX 611 ; N F ; B 86 0 583 718 ; | |
C 71 ; WX 778 ; N G ; B 48 -19 704 737 ; | |
C 72 ; WX 722 ; N H ; B 77 0 646 718 ; | |
C 73 ; WX 278 ; N I ; B 91 0 188 718 ; | |
C 74 ; WX 500 ; N J ; B 17 -19 428 718 ; | |
C 75 ; WX 667 ; N K ; B 76 0 663 718 ; | |
C 76 ; WX 556 ; N L ; B 76 0 537 718 ; | |
C 77 ; WX 833 ; N M ; B 73 0 761 718 ; | |
C 78 ; WX 722 ; N N ; B 76 0 646 718 ; | |
C 79 ; WX 778 ; N O ; B 39 -19 739 737 ; | |
C 80 ; WX 667 ; N P ; B 86 0 622 718 ; | |
C 81 ; WX 778 ; N Q ; B 39 -56 739 737 ; | |
C 82 ; WX 722 ; N R ; B 88 0 684 718 ; | |
C 83 ; WX 667 ; N S ; B 49 -19 620 737 ; | |
C 84 ; WX 611 ; N T ; B 14 0 597 718 ; | |
C 85 ; WX 722 ; N U ; B 79 -19 644 718 ; | |
C 86 ; WX 667 ; N V ; B 20 0 647 718 ; | |
C 87 ; WX 944 ; N W ; B 16 0 928 718 ; | |
C 88 ; WX 667 ; N X ; B 19 0 648 718 ; | |
C 89 ; WX 667 ; N Y ; B 14 0 653 718 ; | |
C 90 ; WX 611 ; N Z ; B 23 0 588 718 ; | |
C 91 ; WX 278 ; N bracketleft ; B 63 -196 250 722 ; | |
C 92 ; WX 278 ; N backslash ; B -17 -19 295 737 ; | |
C 93 ; WX 278 ; N bracketright ; B 28 -196 215 722 ; | |
C 94 ; WX 469 ; N asciicircum ; B -14 264 483 688 ; | |
C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ; | |
C 96 ; WX 222 ; N quoteleft ; B 65 470 169 725 ; | |
C 97 ; WX 556 ; N a ; B 36 -15 530 538 ; | |
C 98 ; WX 556 ; N b ; B 58 -15 517 718 ; | |
C 99 ; WX 500 ; N c ; B 30 -15 477 538 ; | |
C 100 ; WX 556 ; N d ; B 35 -15 499 718 ; | |
C 101 ; WX 556 ; N e ; B 40 -15 516 538 ; | |
C 102 ; WX 278 ; N f ; B 14 0 262 728 ; L i fi ; L l fl ; | |
C 103 ; WX 556 ; N g ; B 40 -220 499 538 ; | |
C 104 ; WX 556 ; N h ; B 65 0 491 718 ; | |
C 105 ; WX 222 ; N i ; B 67 0 155 718 ; | |
C 106 ; WX 222 ; N j ; B -16 -210 155 718 ; | |
C 107 ; WX 500 ; N k ; B 67 0 501 718 ; | |
C 108 ; WX 222 ; N l ; B 67 0 155 718 ; | |
C 109 ; WX 833 ; N m ; B 65 0 769 538 ; | |
C 110 ; WX 556 ; N n ; B 65 0 491 538 ; | |
C 111 ; WX 556 ; N o ; B 35 -14 521 538 ; | |
C 112 ; WX 556 ; N p ; B 58 -207 517 538 ; | |
C 113 ; WX 556 ; N q ; B 35 -207 494 538 ; | |
C 114 ; WX 333 ; N r ; B 77 0 332 538 ; | |
C 115 ; WX 500 ; N s ; B 32 -15 464 538 ; | |
C 116 ; WX 278 ; N t ; B 14 -7 257 669 ; | |
C 117 ; WX 556 ; N u ; B 68 -15 489 523 ; | |
C 118 ; WX 500 ; N v ; B 8 0 492 523 ; | |
C 119 ; WX 722 ; N w ; B 14 0 709 523 ; | |
C 120 ; WX 500 ; N x ; B 11 0 490 523 ; | |
C 121 ; WX 500 ; N y ; B 11 -214 489 523 ; | |
C 122 ; WX 500 ; N z ; B 31 0 469 523 ; | |
C 123 ; WX 334 ; N braceleft ; B 42 -196 292 722 ; | |
C 124 ; WX 260 ; N bar ; B 94 -225 167 775 ; | |
C 125 ; WX 334 ; N braceright ; B 42 -196 292 722 ; | |
C 126 ; WX 584 ; N asciitilde ; B 61 180 523 326 ;''' | |
times_new_text ='''C 32 ; WX 250 ; N space ; B 0 0 0 0 ; | |
C 33 ; WX 333 ; N exclam ; B 130 -9 238 676 ; | |
C 34 ; WX 408 ; N quotedbl ; B 77 431 331 676 ; | |
C 35 ; WX 500 ; N numbersign ; B 5 0 496 662 ; | |
C 36 ; WX 500 ; N dollar ; B 44 -87 457 727 ; | |
C 37 ; WX 833 ; N percent ; B 61 -13 772 676 ; | |
C 38 ; WX 778 ; N ampersand ; B 42 -13 750 676 ; | |
C 39 ; WX 333 ; N quoteright ; B 79 433 218 676 ; | |
C 40 ; WX 333 ; N parenleft ; B 48 -177 304 676 ; | |
C 41 ; WX 333 ; N parenright ; B 29 -177 285 676 ; | |
C 42 ; WX 500 ; N asterisk ; B 69 265 432 676 ; | |
C 43 ; WX 564 ; N plus ; B 30 0 534 506 ; | |
C 44 ; WX 250 ; N comma ; B 56 -141 195 102 ; | |
C 45 ; WX 333 ; N hyphen ; B 39 194 285 257 ; | |
C 46 ; WX 250 ; N period ; B 70 -11 181 100 ; | |
C 47 ; WX 278 ; N slash ; B -9 -14 287 676 ; | |
C 48 ; WX 500 ; N zero ; B 24 -14 476 676 ; | |
C 49 ; WX 500 ; N one ; B 111 0 394 676 ; | |
C 50 ; WX 500 ; N two ; B 30 0 475 676 ; | |
C 51 ; WX 500 ; N three ; B 43 -14 431 676 ; | |
C 52 ; WX 500 ; N four ; B 12 0 472 676 ; | |
C 53 ; WX 500 ; N five ; B 32 -14 438 688 ; | |
C 54 ; WX 500 ; N six ; B 34 -14 468 684 ; | |
C 55 ; WX 500 ; N seven ; B 20 -8 449 662 ; | |
C 56 ; WX 500 ; N eight ; B 56 -14 445 676 ; | |
C 57 ; WX 500 ; N nine ; B 30 -22 459 676 ; | |
C 58 ; WX 278 ; N colon ; B 81 -11 192 459 ; | |
C 59 ; WX 278 ; N semicolon ; B 80 -141 219 459 ; | |
C 60 ; WX 564 ; N less ; B 28 -8 536 514 ; | |
C 61 ; WX 564 ; N equal ; B 30 120 534 386 ; | |
C 62 ; WX 564 ; N greater ; B 28 -8 536 514 ; | |
C 63 ; WX 444 ; N question ; B 68 -8 414 676 ; | |
C 64 ; WX 921 ; N at ; B 116 -14 809 676 ; | |
C 65 ; WX 722 ; N A ; B 15 0 706 674 ; | |
C 66 ; WX 667 ; N B ; B 17 0 593 662 ; | |
C 67 ; WX 667 ; N C ; B 28 -14 633 676 ; | |
C 68 ; WX 722 ; N D ; B 16 0 685 662 ; | |
C 69 ; WX 611 ; N E ; B 12 0 597 662 ; | |
C 70 ; WX 556 ; N F ; B 12 0 546 662 ; | |
C 71 ; WX 722 ; N G ; B 32 -14 709 676 ; | |
C 72 ; WX 722 ; N H ; B 19 0 702 662 ; | |
C 73 ; WX 333 ; N I ; B 18 0 315 662 ; | |
C 74 ; WX 389 ; N J ; B 10 -14 370 662 ; | |
C 75 ; WX 722 ; N K ; B 34 0 723 662 ; | |
C 76 ; WX 611 ; N L ; B 12 0 598 662 ; | |
C 77 ; WX 889 ; N M ; B 12 0 863 662 ; | |
C 78 ; WX 722 ; N N ; B 12 -11 707 662 ; | |
C 79 ; WX 722 ; N O ; B 34 -14 688 676 ; | |
C 80 ; WX 556 ; N P ; B 16 0 542 662 ; | |
C 81 ; WX 722 ; N Q ; B 34 -178 701 676 ; | |
C 82 ; WX 667 ; N R ; B 17 0 659 662 ; | |
C 83 ; WX 556 ; N S ; B 42 -14 491 676 ; | |
C 84 ; WX 611 ; N T ; B 17 0 593 662 ; | |
C 85 ; WX 722 ; N U ; B 14 -14 705 662 ; | |
C 86 ; WX 722 ; N V ; B 16 -11 697 662 ; | |
C 87 ; WX 944 ; N W ; B 5 -11 932 662 ; | |
C 88 ; WX 722 ; N X ; B 10 0 704 662 ; | |
C 89 ; WX 722 ; N Y ; B 22 0 703 662 ; | |
C 90 ; WX 611 ; N Z ; B 9 0 597 662 ; | |
C 91 ; WX 333 ; N bracketleft ; B 88 -156 299 662 ; | |
C 92 ; WX 278 ; N backslash ; B -9 -14 287 676 ; | |
C 93 ; WX 333 ; N bracketright ; B 34 -156 245 662 ; | |
C 94 ; WX 469 ; N asciicircum ; B 24 297 446 662 ; | |
C 95 ; WX 500 ; N underscore ; B 0 -125 500 -75 ; | |
C 96 ; WX 333 ; N quoteleft ; B 115 433 254 676 ; | |
C 97 ; WX 444 ; N a ; B 37 -10 442 460 ; | |
C 98 ; WX 500 ; N b ; B 3 -10 468 683 ; | |
C 99 ; WX 444 ; N c ; B 25 -10 412 460 ; | |
C 100 ; WX 500 ; N d ; B 27 -10 491 683 ; | |
C 101 ; WX 444 ; N e ; B 25 -10 424 460 ; | |
C 102 ; WX 333 ; N f ; B 20 0 383 683 ; L i fi ; L l fl ; | |
C 103 ; WX 500 ; N g ; B 28 -218 470 460 ; | |
C 104 ; WX 500 ; N h ; B 9 0 487 683 ; | |
C 105 ; WX 278 ; N i ; B 16 0 253 683 ; | |
C 106 ; WX 278 ; N j ; B -70 -218 194 683 ; | |
C 107 ; WX 500 ; N k ; B 7 0 505 683 ; | |
C 108 ; WX 278 ; N l ; B 19 0 257 683 ; | |
C 109 ; WX 778 ; N m ; B 16 0 775 460 ; | |
C 110 ; WX 500 ; N n ; B 16 0 485 460 ; | |
C 111 ; WX 500 ; N o ; B 29 -10 470 460 ; | |
C 112 ; WX 500 ; N p ; B 5 -217 470 460 ; | |
C 113 ; WX 500 ; N q ; B 24 -217 488 460 ; | |
C 114 ; WX 333 ; N r ; B 5 0 335 460 ; | |
C 115 ; WX 389 ; N s ; B 51 -10 348 460 ; | |
C 116 ; WX 278 ; N t ; B 13 -10 279 579 ; | |
C 117 ; WX 500 ; N u ; B 9 -10 479 450 ; | |
C 118 ; WX 500 ; N v ; B 19 -14 477 450 ; | |
C 119 ; WX 722 ; N w ; B 21 -14 694 450 ; | |
C 120 ; WX 500 ; N x ; B 17 0 479 450 ; | |
C 121 ; WX 500 ; N y ; B 14 -218 475 450 ; | |
C 122 ; WX 444 ; N z ; B 27 0 418 450 ; | |
C 123 ; WX 480 ; N braceleft ; B 100 -181 350 680 ; | |
C 124 ; WX 200 ; N bar ; B 67 -218 133 782 ; | |
C 125 ; WX 480 ; N braceright ; B 130 -181 380 680 ; | |
C 126 ; WX 541 ; N asciitilde ; B 40 183 502 323 ;''' | |
arial_text ='''C 32 ; WX 278 ; N space ; B 0 0 0 0 ; | |
C 33 ; WX 278 ; N exclam ; B 86 0 195 716 ; | |
C 34 ; WX 355 ; N quotedbl ; B 46 462 308 716 ; | |
C 35 ; WX 556 ; N numbersign ; B 10 -12 543 728 ; | |
C 36 ; WX 556 ; N dollar ; B 36 -103 509 782 ; | |
C 37 ; WX 889 ; N percent ; B 58 -26 828 728 ; | |
C 38 ; WX 667 ; N ampersand ; B 43 -17 644 728 ; | |
C 39 ; WX 191 ; N quotesingle ; B 44 462 144 716 ; | |
C 40 ; WX 333 ; N parenleft ; B 61 -210 297 728 ; | |
C 41 ; WX 333 ; N parenright ; B 61 -210 297 728 ; | |
C 42 ; WX 389 ; N asterisk ; B 31 423 354 728 ; | |
C 43 ; WX 584 ; N plus ; B 56 116 528 589 ; | |
C 44 ; WX 278 ; N comma ; B 83 -142 189 100 ; | |
C 45 ; WX 333 ; N hyphen ; B 32 215 302 303 ; | |
C 46 ; WX 278 ; N period ; B 91 0 191 100 ; | |
C 47 ; WX 278 ; N slash ; B 0 -12 278 728 ; | |
C 48 ; WX 556 ; N zero ; B 42 -12 508 719 ; | |
C 49 ; WX 556 ; N one ; B 109 0 373 719 ; | |
C 50 ; WX 556 ; N two ; B 29 0 503 719 ; | |
C 51 ; WX 556 ; N three ; B 42 -13 511 719 ; | |
C 52 ; WX 556 ; N four ; B 13 0 508 716 ; | |
C 53 ; WX 556 ; N five ; B 42 -12 516 706 ; | |
C 54 ; WX 556 ; N six ; B 38 -12 510 719 ; | |
C 55 ; WX 556 ; N seven ; B 47 0 511 707 ; | |
C 56 ; WX 556 ; N eight ; B 41 -12 512 719 ; | |
C 57 ; WX 556 ; N nine ; B 42 -12 512 719 ; | |
C 58 ; WX 278 ; N colon ; B 90 0 190 519 ; | |
C 59 ; WX 278 ; N semicolon ; B 83 -142 189 519 ; | |
C 60 ; WX 584 ; N less ; B 55 110 529 595 ; | |
C 61 ; WX 584 ; N equal ; B 56 204 528 503 ; | |
C 62 ; WX 584 ; N greater ; B 55 110 529 595 ; | |
C 63 ; WX 556 ; N question ; B 44 0 506 728 ; | |
C 64 ; WX 1015 ; N at ; B 54 -210 979 729 ; | |
C 65 ; WX 667 ; N A ; B -1 0 668 716 ; | |
C 66 ; WX 667 ; N B ; B 73 0 614 716 ; | |
C 67 ; WX 722 ; N C ; B 50 -12 683 728 ; | |
C 68 ; WX 722 ; N D ; B 77 0 669 716 ; | |
C 69 ; WX 667 ; N E ; B 79 0 613 716 ; | |
C 70 ; WX 611 ; N F ; B 82 0 565 716 ; | |
C 71 ; WX 778 ; N G ; B 53 -12 715 728 ; | |
C 72 ; WX 722 ; N H ; B 80 0 642 716 ; | |
C 73 ; WX 278 ; N I ; B 93 0 188 716 ; | |
C 74 ; WX 500 ; N J ; B 27 -12 422 716 ; | |
C 75 ; WX 667 ; N K ; B 73 0 665 716 ; | |
C 76 ; WX 556 ; N L ; B 73 0 521 716 ; | |
C 77 ; WX 833 ; N M ; B 74 0 757 716 ; | |
C 78 ; WX 722 ; N N ; B 76 0 640 716 ; | |
C 79 ; WX 778 ; N O ; B 48 -12 733 729 ; | |
C 80 ; WX 667 ; N P ; B 77 0 624 716 ; | |
C 81 ; WX 778 ; N Q ; B 43 -56 741 729 ; | |
C 82 ; WX 722 ; N R ; B 79 0 709 716 ; | |
C 83 ; WX 667 ; N S ; B 45 -12 615 728 ; | |
C 84 ; WX 611 ; N T ; B 23 0 591 716 ; | |
C 85 ; WX 722 ; N U ; B 79 -12 642 716 ; | |
C 86 ; WX 667 ; N V ; B 4 0 659 716 ; | |
C 87 ; WX 944 ; N W ; B 12 0 933 716 ; | |
C 88 ; WX 667 ; N X ; B 4 0 661 716 ; | |
C 89 ; WX 667 ; N Y ; B 3 0 659 716 ; | |
C 90 ; WX 611 ; N Z ; B 20 0 586 716 ; | |
C 91 ; WX 278 ; N bracketleft ; B 68 -199 262 716 ; | |
C 92 ; WX 278 ; N backslash ; B 0 -12 278 728 ; | |
C 93 ; WX 278 ; N bracketright ; B 19 -199 213 716 ; | |
C 94 ; WX 469 ; N asciicircum ; B 26 337 443 728 ; | |
C 95 ; WX 556 ; N underscore ; B -15 -199 567 -135 ; | |
C 96 ; WX 333 ; N grave ; B 43 583 227 720 ; | |
C 97 ; WX 556 ; N a ; B 36 -12 514 530 ; | |
C 98 ; WX 556 ; N b ; B 65 -12 515 716 ; | |
C 99 ; WX 500 ; N c ; B 39 -12 491 530 ; | |
C 100 ; WX 556 ; N d ; B 34 -12 484 716 ; | |
C 101 ; WX 556 ; N e ; B 37 -12 515 530 ; | |
C 102 ; WX 278 ; N f ; B 9 0 312 728 ; | |
C 103 ; WX 556 ; N g ; B 32 -210 489 530 ; | |
C 104 ; WX 556 ; N h ; B 66 0 488 716 ; | |
C 105 ; WX 222 ; N i ; B 66 0 154 716 ; | |
C 106 ; WX 222 ; N j ; B -46 -210 153 716 ; | |
C 107 ; WX 500 ; N k ; B 66 0 496 716 ; | |
C 108 ; WX 222 ; N l ; B 64 0 152 716 ; | |
C 109 ; WX 833 ; N m ; B 66 0 769 530 ; | |
C 110 ; WX 556 ; N n ; B 66 0 487 530 ; | |
C 111 ; WX 556 ; N o ; B 33 -12 519 530 ; | |
C 112 ; WX 556 ; N p ; B 66 -199 516 530 ; | |
C 113 ; WX 556 ; N q ; B 35 -199 484 530 ; | |
C 114 ; WX 333 ; N r ; B 65 0 347 530 ; | |
C 115 ; WX 500 ; N s ; B 31 -12 461 530 ; | |
C 116 ; WX 278 ; N t ; B 18 -7 271 700 ; | |
C 117 ; WX 556 ; N u ; B 64 -12 484 519 ; | |
C 118 ; WX 500 ; N v ; B 13 0 488 519 ; | |
C 119 ; WX 722 ; N w ; B 3 0 714 519 ; | |
C 120 ; WX 500 ; N x ; B 7 0 493 519 ; | |
C 121 ; WX 500 ; N y ; B 16 -210 491 519 ; | |
C 122 ; WX 500 ; N z ; B 20 0 479 519 ; | |
C 123 ; WX 334 ; N braceleft ; B 28 -210 311 728 ; | |
C 124 ; WX 260 ; N bar ; B 92 -210 168 728 ; | |
C 125 ; WX 334 ; N braceright ; B 23 -210 306 728 ; | |
C 126 ; WX 584 ; N asciitilde ; B 42 272 542 432 ; | |
C 128 ; WX 556 ; N uni20AC ; B -14 -12 541 728 ;''' | |
def parse(text: str) -> dict[str, float]: | |
chmap = {} | |
for line in text.split("\n"): | |
match = re.match(r'C (\d+) ; WX (\d+)', line) | |
k, v = map(int, match.groups()) | |
if k < 128 and chr(k).isprintable(): | |
chmap[k] = v | |
return {chr(k): v/chmap[ord('m')] for (k,v) in chmap.items()} | |
helveticamap = parse(helvetica_text) | |
timesmap = parse(times_new_text) | |
arialmap = parse(arial_text) | |
middlemap = {} | |
err = [] | |
for k, tv in timesmap.items(): | |
hv = helveticamap[k] | |
av = arialmap[k] | |
mv = round((tv + hv) / 2., 3) | |
middlemap[k] = mv | |
err.append(abs(mv - av) / av) | |
arial_avg = mean(arialmap.values()) | |
print(json.dumps(middlemap)) | |
print('Mean percentage error using constant width: ', mean(abs(arial_avg - v) for v in arialmap.values())) | |
print('Mean percentage error using approximate per-character widths: ', mean(err)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment