Initial Release

This commit is contained in:
Ekta Sood 2020-11-19 15:49:22 +01:00
parent 0cc1bebf18
commit 5cc0ae8c18
24 changed files with 1753 additions and 1 deletions

202
LICENSE.txt Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2020 Ekta Sood
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -1 +1,47 @@
Tool will be available soon.
## Viz-Tool for Fixations
### Usage
1. Install dependencies with `npm i`.
2. Run a local server with `./start.sh`.
3. Load a file with fixations and its corresponding image of the text. There are some examples in the `example_data` folder.
![fig/menu.png](fig/menu.png)
4. You can also enter split screen mode via the button in the bottom left.
![fig/split_screen.png](fig/split_screen.png)
### Deployment
1. Run `npm run build` to generate bundle files in public folder
2. Copy the entire public directory to your web root, you may also need a reverse proxy (nginx, apache)
## Data format explanation
Fixation data has to be provided in csv format with the following headers
|Header|Example|
|---------|---------|
| x y duration word_id word |646.0 284.0 675 74 exonerated|
## Citing Viz-Tool
```bibtex
@inproceedings{sood-etal-2020-interpreting,
title = "Interpreting Attention Models with Human Visual Attention in Machine Reading Comprehension",
author = "Sood, Ekta and
Tannert, Simon and
Frassinelli, Diego and
Bulling, Andreas and
Vu, Ngoc Thang",
booktitle = "Proceedings of the 24th Conference on Computational Natural Language Learning",
month = nov,
year = "2020",
address = "Online",
publisher = "Association for Computational Linguistics",
url = "https://www.aclweb.org/anthology/2020.conll-1.2",
pages = "12--25",
abstract = "While neural networks with attention mechanisms have achieved superior performance on many natural language processing tasks, it remains unclear to which extent learned attention resembles human visual attention. In this paper, we propose a new method that leverages eye-tracking data to investigate the relationship between human visual attention and neural attention in machine reading comprehension. To this end, we introduce a novel 23 participant eye tracking dataset - MQA-RC, in which participants read movie plots and answered pre-defined questions. We compare state of the art networks based on long short-term memory (LSTM), convolutional neural models (CNN) and XLNet Transformer architectures. We find that higher similarity to human attention and performance significantly correlates to the LSTM and CNN models. However, we show this relationship does not hold true for the XLNet models {--} despite the fact that the XLNet performs best on this challenging task. Our results suggest that different architectures seem to learn rather different neural attention strategies and similarity of neural to human attention does not guarantee best performance.",
}
```

View file

@ -0,0 +1,163 @@
# 317.txt_wrapped.txt.c
x y dur word_id word
916.0 529.0 3755 170 the
715.0 131.0 117 37 field,
593.0 65.0 280 0 When
640.0 58.0 348 1 Don
709.0 48.0 250 3 her
818.0 35.0 302 5 she
926.0 32.0 280
989.0 23.0 318
1121.0 38.0 210 12 which
1086.0 34.0 282 12 which
1147.0 44.0 210 13 results
1215.0 54.0 270 14 in
635.0 102.0 167 18 biker
598.0 112.0 465 18 biker
672.0 104.0 87 19 friends
754.0 99.0 413 20 punching
683.0 102.0 280 19 friends
784.0 91.0 532 21 Don
898.0 80.0 173 24 next
862.0 90.0 267 23 The
930.0 80.0 238 25 morning,
1013.0 76.0 278 10 becomes
1087.0 74.0 233 12 which
1017.0 77.0 148 11 enraged,
1166.0 92.0 100 30 his
1175.0 89.0 98 30 his
615.0 159.0 177 34 middle
582.0 159.0 217
816.0 131.0 198 40 nasty
753.0 145.0 392 38 with
728.0 147.0 210 37 field,
570.0 205.0 270
632.0 198.0 228 46 Later,
673.0 194.0 235 47 Don
752.0 187.0 230 50 a
836.0 179.0 397 52 to
979.0 171.0 200 55 from
939.0 173.0 243 54 flowers
1026.0 168.0 258 45 eye.
1100.0 164.0 373
1148.0 178.0 232 59 named
1166.0 188.0 128 60 Sun
1232.0 192.0 117 62 who
1241.0 162.0 162
1225.0 194.0 225 61 Green
591.0 257.0 203 64 his
562.0 255.0 322
675.0 239.0 225 66 Don
599.0 244.0 118 64 his
1258.0 200.0 338 62 who
582.0 255.0 350
608.0 251.0 200 64 his
672.0 243.0 407 66 Don
718.0 239.0 237 67 leaves
826.0 231.0 175 69 flowers
951.0 221.0 252 73 of
648.0 244.0 240 65 cut.
987.0 226.0 232 74 the
1084.0 216.0 287 76 woman,
1123.0 214.0 197 59 named
1174.0 229.0 317 77 Michelle
1217.0 237.0 523 78 Pepe,
914.0 233.0 155 72 grave
1204.0 231.0 265 78 Pepe,
577.0 290.0 1215
625.0 281.0 275 81 originally
768.0 277.0 223 83 might
870.0 250.0 155 71 the
834.0 261.0 198 85 the
921.0 257.0 253 72 grave
889.0 261.0 125 86 mother
964.0 243.0 110 73 of
1065.0 257.0 223 76 woman,
1121.0 266.0 197 92 died
1187.0 275.0 143 93 five
595.0 340.0 362 96 Finally,
574.0 338.0 200
703.0 332.0 257 98 returns
833.0 315.0 215 100 where
929.0 316.0 380 103 a
1063.0 312.0 423 106 from
1147.0 320.0 310 108 admitting
1217.0 319.0 180 109 she
589.0 392.0 202
542.0 395.0 317
638.0 432.0 128 127 have
646.0 403.0 258 127 have
735.0 393.0 193 114 discusses
660.0 392.0 183 112 him.
759.0 379.0 592 114 discusses
853.0 384.0 513 116 trip
932.0 387.0 242 118 second
836.0 381.0 265 116 trip
949.0 374.0 232 119 letter
1019.0 372.0 195 120 with
1095.0 370.0 300 121 Winston,
1181.0 367.0 375 123 theorizes
1128.0 368.0 298 122 who
1197.0 367.0 247 123 theorizes
560.0 426.0 177
533.0 433.0 292
631.0 444.0 187 143 letters.
604.0 438.0 215 126 might
690.0 437.0 347 128 written
752.0 435.0 280 129 the
831.0 440.0 113 148 young
1013.0 421.0 213 135 He
974.0 417.0 320 134 hoax.
1045.0 415.0 388 136 then
1111.0 420.0 255 138 home
1169.0 420.0 518 140 compare
586.0 478.0 188
553.0 476.0 232
629.0 472.0 257 143 letters.
704.0 469.0 238 145 then
670.0 471.0 225 144 Don
765.0 466.0 270 146 meets
874.0 465.0 183 149 man
847.0 467.0 207 149 man
984.0 462.0 625 152 street
1114.0 465.0 438 155 suspects
1227.0 451.0 268 159 son.
557.0 513.0 272
652.0 520.0 160 164 meal,
649.0 522.0 187 164 meal,
745.0 518.0 267 166 when
873.0 517.0 212 169 that
740.0 525.0 278 166 when
866.0 513.0 217 169 that
942.0 518.0 280 171 young
1022.0 510.0 225 173 believes
1081.0 519.0 197 174 that
1145.0 501.0 225 176 is
1207.0 495.0 150 178 father,
590.0 558.0 160 180 young
540.0 561.0 205
546.0 561.0 95
617.0 553.0 187 180 young
615.0 558.0 63 180 young
689.0 557.0 335 182 becomes
780.0 573.0 95 183 agitated
515.0 785.0 187
610.0 766.0 192
541.0 770.0 102
535.0 759.0 115
650.0 749.0 268 187 does
708.0 739.0 103 189 suspect
716.0 736.0 103 189 suspect
812.0 737.0 242 190 about
887.0 732.0 355 192 young
950.0 727.0 370 195 meets
619.0 845.0 327 206 That
667.0 847.0 148 207 he
549.0 852.0 237
589.0 837.0 330
549.0 824.0 90
651.0 825.0 238 200 That
615.0 824.0 185 200 That
543.0 821.0 160
1808.0 1003.0 163
1804.0 1008.0 1577

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -0,0 +1,182 @@
# 66.txt_wrapped.txt.c
x y dur word_id word
912.0 547.0 1822 162 eventually
603.0 66.0 415 0 When
574.0 71.0 220
637.0 70.0 260 1 Mrs
706.0 67.0 272 2 Moore
795.0 60.0 348 5 clear
892.0 49.0 207 7 she
851.0 56.0 175 6 that
820.0 63.0 185 5 clear
934.0 52.0 247 8 firmly
985.0 52.0 187 9 believes
1056.0 53.0 428 11 Aziz's
1127.0 50.0 318 12 innocence
1215.0 67.0 200 13 and
603.0 116.0 598 16 testify
801.0 111.0 195 20 is
759.0 129.0 287 34 during
855.0 114.0 248 21 decided
815.0 115.0 235 21 decided
920.0 102.0 227 23 should
1008.0 102.0 302 24 return
927.0 107.0 297 23 should
1003.0 104.0 342 24 return
1022.0 127.0 107 40 at
1128.0 83.0 358 27 She
1152.0 70.0 165 12 innocence
1227.0 93.0 172 28 subsequently
642.0 140.0 145 31 fatal
596.0 154.0 302 30 a
661.0 146.0 345 32 heart
725.0 142.0 288 33 attack
767.0 137.0 270 34 during
853.0 130.0 325 36 voyage
937.0 123.0 450 23 should
1000.0 121.0 223 24 return
636.0 191.0 263 43 the
614.0 195.0 208 43 the
703.0 182.0 178 44 consternation
789.0 175.0 285 46 her
870.0 170.0 253 48 and
790.0 179.0 237 46 her
826.0 174.0 158 47 fianc
906.0 171.0 252 49 friends,
972.0 169.0 553 39 buried
1063.0 168.0 230 41 sea.
1004.0 171.0 235 50 Adela
1115.0 161.0 255
1162.0 173.0 157 55 heart
1212.0 175.0 303 56 and
1247.0 182.0 125 57 clears
1206.0 175.0 308 56 and
590.0 249.0 215 59 in
564.0 246.0 250
694.0 225.0 448 61 The
779.0 224.0 278 62 Colonials
823.0 220.0 198 64 forced
920.0 216.0 312 66 an
1009.0 219.0 188 67 ignominious
1053.0 215.0 498 68 retreat
1142.0 221.0 313 70 the
1082.0 223.0 255 68 retreat
1208.0 227.0 432 71 Indians
583.0 298.0 522
646.0 284.0 675 74 exonerated
814.0 266.0 225 78 courtroom
793.0 274.0 212 78 courtroom
937.0 267.0 253 81 shoulders,
1051.0 267.0 128 82 cheering
1023.0 267.0 260 82 cheering
1095.0 288.0 138 83 wildly.
1140.0 273.0 87 83 wildly.
1150.0 249.0 155 70 the
1209.0 272.0 382 84 Fielding
1195.0 313.0 72 101 leaves
1111.0 317.0 328 99 aftermath,
551.0 360.0 150
593.0 336.0 317 86 after
561.0 336.0 207
637.0 329.0 315 86 after
702.0 327.0 247 88 since
661.0 332.0 292 87 Adela
866.0 320.0 235 93 else
928.0 314.0 167 95 turn
1027.0 314.0 237 98 the
1095.0 315.0 158 99 aftermath,
1135.0 320.0 210 100 Adela
1192.0 313.0 255 101 leaves
1168.0 317.0 153 100 Adela
582.0 385.0 935
647.0 375.0 222 104 Dr
734.0 365.0 225 106 feeling
705.0 369.0 257 105 Aziz,
865.0 363.0 215 108 by
831.0 367.0 213 107 betrayed
951.0 367.0 512 110 friend
1052.0 369.0 263 112 abandons
1031.0 371.0 338 111 Fielding,
1120.0 360.0 343 113 his
1189.0 361.0 340 114 Western
1242.0 369.0 155 115 attire,
604.0 438.0 195 117 traditional
575.0 424.0 252
767.0 405.0 508 119 and
873.0 407.0 308 121 from
924.0 413.0 273 122 ex-pat
1030.0 411.0 482 124 opening
1132.0 405.0 175 126 clinic
1181.0 413.0 345 127 in
1239.0 419.0 135 128 Kashmir
615.0 466.0 183 131 Himalayas.
566.0 463.0 363
656.0 469.0 523 131 Himalayas.
759.0 463.0 298 132 Meanwhile,
808.0 476.0 100 133 through
888.0 457.0 227 135 Fielding
944.0 469.0 252 135 Fielding
921.0 463.0 238 135 Fielding
1020.0 459.0 287 137 married
1083.0 457.0 273 138 Stella
1148.0 463.0 502 139 Moore,
1070.0 467.0 218 138 Stella
1139.0 464.0 217 139 Moore,
585.0 508.0 182
543.0 504.0 275
707.0 511.0 285 144 second
1027.0 501.0 247 150 first
1138.0 509.0 412 152 child.
1193.0 519.0 490 153 While
623.0 557.0 195 156 angry
544.0 562.0 272
657.0 564.0 262 157 and
761.0 568.0 290 160 years,
855.0 548.0 702 162 eventually
961.0 543.0 255 163 reconciles
1085.0 548.0 480 165 Fielding
1169.0 557.0 368 166 and
1238.0 574.0 70 168 to
574.0 611.0 403
656.0 620.0 135
776.0 615.0 183 174 and
594.0 759.0 213
548.0 760.0 168
619.0 750.0 243 176 Does
660.0 750.0 250 177 Aziz
668.0 752.0 92 177 Aziz
657.0 753.0 153 177 Aziz
712.0 756.0 65
802.0 749.0 160 179 Fielding
906.0 727.0 207 183 of
697.0 747.0 225 178 forgive
605.0 740.0 212 176 Does
561.0 749.0 95
642.0 734.0 298 177 Aziz
732.0 735.0 287 178 forgive
836.0 735.0 337 181 the
673.0 615.0 292 172 his
796.0 566.0 245 160 years,
1133.0 549.0 313 165 Fielding
1062.0 550.0 200 164 with
919.0 544.0 320 162 eventually
986.0 541.0 130 163 reconciles
605.0 863.0 177 192 2:
573.0 856.0 200
571.0 911.0 282
532.0 909.0 235
633.0 826.0 282 187 No,
696.0 819.0 180 189 he
741.0 820.0 233 190 forgives
602.0 850.0 155 192 2:
619.0 822.0 232 187 No,
677.0 815.0 253 188 but
603.0 904.0 238 194 3:
549.0 938.0 197
1244.0 886.0 67
1803.0 1029.0 67
1420.0 1292.0 68
1385.0 1289.0 105
1426.0 1280.0 132
1804.0 999.0 80
1405.0 1281.0 278

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View file

@ -0,0 +1,199 @@
# 848.txt_wrapped.txt.c
x y dur word_id word
920.0 530.0 213 169 as
644.0 475.0 108 143 clutching
613.0 73.0 222 0 Whale
583.0 72.0 428
637.0 67.0 292 0 Whale
697.0 63.0 455 2 only
774.0 62.0 288 5 sweater,
842.0 53.0 318 6 so
902.0 43.0 493 7 Boone
933.0 45.0 178 8 wears
909.0 48.0 182 7 Boone
987.0 44.0 322 10 towel
1039.0 39.0 287 11 wrapped
1130.0 38.0 297 12 around
1076.0 37.0 203 11 wrapped
1177.0 50.0 185 14 waist.
1211.0 56.0 198 14 waist.
664.0 87.0 152 17 to
571.0 105.0 250
657.0 107.0 142 17 to
693.0 87.0 130 18 try
724.0 103.0 72 19 to
746.0 102.0 427 20 sketch
827.0 95.0 308 21 Boone
885.0 87.0 220 23 more
990.0 82.0 255 25 After
959.0 85.0 223 25 After
1054.0 82.0 202 27 minutes,
1145.0 98.0 312 29 shows
1215.0 102.0 268 30 his
626.0 160.0 188 33 Boone,
567.0 163.0 365
657.0 154.0 620 34 disclosing
798.0 143.0 255 37 has
884.0 128.0 368 39 his
1002.0 120.0 228 25 After
1087.0 125.0 228 44 Boone
1035.0 126.0 228 42 draw.
1122.0 132.0 280 44 Boone
1197.0 143.0 175 46 his
590.0 200.0 608 49 pose
690.0 191.0 502 51 Whale
647.0 197.0 313 50 nude,
729.0 190.0 240 52 makes
827.0 184.0 253 54 wear
799.0 196.0 157 53 him
878.0 190.0 167 56 World
785.0 197.0 257 53 him
961.0 187.0 467 59 gas
1127.0 201.0 208 63 uses
1066.0 189.0 342 62 then
1196.0 198.0 178 65 opportunity
585.0 255.0 208
666.0 242.0 192 69 sexual
721.0 242.0 272 70 advance
791.0 242.0 225 72 Boone,
842.0 245.0 238 72 Boone,
939.0 233.0 355 74 his
897.0 232.0 175 73 kissing
1022.0 226.0 287 76 Boone
1089.0 225.0 573 77 becomes
1165.0 236.0 172 78 enraged
1213.0 240.0 273 79 and
640.0 295.0 233 81 Whale,
591.0 295.0 375 81 Whale,
656.0 296.0 270 82 who
740.0 288.0 250 83 confesses
844.0 275.0 242 86 had
926.0 279.0 242 88 his
1024.0 272.0 262 91 begs
1002.0 270.0 178 90 and
1106.0 266.0 285 93 to
1197.0 278.0 307 95 him
1221.0 275.0 120 96 to
616.0 341.0 452 100 his
744.0 330.0 285 102 Boone
717.0 335.0 162 101 suffering.
801.0 326.0 155 103 refuses,
882.0 325.0 268 104 puts
853.0 333.0 307 103 refuses,
992.0 321.0 333 107 bed,
924.0 322.0 125 105 Whale
1052.0 317.0 272 109 sleeps
1121.0 319.0 152 110 downstairs.
1021.0 320.0 263 108 then
1206.0 322.0 428 111 The
709.0 369.0 173 114 Hanna
610.0 377.0 190 113 morning,
585.0 375.0 197
671.0 370.0 338 114 Hanna
758.0 376.0 213 116 alarmed
891.0 375.0 425 119 can't
964.0 369.0 170 121 Whale,
1033.0 367.0 383 122 prompting
1132.0 365.0 318 124 search
1094.0 365.0 177 123 a
669.0 425.0 232 129 Boone
627.0 424.0 170 128 Hanna.
721.0 425.0 208 130 finds
828.0 423.0 330 132 floating
896.0 413.0 185 133 dead
1031.0 423.0 362 138 a
1133.0 416.0 232 139 distraught
1164.0 415.0 138 140 Hanna
604.0 472.0 277 143 clutching
672.0 473.0 312 144 a
816.0 471.0 93 147 Boone
837.0 467.0 197 147 Boone
955.0 474.0 208 150 agree
1042.0 470.0 168 152 Boone
1132.0 459.0 277 154 disappear
1230.0 455.0 185 155 from
600.0 515.0 152 158 to
584.0 520.0 313
670.0 532.0 215 164 closes
596.0 552.0 435 162 The
705.0 590.0 333 180 Frankenstein
649.0 594.0 172 179 of
574.0 604.0 192
673.0 541.0 363 164 closes
719.0 546.0 168 165 roughly
807.0 548.0 480 167 decade
906.0 549.0 282 169 as
1016.0 562.0 260 172 his
1103.0 558.0 302 174 son,
1182.0 542.0 227 175 Michael,
601.0 603.0 190 178 Bride
553.0 606.0 197
736.0 586.0 325 180 Frankenstein
616.0 557.0 340 162 The
849.0 543.0 212 167 decade
724.0 544.0 170 165 roughly
665.0 556.0 237 164 closes
603.0 561.0 138 162 The
605.0 570.0 112 162 The
680.0 558.0 187 164 closes
754.0 575.0 153 180 Frankenstein
707.0 572.0 68 164 closes
707.0 566.0 82 164 closes
804.0 569.0 142 167 decade
742.0 570.0 63 165 roughly
741.0 591.0 73 180 Frankenstein
819.0 589.0 278 182 television.
922.0 563.0 217 169 as
985.0 569.0 390 171 and
1085.0 562.0 203 173 young
1170.0 542.0 215 175 Michael,
644.0 657.0 205
589.0 611.0 167
565.0 614.0 195
558.0 778.0 92
552.0 778.0 190
644.0 762.0 322
544.0 772.0 85
520.0 778.0 177
630.0 755.0 183
709.0 748.0 203 185 Whale's
525.0 872.0 188
684.0 753.0 245 185 Whale's
824.0 428.0 220 132 floating
790.0 489.0 168
776.0 470.0 142 146 note.
805.0 398.0 275 132 floating
880.0 413.0 265 133 dead
1094.0 422.0 202 139 distraught
1030.0 363.0 248 122 prompting
916.0 339.0 275 105 Whale
923.0 371.0 250 120 find
1023.0 369.0 260 122 prompting
1127.0 362.0 195 124 search
1101.0 362.0 233 123 a
1165.0 366.0 172 124 search
1182.0 335.0 178 110 downstairs.
602.0 384.0 362 113 morning,
746.0 380.0 242 116 alarmed
713.0 392.0 202 115 is
888.0 460.0 312 149 Hanna
960.0 422.0 175 136 pool,
1052.0 416.0 312 139 distraught
1108.0 371.0 363 123 a
716.0 424.0 287 130 finds
651.0 424.0 218 129 Boone
766.0 416.0 192 131 Whale
682.0 460.0 323 144 a
586.0 452.0 103
1024.0 420.0 280 137 as
999.0 423.0 178 136 pool,
1115.0 428.0 202 139 distraught
1156.0 414.0 280 140 Hanna
595.0 476.0 178 143 clutching
556.0 851.0 335
570.0 898.0 145
543.0 876.0 183
568.0 880.0 148
1685.0 918.0 88
1846.0 1003.0 357
1817.0 999.0 915

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
fig/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
fig/split_screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

22
package.json Normal file
View file

@ -0,0 +1,22 @@
{
"name": "svelte-app",
"version": "1.0.0",
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public"
},
"devDependencies": {
"rollup": "^1.12.0",
"rollup-plugin-commonjs": "^10.0.0",
"rollup-plugin-livereload": "^1.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-svelte": "~6.1.1",
"rollup-plugin-terser": "^5.1.2",
"rollup-plugin-css-only": "^1.0.0",
"svelte": "^3.0.0"
},
"dependencies": {
"sirv-cli": "^0.4.4"
}
}

6
public/base.css Normal file
View file

@ -0,0 +1,6 @@
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}

18
public/index.html Normal file
View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Fixation Visualization Tool</title>
<link rel="stylesheet" href="base.css">
<link rel='stylesheet' href='/build/bundle.css'>
<link rel='stylesheet' href='/build/vendor.css'>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>

74
rollup.config.js Normal file
View file

@ -0,0 +1,74 @@
import svelte from 'rollup-plugin-svelte';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import { terser } from 'rollup-plugin-terser';
import css from 'rollup-plugin-css-only';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/main.js',
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: 'public/build/bundle.js'
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: !production,
// we'll extract any component CSS out into
// a separate file — better for performance
css: css => {
css.write('bundle.css');
}
}),
css({ output: 'public/build/vendor.css' }),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration —
// consult the documentation for details:
// https://github.com/rollup/rollup-plugin-commonjs
resolve({
browser: true,
dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
}),
commonjs(),
// In dev mode, call `npm run start` once
// the bundle has been generated
!production && serve(),
// Watch the `public` directory and refresh the
// browser on changes when not in production
!production && livereload('public'),
// If we're building for production (npm run build
// instead of npm run dev), minify
production && terser()
],
watch: {
clearScreen: false
}
};
function serve() {
let started = false;
return {
writeBundle() {
if (!started) {
started = true;
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true
});
}
}
};
}

127
src/App.svelte Normal file
View file

@ -0,0 +1,127 @@
<script>
import Visualization from './Visualization.svelte';
import { config } from './stores.js';
import './vendor/normalize.css';
import './vendor/milligram.min.css';
let isAnimated = false;
let splitscreen = false;
let controlsOpen = false;
let left, right;
function handleKeyboard(event) {
switch (event.code) {
case 'ArrowLeft':
//i = (i>0) ? i-1 : data.length-1;
event.preventDefault();
break;
case 'ArrowRight':
//i = (i<data.length-1) ? i+1 : 0;
event.preventDefault();
break;
case 'ArrowUp':
$config.speed += 10;
event.preventDefault();
break;
case 'ArrowDown':
$config.speed -= 10;
event.preventDefault();
break;
case 'Space':
isAnimated = !isAnimated;
event.preventDefault();
break;
}
//log current index on the lower right
}
function reset() {
left.reset();
if (splitscreen) {
right.reset();
}
}
</script>
<svelte:window on:keydown={handleKeyboard} />
<main>
<Visualization bind:this={left} {isAnimated}/>
{#if splitscreen}<Visualization bind:this={right} {isAnimated}/>{/if}
</main>
<aside class:open={controlsOpen}>
<label class="hideCheckbox toggle" title="Open Controls"><input type="checkbox" bind:checked={controlsOpen}></label>
<div id="controls">
<h3>Controls</h3>
<p><small>Press Space to pause and use arrow keys to skip or change speed</small></p>
<label>Zoom:<br/><input type="number" id="zoom" step="1" value={$config.zoom} on:change={e => $config.zoom = e.target.value}></label>
<label>Speed:<br/><input type="number" id="speed" step="1" value={$config.speed} on:change={e => $config.speed = e.target.value}></label>
<label>Duration Multiplier:<br/><input type="number" id="duration_multiplier" step="0.1" value={$config.duration_multiplier} on:change={e => $config.duration_multiplier = e.target.value}></label>
<label>Trace Length:<br/><input type="number" id="trace_length" step="1" value={$config.trace_length} on:change={e => $config.trace_length = e.target.value}></label>
<label>Duration Function Exponent:<br/><input type="number" id="exp" step="0.1" value={$config.duration_exponent} on:change={e => $config.duration_exponent = e.target.value}></label>
</div>
<label id="run" class="hideCheckbox toggle" title="Run Animation">{#if !isAnimated}{:else}{/if}<input type="checkbox" bind:checked={isAnimated}></label>
<label id="split" class="hideCheckbox toggle" title="Make Splitscreen">{#if !splitscreen}🗖{:else}🗗{/if}<input type="checkbox" bind:checked={splitscreen}></label>
<span id="reset" class="toggle" title="Reset Animation" on:click={reset}>↶</span>
</aside>
<style>
main {
display: flex;
height: 100%;
width: 100%;
}
aside {
position: absolute;
left: -20vw;
transition: left 0.5s;
top: 0;
bottom: 0;
width: 20vw;
padding: 20px;
background: white;
}
.open {
left: 0;
}
.toggle {
position: absolute;
right: -30px;
width: 20px;
font-size: 20px;
line-height: 20px;
cursor: pointer;
text-align: center;
transition: left 0.5s;
margin: 0;
font-family: monospace;
}
.hideCheckbox > input {
position: absolute;
left: -9999px;
}
#run {
bottom: 100px;
}
#split {
bottom: 60px;
}
#reset {
bottom: 20px;
}
</style>

52
src/FilePicker.svelte Normal file
View file

@ -0,0 +1,52 @@
<script>
import { createEventDispatcher } from 'svelte';
import { readFileAsync } from './helpers';
import Papa from './vendor/papaparse.min.js';
let datafiles, imagefiles, isValid, fixation_data, sequential_fixation_data;
const image = new Image();
const dispatch = createEventDispatcher();
$: isValid = datafiles && imagefiles && datafiles[0] && imagefiles[0];
async function visualize() {
image.src = await readFileAsync(imagefiles[0]);
let parsing = new Promise( resolve => {
Papa.parse(datafiles[0], {
comments: '#',
header: true,
dynamicTyping: true,
complete: results => {
if (!results.data[0].x || !results.data[0].y || !results.data[0].dur || !results.data[0].word_id || !results.data[0].word) {
throw Error('Data malformed. Please use csv style tab-separated format with headers x,y,dur,word_id, word as first line.');
}
fixation_data = results.data;
resolve();
}
});
});
parsing.then( () => {
dispatch('load', {image, fixation_data})
});
}
</script>
<div id="overlay">
<h1>Choose Fixation Data and Image</h1>
<label>Fixation Data<br/><input bind:files={datafiles} type="file" accept=".txt" /></label>
<label>Image<br /><input bind:files={imagefiles} type="file" accept=".png, .jpg" /></label>
<button id="run-button" class="button" on:click={visualize} disabled={!isValid}>Visualize!</button>
</div>
<style>
#overlay {
width: 400px;
height: 200px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>

203
src/Visualization.svelte Normal file
View file

@ -0,0 +1,203 @@
<script>
export let isAnimated = false;
import FilePicker from './FilePicker.svelte';
import { onMount, onDestroy, tick as nextTick } from 'svelte';
import { config } from './stores.js';
import { aggregateWordFixations } from './helpers';
let observer, canvas, progress, ctx, show_sequential, fixation_data, sequential_fixation_data, fixation_backdrop, data, container;
$: {
data = (show_sequential) ? sequential_fixation_data : fixation_data;
reset();
}
let i = 0, t = null, isInitialized = false;
onMount(() => {
ctx = canvas.getContext('2d');
observer = new ResizeObserver( entries => {
canvas.height = entries[0].contentRect.height;
canvas.width = entries[0].contentRect.width;
});
observer.observe(container);
});
onDestroy(() => {
observer.disconnect();
});
async function onLoad(event) {
fixation_data = event.detail.fixation_data;
sequential_fixation_data = aggregateWordFixations(event.detail.fixation_data);
fixation_backdrop = event.detail.image;
isInitialized = true;
await nextTick();
//config.update(c => {c.$config.zoom = canvas.width/fixation_backdrop.width; return c;});
requestAnimationFrame(tick);
}
function tick(time) {
if (!data || !fixation_backdrop) {
requestAnimationFrame(tick);
return;
}
let dt;
if (isAnimated){
if (t == null) t = time;
dt = (time - t)*$config.speed/100
if (dt > data[i].dur) {
i = (i<data.length-1)?i+1:0;
t = time;
progress.style.width = (100/data.length*i)+'%';
}
} else {
dt = data[i].dur;
progress.style.width = (100/data.length*i)+'%';
}
ctx.clearRect(0, 0, 5000, 5000);
ctx.save();
drawBackdrop();
drawFixation(data[i], dt);
drawTrace(data.slice((i-$config.trace_length>0)?i-$config.trace_length:0,i+1))
ctx.restore();
requestAnimationFrame(tick);
}
export function reset() {
i = 0;
t = null;
}
function transform({ x, y }) {
// transforms coordinates from image space into drawing space
return [$config.zoom/100 * x + $config.translatex, $config.zoom/100 * y + $config.translatey]
}
function drawBackdrop() {
ctx.drawImage(fixation_backdrop, $config.translatex, $config.translatey, $config.zoom/100*fixation_backdrop.width, $config.zoom/100*fixation_backdrop.height);
}
function drawFixation({ x, y, dur }, dt) {
ctx.save();
ctx.beginPath();
let radius = Math.pow(dt/dur, $config.duration_exponent)*dur*$config.duration_multiplier;
let [xt, yt] = transform({x, y});
let gradient;
try {
gradient = ctx.createRadialGradient(xt,yt,0, xt,yt,radius);
} catch(e) {
console.error(e);
return;
}
gradient.addColorStop(0, 'rgb(200, 0, 0, 0.5)');
gradient.addColorStop(1, 'rgb(200, 0, 0, 0)');
ctx.fillStyle = gradient;
ctx.arc(xt, yt, radius, 0, Math.PI*2, true);
ctx.fill();
ctx.restore();
}
function drawTrace(trace) {
ctx.save()
ctx.lineWidth = $config.trace_width;
let alpha = 0.2 + 0.8/$config.trace_length;
let i=0, xt, yt, xtn, ytn;
for (i; i<trace.length-1; i++) {
let { x, y } = trace[i];
let { x:xn, y:yn } = trace[i+1];
[xt, yt] = transform({x, y});
[xtn, ytn] = transform({x:xn, y:yn});
ctx.strokeStyle = `rgba(0,0,0,${alpha}`;
ctx.beginPath();
ctx.moveTo(xt, yt);
ctx.arc(xt, yt, $config.trace_radius, 0, Math.PI*2, true);
ctx.lineTo(xtn, ytn);
ctx.stroke();
alpha += 0.8/$config.trace_length;
}
ctx.beginPath();
ctx.arc(xt, yt, $config.trace_radius, 0, Math.PI*2, true);
ctx.stroke();
ctx.restore();
}
function translate(e) {
if (e.buttons == 1) {
$config.translatex += e.movementX;
$config.translatey += e.movementY;
}
}
function setZoom(e) {
$config.zoom += (e.deltaY > 0) ? -1 : 1;
}
</script>
<div bind:this={container} id="container">
{#if !isInitialized}
<FilePicker on:load={onLoad} />
{/if}
<span id="loadFile" class:hide={!isInitialized} title="Close and load other files" on:click={() => isInitialized = false}>🞩</span>
<div id="controls" class:hide={!isInitialized}>
<label title="Aggregates multiple (re-)visits into one fixation per word. Averages the fixation position and plays back in word order. Use to compare to fixation prediction models."><input type="checkbox" bind:checked={show_sequential}> As sequential word fixations</label>
</div>
<canvas class:hide={!isInitialized} bind:this={canvas} on:mousemove={translate} on:wheel|preventDefault={setZoom} height="1080" width="1920">This browser does not support canvas animations, which are required to render the visualization.</canvas>
<div id="progress" bind:this={progress}></div>
</div>
<style>
canvas {
margin: auto;
}
label {
font-weight: normal;
}
#loadFile {
position: absolute;
top: 0;
right: 0;
cursor: pointer;
margin: 10px;
}
#container {
position: relative;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
#progress {
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 20px;
background: #9b4dca;
}
#controls {
position: absolute;
right: 0;
bottom: 0;
text-align: right;
background: rgba(255,255,255,0.5);
padding: 10px;
}
.hide {
display: none;
}
</style>

40
src/helpers.js Normal file
View file

@ -0,0 +1,40 @@
export function readFileAsync(file) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
export function aggregateWordFixations(data) {
//slicing off first fixation since it is the calibration in center
let sorted = data.filter( item => item.word_id ).slice(1).sort((a,b) => a.word_id-b.word_id);
//add first back in
sorted.unshift(data[0]);
//aggregate fixations for same words in bags
let aggregate = sorted.reduce( (acc, val) => {
if (acc[0].length == 0 || val.word_id == acc[acc.length-1][0].word_id) {
acc[acc.length-1].push(val)
} else {
acc.push([val]);
}
return acc;
}, [[]]);
//average fixation coordinates and sum duration for each bag
return aggregate.map( bag => {
let word = bag[0].word;
let word_id = bag[0].word_id;
let x=0;
let y=0;
let dur=0;
for (let fixation of bag) {
x += fixation.x/bag.length;
y += fixation.y/bag.length;
dur += fixation.dur;
}
return {x, y, dur, word_id, word};
});
}

9
src/main.js Normal file
View file

@ -0,0 +1,9 @@
import App from './App.svelte';
const app = new App({
target: document.body,
props: {
}
});
export default app;

41
src/stores.js Normal file
View file

@ -0,0 +1,41 @@
import { writable } from 'svelte/store';
export const config = writable({
zoom: 100,
translatex: 0,
translatey: 0,
duration_multiplier: 0.1,
duration_exponent: 0.2,
speed: 100,
show_sequential: false,
trace_length: 3,
trace_radius: 5,
trace_width: 2,
canvas_width: 1920,
canvas_height: 1080
});
// export const time = readable(new Date(), function start(set) {
// const interval = setInterval(() => {
// set(new Date());
// }, 1000);
// return function stop() {
// clearInterval(interval);
// };
// });
// function tickGenerator() {
// const { subscribe, set, update } = writable(0);
// let interval;
// return {
// subscribe,
// start: () => setInterval(),
// stop: () => update(n => n - 1),
// reset: () => set(0)
// };
// }
//export const count = createCount();

11
src/vendor/milligram.min.css vendored Normal file

File diff suppressed because one or more lines are too long

349
src/vendor/normalize.css vendored Normal file
View file

@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
</