-
+
Toggle Sidebar
-
-
-
+
@@ -264,21 +279,66 @@ limitations under the License.
-
Document Outline
+
+ Attachments
+
-
diff --git a/static/pdf.js/cmaps/78-EUC-H.bcmap b/static/pdf.js/cmaps/78-EUC-H.bcmap
new file mode 100644
index 000000000..2655fc70a
Binary files /dev/null and b/static/pdf.js/cmaps/78-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/78-EUC-V.bcmap b/static/pdf.js/cmaps/78-EUC-V.bcmap
new file mode 100644
index 000000000..f1ed85382
Binary files /dev/null and b/static/pdf.js/cmaps/78-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/78-H.bcmap b/static/pdf.js/cmaps/78-H.bcmap
new file mode 100644
index 000000000..39e89d333
Binary files /dev/null and b/static/pdf.js/cmaps/78-H.bcmap differ
diff --git a/static/pdf.js/cmaps/78-RKSJ-H.bcmap b/static/pdf.js/cmaps/78-RKSJ-H.bcmap
new file mode 100644
index 000000000..e4167cb51
Binary files /dev/null and b/static/pdf.js/cmaps/78-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/78-RKSJ-V.bcmap b/static/pdf.js/cmaps/78-RKSJ-V.bcmap
new file mode 100644
index 000000000..50b1646e9
Binary files /dev/null and b/static/pdf.js/cmaps/78-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/78-V.bcmap b/static/pdf.js/cmaps/78-V.bcmap
new file mode 100644
index 000000000..d7af99b5e
Binary files /dev/null and b/static/pdf.js/cmaps/78-V.bcmap differ
diff --git a/static/pdf.js/cmaps/78ms-RKSJ-H.bcmap b/static/pdf.js/cmaps/78ms-RKSJ-H.bcmap
new file mode 100644
index 000000000..37077d01e
Binary files /dev/null and b/static/pdf.js/cmaps/78ms-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/78ms-RKSJ-V.bcmap b/static/pdf.js/cmaps/78ms-RKSJ-V.bcmap
new file mode 100644
index 000000000..acf23231a
Binary files /dev/null and b/static/pdf.js/cmaps/78ms-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/83pv-RKSJ-H.bcmap b/static/pdf.js/cmaps/83pv-RKSJ-H.bcmap
new file mode 100644
index 000000000..2359bc529
Binary files /dev/null and b/static/pdf.js/cmaps/83pv-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/90ms-RKSJ-H.bcmap b/static/pdf.js/cmaps/90ms-RKSJ-H.bcmap
new file mode 100644
index 000000000..af8293829
Binary files /dev/null and b/static/pdf.js/cmaps/90ms-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/90ms-RKSJ-V.bcmap b/static/pdf.js/cmaps/90ms-RKSJ-V.bcmap
new file mode 100644
index 000000000..780549de1
Binary files /dev/null and b/static/pdf.js/cmaps/90ms-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/90msp-RKSJ-H.bcmap b/static/pdf.js/cmaps/90msp-RKSJ-H.bcmap
new file mode 100644
index 000000000..bfd3119c6
Binary files /dev/null and b/static/pdf.js/cmaps/90msp-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/90msp-RKSJ-V.bcmap b/static/pdf.js/cmaps/90msp-RKSJ-V.bcmap
new file mode 100644
index 000000000..25ef14ab4
Binary files /dev/null and b/static/pdf.js/cmaps/90msp-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/90pv-RKSJ-H.bcmap b/static/pdf.js/cmaps/90pv-RKSJ-H.bcmap
new file mode 100644
index 000000000..02f713bb8
Binary files /dev/null and b/static/pdf.js/cmaps/90pv-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/90pv-RKSJ-V.bcmap b/static/pdf.js/cmaps/90pv-RKSJ-V.bcmap
new file mode 100644
index 000000000..d08e0cc5d
Binary files /dev/null and b/static/pdf.js/cmaps/90pv-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Add-H.bcmap b/static/pdf.js/cmaps/Add-H.bcmap
new file mode 100644
index 000000000..59442acaf
Binary files /dev/null and b/static/pdf.js/cmaps/Add-H.bcmap differ
diff --git a/static/pdf.js/cmaps/Add-RKSJ-H.bcmap b/static/pdf.js/cmaps/Add-RKSJ-H.bcmap
new file mode 100644
index 000000000..a3065e441
Binary files /dev/null and b/static/pdf.js/cmaps/Add-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/Add-RKSJ-V.bcmap b/static/pdf.js/cmaps/Add-RKSJ-V.bcmap
new file mode 100644
index 000000000..040014cfc
Binary files /dev/null and b/static/pdf.js/cmaps/Add-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Add-V.bcmap b/static/pdf.js/cmaps/Add-V.bcmap
new file mode 100644
index 000000000..2f816d320
Binary files /dev/null and b/static/pdf.js/cmaps/Add-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-0.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-0.bcmap
new file mode 100644
index 000000000..88ec04af4
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-0.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-1.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-1.bcmap
new file mode 100644
index 000000000..03a501477
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-1.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-2.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-2.bcmap
new file mode 100644
index 000000000..2aa95141f
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-3.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-3.bcmap
new file mode 100644
index 000000000..86d8b8c79
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-3.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-4.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-4.bcmap
new file mode 100644
index 000000000..f50fc6c14
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-4.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-5.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-5.bcmap
new file mode 100644
index 000000000..6caf4a831
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-5.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-6.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-6.bcmap
new file mode 100644
index 000000000..b77fb0705
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-6.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-CNS1-UCS2.bcmap b/static/pdf.js/cmaps/Adobe-CNS1-UCS2.bcmap
new file mode 100644
index 000000000..69d79a2c2
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-CNS1-UCS2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-0.bcmap b/static/pdf.js/cmaps/Adobe-GB1-0.bcmap
new file mode 100644
index 000000000..36101083f
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-0.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-1.bcmap b/static/pdf.js/cmaps/Adobe-GB1-1.bcmap
new file mode 100644
index 000000000..707bb1065
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-1.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-2.bcmap b/static/pdf.js/cmaps/Adobe-GB1-2.bcmap
new file mode 100644
index 000000000..f7648cc3f
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-3.bcmap b/static/pdf.js/cmaps/Adobe-GB1-3.bcmap
new file mode 100644
index 000000000..852145890
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-3.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-4.bcmap b/static/pdf.js/cmaps/Adobe-GB1-4.bcmap
new file mode 100644
index 000000000..e40c63ab1
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-4.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-5.bcmap b/static/pdf.js/cmaps/Adobe-GB1-5.bcmap
new file mode 100644
index 000000000..d7623b500
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-5.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-GB1-UCS2.bcmap b/static/pdf.js/cmaps/Adobe-GB1-UCS2.bcmap
new file mode 100644
index 000000000..758652593
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-GB1-UCS2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-0.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-0.bcmap
new file mode 100644
index 000000000..f0e94ec19
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-0.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-1.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-1.bcmap
new file mode 100644
index 000000000..dad42c5ad
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-1.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-2.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-2.bcmap
new file mode 100644
index 000000000..090819a06
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-3.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-3.bcmap
new file mode 100644
index 000000000..087dfc155
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-3.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-4.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-4.bcmap
new file mode 100644
index 000000000..46aa9bffe
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-4.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-5.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-5.bcmap
new file mode 100644
index 000000000..5b4b65cc6
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-5.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-6.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-6.bcmap
new file mode 100644
index 000000000..e77d699ab
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-6.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Japan1-UCS2.bcmap b/static/pdf.js/cmaps/Adobe-Japan1-UCS2.bcmap
new file mode 100644
index 000000000..128a14107
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Japan1-UCS2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Korea1-0.bcmap b/static/pdf.js/cmaps/Adobe-Korea1-0.bcmap
new file mode 100644
index 000000000..cef1a9985
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Korea1-0.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Korea1-1.bcmap b/static/pdf.js/cmaps/Adobe-Korea1-1.bcmap
new file mode 100644
index 000000000..11ffa36df
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Korea1-1.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Korea1-2.bcmap b/static/pdf.js/cmaps/Adobe-Korea1-2.bcmap
new file mode 100644
index 000000000..3172308c7
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Korea1-2.bcmap differ
diff --git a/static/pdf.js/cmaps/Adobe-Korea1-UCS2.bcmap b/static/pdf.js/cmaps/Adobe-Korea1-UCS2.bcmap
new file mode 100644
index 000000000..f3371c0cb
Binary files /dev/null and b/static/pdf.js/cmaps/Adobe-Korea1-UCS2.bcmap differ
diff --git a/static/pdf.js/cmaps/B5-H.bcmap b/static/pdf.js/cmaps/B5-H.bcmap
new file mode 100644
index 000000000..beb4d2281
Binary files /dev/null and b/static/pdf.js/cmaps/B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/B5-V.bcmap b/static/pdf.js/cmaps/B5-V.bcmap
new file mode 100644
index 000000000..2d4f87d50
Binary files /dev/null and b/static/pdf.js/cmaps/B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/B5pc-H.bcmap b/static/pdf.js/cmaps/B5pc-H.bcmap
new file mode 100644
index 000000000..ce0013167
Binary files /dev/null and b/static/pdf.js/cmaps/B5pc-H.bcmap differ
diff --git a/static/pdf.js/cmaps/B5pc-V.bcmap b/static/pdf.js/cmaps/B5pc-V.bcmap
new file mode 100644
index 000000000..73b99ff2f
Binary files /dev/null and b/static/pdf.js/cmaps/B5pc-V.bcmap differ
diff --git a/static/pdf.js/cmaps/CNS-EUC-H.bcmap b/static/pdf.js/cmaps/CNS-EUC-H.bcmap
new file mode 100644
index 000000000..61d1d0cb0
Binary files /dev/null and b/static/pdf.js/cmaps/CNS-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/CNS-EUC-V.bcmap b/static/pdf.js/cmaps/CNS-EUC-V.bcmap
new file mode 100644
index 000000000..1a393a51e
Binary files /dev/null and b/static/pdf.js/cmaps/CNS-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/CNS1-H.bcmap b/static/pdf.js/cmaps/CNS1-H.bcmap
new file mode 100644
index 000000000..f738e218a
Binary files /dev/null and b/static/pdf.js/cmaps/CNS1-H.bcmap differ
diff --git a/static/pdf.js/cmaps/CNS1-V.bcmap b/static/pdf.js/cmaps/CNS1-V.bcmap
new file mode 100644
index 000000000..9c3169f0d
Binary files /dev/null and b/static/pdf.js/cmaps/CNS1-V.bcmap differ
diff --git a/static/pdf.js/cmaps/CNS2-H.bcmap b/static/pdf.js/cmaps/CNS2-H.bcmap
new file mode 100644
index 000000000..c89b3527f
Binary files /dev/null and b/static/pdf.js/cmaps/CNS2-H.bcmap differ
diff --git a/static/pdf.js/cmaps/CNS2-V.bcmap b/static/pdf.js/cmaps/CNS2-V.bcmap
new file mode 100644
index 000000000..7588cec83
--- /dev/null
+++ b/static/pdf.js/cmaps/CNS2-V.bcmap
@@ -0,0 +1,3 @@
+àRCopyright 1990-2009 Adobe Systems Incorporated.
+All rights reserved.
+See ./LICENSEáCNS2-H
\ No newline at end of file
diff --git a/static/pdf.js/cmaps/ETHK-B5-H.bcmap b/static/pdf.js/cmaps/ETHK-B5-H.bcmap
new file mode 100644
index 000000000..cb29415de
Binary files /dev/null and b/static/pdf.js/cmaps/ETHK-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/ETHK-B5-V.bcmap b/static/pdf.js/cmaps/ETHK-B5-V.bcmap
new file mode 100644
index 000000000..f09aec631
Binary files /dev/null and b/static/pdf.js/cmaps/ETHK-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/ETen-B5-H.bcmap b/static/pdf.js/cmaps/ETen-B5-H.bcmap
new file mode 100644
index 000000000..c2d77462d
Binary files /dev/null and b/static/pdf.js/cmaps/ETen-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/ETen-B5-V.bcmap b/static/pdf.js/cmaps/ETen-B5-V.bcmap
new file mode 100644
index 000000000..89bff159e
Binary files /dev/null and b/static/pdf.js/cmaps/ETen-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/ETenms-B5-H.bcmap b/static/pdf.js/cmaps/ETenms-B5-H.bcmap
new file mode 100644
index 000000000..a7d69db5e
--- /dev/null
+++ b/static/pdf.js/cmaps/ETenms-B5-H.bcmap
@@ -0,0 +1,3 @@
+àRCopyright 1990-2009 Adobe Systems Incorporated.
+All rights reserved.
+See ./LICENSEá ETen-B5-H` ^
\ No newline at end of file
diff --git a/static/pdf.js/cmaps/ETenms-B5-V.bcmap b/static/pdf.js/cmaps/ETenms-B5-V.bcmap
new file mode 100644
index 000000000..adc5d618d
Binary files /dev/null and b/static/pdf.js/cmaps/ETenms-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/EUC-H.bcmap b/static/pdf.js/cmaps/EUC-H.bcmap
new file mode 100644
index 000000000..e92ea5b3b
Binary files /dev/null and b/static/pdf.js/cmaps/EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/EUC-V.bcmap b/static/pdf.js/cmaps/EUC-V.bcmap
new file mode 100644
index 000000000..7a7c18322
Binary files /dev/null and b/static/pdf.js/cmaps/EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Ext-H.bcmap b/static/pdf.js/cmaps/Ext-H.bcmap
new file mode 100644
index 000000000..3b5cde44d
Binary files /dev/null and b/static/pdf.js/cmaps/Ext-H.bcmap differ
diff --git a/static/pdf.js/cmaps/Ext-RKSJ-H.bcmap b/static/pdf.js/cmaps/Ext-RKSJ-H.bcmap
new file mode 100644
index 000000000..ea4d2d97b
Binary files /dev/null and b/static/pdf.js/cmaps/Ext-RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/Ext-RKSJ-V.bcmap b/static/pdf.js/cmaps/Ext-RKSJ-V.bcmap
new file mode 100644
index 000000000..3457c2770
Binary files /dev/null and b/static/pdf.js/cmaps/Ext-RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Ext-V.bcmap b/static/pdf.js/cmaps/Ext-V.bcmap
new file mode 100644
index 000000000..4999ca404
Binary files /dev/null and b/static/pdf.js/cmaps/Ext-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GB-EUC-H.bcmap b/static/pdf.js/cmaps/GB-EUC-H.bcmap
new file mode 100644
index 000000000..e39908b98
Binary files /dev/null and b/static/pdf.js/cmaps/GB-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GB-EUC-V.bcmap b/static/pdf.js/cmaps/GB-EUC-V.bcmap
new file mode 100644
index 000000000..d5be5446a
Binary files /dev/null and b/static/pdf.js/cmaps/GB-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GB-H.bcmap b/static/pdf.js/cmaps/GB-H.bcmap
new file mode 100644
index 000000000..39189c54e
--- /dev/null
+++ b/static/pdf.js/cmaps/GB-H.bcmap
@@ -0,0 +1,4 @@
+àRCopyright 1990-2009 Adobe Systems Incorporated.
+All rights reserved.
+See ./LICENSE!!º]aX!!]`21> pz$]‚"R‚d-Uƒ7*„
4„%+ „Z „{/…%…<9K…b1]†."‡‰`]‡,"]ˆ
+"]ˆh"]‰F"]Š$"]‹"]‹`"]Œ>"]"]z"]ŽX"]6"]"]r"]‘P"]’."]“"]“j"]”H"]•&"]–"]–b"]—@"]˜"]˜|"]™Z"]š8"]›"]›t"]œR"]0"]ž"]žl"]ŸJ"] ("]¡"]¡d"]¢B"]£ "X£~']¤W"]¥5"]¦"]¦q"]§O"]¨-"]©"]©i"]ªG"]«%"]¬"]¬a"]?"]®"]®{"]¯Y"]°7"]±"]±s"]²Q"]³/"]´
"]´k"]µI"]¶'"]·"]·c"]¸A"]¹"]¹}"]º["]»9
\ No newline at end of file
diff --git a/static/pdf.js/cmaps/GB-V.bcmap b/static/pdf.js/cmaps/GB-V.bcmap
new file mode 100644
index 000000000..310834512
Binary files /dev/null and b/static/pdf.js/cmaps/GB-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBK-EUC-H.bcmap b/static/pdf.js/cmaps/GBK-EUC-H.bcmap
new file mode 100644
index 000000000..05fff7e82
Binary files /dev/null and b/static/pdf.js/cmaps/GBK-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBK-EUC-V.bcmap b/static/pdf.js/cmaps/GBK-EUC-V.bcmap
new file mode 100644
index 000000000..0cdf6bed6
Binary files /dev/null and b/static/pdf.js/cmaps/GBK-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBK2K-H.bcmap b/static/pdf.js/cmaps/GBK2K-H.bcmap
new file mode 100644
index 000000000..46f6ba596
Binary files /dev/null and b/static/pdf.js/cmaps/GBK2K-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBK2K-V.bcmap b/static/pdf.js/cmaps/GBK2K-V.bcmap
new file mode 100644
index 000000000..d9a947984
Binary files /dev/null and b/static/pdf.js/cmaps/GBK2K-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBKp-EUC-H.bcmap b/static/pdf.js/cmaps/GBKp-EUC-H.bcmap
new file mode 100644
index 000000000..5cb0af687
Binary files /dev/null and b/static/pdf.js/cmaps/GBKp-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBKp-EUC-V.bcmap b/static/pdf.js/cmaps/GBKp-EUC-V.bcmap
new file mode 100644
index 000000000..bca93b8ef
Binary files /dev/null and b/static/pdf.js/cmaps/GBKp-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBT-EUC-H.bcmap b/static/pdf.js/cmaps/GBT-EUC-H.bcmap
new file mode 100644
index 000000000..4b4e2d322
Binary files /dev/null and b/static/pdf.js/cmaps/GBT-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBT-EUC-V.bcmap b/static/pdf.js/cmaps/GBT-EUC-V.bcmap
new file mode 100644
index 000000000..38f706699
Binary files /dev/null and b/static/pdf.js/cmaps/GBT-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBT-H.bcmap b/static/pdf.js/cmaps/GBT-H.bcmap
new file mode 100644
index 000000000..8437ac337
Binary files /dev/null and b/static/pdf.js/cmaps/GBT-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBT-V.bcmap b/static/pdf.js/cmaps/GBT-V.bcmap
new file mode 100644
index 000000000..697ab4a8e
Binary files /dev/null and b/static/pdf.js/cmaps/GBT-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBTpc-EUC-H.bcmap b/static/pdf.js/cmaps/GBTpc-EUC-H.bcmap
new file mode 100644
index 000000000..f6e50e893
Binary files /dev/null and b/static/pdf.js/cmaps/GBTpc-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBTpc-EUC-V.bcmap b/static/pdf.js/cmaps/GBTpc-EUC-V.bcmap
new file mode 100644
index 000000000..6c0d71a2d
Binary files /dev/null and b/static/pdf.js/cmaps/GBTpc-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/GBpc-EUC-H.bcmap b/static/pdf.js/cmaps/GBpc-EUC-H.bcmap
new file mode 100644
index 000000000..c9edf67cf
Binary files /dev/null and b/static/pdf.js/cmaps/GBpc-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/GBpc-EUC-V.bcmap b/static/pdf.js/cmaps/GBpc-EUC-V.bcmap
new file mode 100644
index 000000000..31450c97f
Binary files /dev/null and b/static/pdf.js/cmaps/GBpc-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/H.bcmap b/static/pdf.js/cmaps/H.bcmap
new file mode 100644
index 000000000..7b24ea462
Binary files /dev/null and b/static/pdf.js/cmaps/H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKdla-B5-H.bcmap b/static/pdf.js/cmaps/HKdla-B5-H.bcmap
new file mode 100644
index 000000000..7d30c0500
Binary files /dev/null and b/static/pdf.js/cmaps/HKdla-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKdla-B5-V.bcmap b/static/pdf.js/cmaps/HKdla-B5-V.bcmap
new file mode 100644
index 000000000..78946940d
Binary files /dev/null and b/static/pdf.js/cmaps/HKdla-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/HKdlb-B5-H.bcmap b/static/pdf.js/cmaps/HKdlb-B5-H.bcmap
new file mode 100644
index 000000000..d829a2310
Binary files /dev/null and b/static/pdf.js/cmaps/HKdlb-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKdlb-B5-V.bcmap b/static/pdf.js/cmaps/HKdlb-B5-V.bcmap
new file mode 100644
index 000000000..2b572b50a
Binary files /dev/null and b/static/pdf.js/cmaps/HKdlb-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/HKgccs-B5-H.bcmap b/static/pdf.js/cmaps/HKgccs-B5-H.bcmap
new file mode 100644
index 000000000..971a4f23f
Binary files /dev/null and b/static/pdf.js/cmaps/HKgccs-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKgccs-B5-V.bcmap b/static/pdf.js/cmaps/HKgccs-B5-V.bcmap
new file mode 100644
index 000000000..d353ca256
Binary files /dev/null and b/static/pdf.js/cmaps/HKgccs-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/HKm314-B5-H.bcmap b/static/pdf.js/cmaps/HKm314-B5-H.bcmap
new file mode 100644
index 000000000..576dc0111
Binary files /dev/null and b/static/pdf.js/cmaps/HKm314-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKm314-B5-V.bcmap b/static/pdf.js/cmaps/HKm314-B5-V.bcmap
new file mode 100644
index 000000000..0e96d0e22
Binary files /dev/null and b/static/pdf.js/cmaps/HKm314-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/HKm471-B5-H.bcmap b/static/pdf.js/cmaps/HKm471-B5-H.bcmap
new file mode 100644
index 000000000..11d170c75
Binary files /dev/null and b/static/pdf.js/cmaps/HKm471-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKm471-B5-V.bcmap b/static/pdf.js/cmaps/HKm471-B5-V.bcmap
new file mode 100644
index 000000000..54959bf9e
Binary files /dev/null and b/static/pdf.js/cmaps/HKm471-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/HKscs-B5-H.bcmap b/static/pdf.js/cmaps/HKscs-B5-H.bcmap
new file mode 100644
index 000000000..6ef7857ad
Binary files /dev/null and b/static/pdf.js/cmaps/HKscs-B5-H.bcmap differ
diff --git a/static/pdf.js/cmaps/HKscs-B5-V.bcmap b/static/pdf.js/cmaps/HKscs-B5-V.bcmap
new file mode 100644
index 000000000..1fb2fa2a2
Binary files /dev/null and b/static/pdf.js/cmaps/HKscs-B5-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Hankaku.bcmap b/static/pdf.js/cmaps/Hankaku.bcmap
new file mode 100644
index 000000000..4b8ec7fce
Binary files /dev/null and b/static/pdf.js/cmaps/Hankaku.bcmap differ
diff --git a/static/pdf.js/cmaps/Hiragana.bcmap b/static/pdf.js/cmaps/Hiragana.bcmap
new file mode 100644
index 000000000..17e983e77
Binary files /dev/null and b/static/pdf.js/cmaps/Hiragana.bcmap differ
diff --git a/static/pdf.js/cmaps/KSC-EUC-H.bcmap b/static/pdf.js/cmaps/KSC-EUC-H.bcmap
new file mode 100644
index 000000000..a45c65f00
Binary files /dev/null and b/static/pdf.js/cmaps/KSC-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/KSC-EUC-V.bcmap b/static/pdf.js/cmaps/KSC-EUC-V.bcmap
new file mode 100644
index 000000000..0e7b21f0a
Binary files /dev/null and b/static/pdf.js/cmaps/KSC-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/KSC-H.bcmap b/static/pdf.js/cmaps/KSC-H.bcmap
new file mode 100644
index 000000000..b9b22b678
Binary files /dev/null and b/static/pdf.js/cmaps/KSC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/KSC-Johab-H.bcmap b/static/pdf.js/cmaps/KSC-Johab-H.bcmap
new file mode 100644
index 000000000..2531ffcf4
Binary files /dev/null and b/static/pdf.js/cmaps/KSC-Johab-H.bcmap differ
diff --git a/static/pdf.js/cmaps/KSC-Johab-V.bcmap b/static/pdf.js/cmaps/KSC-Johab-V.bcmap
new file mode 100644
index 000000000..367ceb226
Binary files /dev/null and b/static/pdf.js/cmaps/KSC-Johab-V.bcmap differ
diff --git a/static/pdf.js/cmaps/KSC-V.bcmap b/static/pdf.js/cmaps/KSC-V.bcmap
new file mode 100644
index 000000000..6ae2f0b6b
Binary files /dev/null and b/static/pdf.js/cmaps/KSC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/KSCms-UHC-H.bcmap b/static/pdf.js/cmaps/KSCms-UHC-H.bcmap
new file mode 100644
index 000000000..a8d4240e6
Binary files /dev/null and b/static/pdf.js/cmaps/KSCms-UHC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/KSCms-UHC-HW-H.bcmap b/static/pdf.js/cmaps/KSCms-UHC-HW-H.bcmap
new file mode 100644
index 000000000..8b4ae18fd
Binary files /dev/null and b/static/pdf.js/cmaps/KSCms-UHC-HW-H.bcmap differ
diff --git a/static/pdf.js/cmaps/KSCms-UHC-HW-V.bcmap b/static/pdf.js/cmaps/KSCms-UHC-HW-V.bcmap
new file mode 100644
index 000000000..b655dbcfb
Binary files /dev/null and b/static/pdf.js/cmaps/KSCms-UHC-HW-V.bcmap differ
diff --git a/static/pdf.js/cmaps/KSCms-UHC-V.bcmap b/static/pdf.js/cmaps/KSCms-UHC-V.bcmap
new file mode 100644
index 000000000..21f97f65b
Binary files /dev/null and b/static/pdf.js/cmaps/KSCms-UHC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/KSCpc-EUC-H.bcmap b/static/pdf.js/cmaps/KSCpc-EUC-H.bcmap
new file mode 100644
index 000000000..e06f361eb
Binary files /dev/null and b/static/pdf.js/cmaps/KSCpc-EUC-H.bcmap differ
diff --git a/static/pdf.js/cmaps/KSCpc-EUC-V.bcmap b/static/pdf.js/cmaps/KSCpc-EUC-V.bcmap
new file mode 100644
index 000000000..f3c9113fc
Binary files /dev/null and b/static/pdf.js/cmaps/KSCpc-EUC-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Katakana.bcmap b/static/pdf.js/cmaps/Katakana.bcmap
new file mode 100644
index 000000000..524303c4f
Binary files /dev/null and b/static/pdf.js/cmaps/Katakana.bcmap differ
diff --git a/static/pdf.js/cmaps/LICENSE b/static/pdf.js/cmaps/LICENSE
new file mode 100644
index 000000000..b1ad168ad
--- /dev/null
+++ b/static/pdf.js/cmaps/LICENSE
@@ -0,0 +1,36 @@
+%%Copyright: -----------------------------------------------------------
+%%Copyright: Copyright 1990-2009 Adobe Systems Incorporated.
+%%Copyright: All rights reserved.
+%%Copyright:
+%%Copyright: Redistribution and use in source and binary forms, with or
+%%Copyright: without modification, are permitted provided that the
+%%Copyright: following conditions are met:
+%%Copyright:
+%%Copyright: Redistributions of source code must retain the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer.
+%%Copyright:
+%%Copyright: Redistributions in binary form must reproduce the above
+%%Copyright: copyright notice, this list of conditions and the following
+%%Copyright: disclaimer in the documentation and/or other materials
+%%Copyright: provided with the distribution.
+%%Copyright:
+%%Copyright: Neither the name of Adobe Systems Incorporated nor the names
+%%Copyright: of its contributors may be used to endorse or promote
+%%Copyright: products derived from this software without specific prior
+%%Copyright: written permission.
+%%Copyright:
+%%Copyright: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+%%Copyright: CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+%%Copyright: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+%%Copyright: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+%%Copyright: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+%%Copyright: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+%%Copyright: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+%%Copyright: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+%%Copyright: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+%%Copyright: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+%%Copyright: CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+%%Copyright: OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+%%Copyright: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+%%Copyright: -----------------------------------------------------------
diff --git a/static/pdf.js/cmaps/NWP-H.bcmap b/static/pdf.js/cmaps/NWP-H.bcmap
new file mode 100644
index 000000000..afc5e4b05
Binary files /dev/null and b/static/pdf.js/cmaps/NWP-H.bcmap differ
diff --git a/static/pdf.js/cmaps/NWP-V.bcmap b/static/pdf.js/cmaps/NWP-V.bcmap
new file mode 100644
index 000000000..bb5785e32
Binary files /dev/null and b/static/pdf.js/cmaps/NWP-V.bcmap differ
diff --git a/static/pdf.js/cmaps/RKSJ-H.bcmap b/static/pdf.js/cmaps/RKSJ-H.bcmap
new file mode 100644
index 000000000..fb8d298e9
Binary files /dev/null and b/static/pdf.js/cmaps/RKSJ-H.bcmap differ
diff --git a/static/pdf.js/cmaps/RKSJ-V.bcmap b/static/pdf.js/cmaps/RKSJ-V.bcmap
new file mode 100644
index 000000000..a2555a6c0
Binary files /dev/null and b/static/pdf.js/cmaps/RKSJ-V.bcmap differ
diff --git a/static/pdf.js/cmaps/Roman.bcmap b/static/pdf.js/cmaps/Roman.bcmap
new file mode 100644
index 000000000..f896dcf1c
Binary files /dev/null and b/static/pdf.js/cmaps/Roman.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UCS2-H.bcmap b/static/pdf.js/cmaps/UniCNS-UCS2-H.bcmap
new file mode 100644
index 000000000..d5db27c5c
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UCS2-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UCS2-V.bcmap b/static/pdf.js/cmaps/UniCNS-UCS2-V.bcmap
new file mode 100644
index 000000000..1dc9b7a21
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UCS2-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UTF16-H.bcmap b/static/pdf.js/cmaps/UniCNS-UTF16-H.bcmap
new file mode 100644
index 000000000..961afefb6
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UTF16-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UTF16-V.bcmap b/static/pdf.js/cmaps/UniCNS-UTF16-V.bcmap
new file mode 100644
index 000000000..df0cffe86
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UTF16-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UTF32-H.bcmap b/static/pdf.js/cmaps/UniCNS-UTF32-H.bcmap
new file mode 100644
index 000000000..1ab18a143
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UTF32-V.bcmap b/static/pdf.js/cmaps/UniCNS-UTF32-V.bcmap
new file mode 100644
index 000000000..ad14662e2
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UTF8-H.bcmap b/static/pdf.js/cmaps/UniCNS-UTF8-H.bcmap
new file mode 100644
index 000000000..83c6bd7c4
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UTF8-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniCNS-UTF8-V.bcmap b/static/pdf.js/cmaps/UniCNS-UTF8-V.bcmap
new file mode 100644
index 000000000..22a27e4dd
Binary files /dev/null and b/static/pdf.js/cmaps/UniCNS-UTF8-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UCS2-H.bcmap b/static/pdf.js/cmaps/UniGB-UCS2-H.bcmap
new file mode 100644
index 000000000..5bd6228ce
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UCS2-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UCS2-V.bcmap b/static/pdf.js/cmaps/UniGB-UCS2-V.bcmap
new file mode 100644
index 000000000..53c534b7f
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UCS2-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UTF16-H.bcmap b/static/pdf.js/cmaps/UniGB-UTF16-H.bcmap
new file mode 100644
index 000000000..b95045b40
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UTF16-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UTF16-V.bcmap b/static/pdf.js/cmaps/UniGB-UTF16-V.bcmap
new file mode 100644
index 000000000..51f023e0d
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UTF16-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UTF32-H.bcmap b/static/pdf.js/cmaps/UniGB-UTF32-H.bcmap
new file mode 100644
index 000000000..f0dbd14f3
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UTF32-V.bcmap b/static/pdf.js/cmaps/UniGB-UTF32-V.bcmap
new file mode 100644
index 000000000..ce9c30a98
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UTF8-H.bcmap b/static/pdf.js/cmaps/UniGB-UTF8-H.bcmap
new file mode 100644
index 000000000..982ca462b
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UTF8-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniGB-UTF8-V.bcmap b/static/pdf.js/cmaps/UniGB-UTF8-V.bcmap
new file mode 100644
index 000000000..f78020dd4
Binary files /dev/null and b/static/pdf.js/cmaps/UniGB-UTF8-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UCS2-H.bcmap b/static/pdf.js/cmaps/UniJIS-UCS2-H.bcmap
new file mode 100644
index 000000000..7daf56afa
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UCS2-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UCS2-HW-H.bcmap b/static/pdf.js/cmaps/UniJIS-UCS2-HW-H.bcmap
new file mode 100644
index 000000000..ac9975c58
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UCS2-HW-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UCS2-HW-V.bcmap b/static/pdf.js/cmaps/UniJIS-UCS2-HW-V.bcmap
new file mode 100644
index 000000000..3da0a1c62
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UCS2-HW-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UCS2-V.bcmap b/static/pdf.js/cmaps/UniJIS-UCS2-V.bcmap
new file mode 100644
index 000000000..c50b9ddfd
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UCS2-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UTF16-H.bcmap b/static/pdf.js/cmaps/UniJIS-UTF16-H.bcmap
new file mode 100644
index 000000000..676134463
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UTF16-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UTF16-V.bcmap b/static/pdf.js/cmaps/UniJIS-UTF16-V.bcmap
new file mode 100644
index 000000000..70bf90c0e
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UTF16-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UTF32-H.bcmap b/static/pdf.js/cmaps/UniJIS-UTF32-H.bcmap
new file mode 100644
index 000000000..7a83d53ae
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UTF32-V.bcmap b/static/pdf.js/cmaps/UniJIS-UTF32-V.bcmap
new file mode 100644
index 000000000..7a8713539
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UTF8-H.bcmap b/static/pdf.js/cmaps/UniJIS-UTF8-H.bcmap
new file mode 100644
index 000000000..9f0334cac
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UTF8-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS-UTF8-V.bcmap b/static/pdf.js/cmaps/UniJIS-UTF8-V.bcmap
new file mode 100644
index 000000000..808a94f0f
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS-UTF8-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS2004-UTF16-H.bcmap b/static/pdf.js/cmaps/UniJIS2004-UTF16-H.bcmap
new file mode 100644
index 000000000..d768bf811
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS2004-UTF16-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS2004-UTF16-V.bcmap b/static/pdf.js/cmaps/UniJIS2004-UTF16-V.bcmap
new file mode 100644
index 000000000..3d5bf6fb4
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS2004-UTF16-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS2004-UTF32-H.bcmap b/static/pdf.js/cmaps/UniJIS2004-UTF32-H.bcmap
new file mode 100644
index 000000000..09eee10d4
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS2004-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS2004-UTF32-V.bcmap b/static/pdf.js/cmaps/UniJIS2004-UTF32-V.bcmap
new file mode 100644
index 000000000..6c5460013
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS2004-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS2004-UTF8-H.bcmap b/static/pdf.js/cmaps/UniJIS2004-UTF8-H.bcmap
new file mode 100644
index 000000000..1b1a64f50
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS2004-UTF8-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJIS2004-UTF8-V.bcmap b/static/pdf.js/cmaps/UniJIS2004-UTF8-V.bcmap
new file mode 100644
index 000000000..994aa9ef9
Binary files /dev/null and b/static/pdf.js/cmaps/UniJIS2004-UTF8-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISPro-UCS2-HW-V.bcmap b/static/pdf.js/cmaps/UniJISPro-UCS2-HW-V.bcmap
new file mode 100644
index 000000000..643f921b6
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISPro-UCS2-HW-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISPro-UCS2-V.bcmap b/static/pdf.js/cmaps/UniJISPro-UCS2-V.bcmap
new file mode 100644
index 000000000..c148f67f5
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISPro-UCS2-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISPro-UTF8-V.bcmap b/static/pdf.js/cmaps/UniJISPro-UTF8-V.bcmap
new file mode 100644
index 000000000..1849d809a
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISPro-UTF8-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISX0213-UTF32-H.bcmap b/static/pdf.js/cmaps/UniJISX0213-UTF32-H.bcmap
new file mode 100644
index 000000000..a83a677c5
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISX0213-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISX0213-UTF32-V.bcmap b/static/pdf.js/cmaps/UniJISX0213-UTF32-V.bcmap
new file mode 100644
index 000000000..f527248ad
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISX0213-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISX02132004-UTF32-H.bcmap b/static/pdf.js/cmaps/UniJISX02132004-UTF32-H.bcmap
new file mode 100644
index 000000000..e1a988dc9
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISX02132004-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniJISX02132004-UTF32-V.bcmap b/static/pdf.js/cmaps/UniJISX02132004-UTF32-V.bcmap
new file mode 100644
index 000000000..47e054a96
Binary files /dev/null and b/static/pdf.js/cmaps/UniJISX02132004-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UCS2-H.bcmap b/static/pdf.js/cmaps/UniKS-UCS2-H.bcmap
new file mode 100644
index 000000000..b5b94852a
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UCS2-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UCS2-V.bcmap b/static/pdf.js/cmaps/UniKS-UCS2-V.bcmap
new file mode 100644
index 000000000..026adcaad
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UCS2-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UTF16-H.bcmap b/static/pdf.js/cmaps/UniKS-UTF16-H.bcmap
new file mode 100644
index 000000000..fd4e66e81
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UTF16-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UTF16-V.bcmap b/static/pdf.js/cmaps/UniKS-UTF16-V.bcmap
new file mode 100644
index 000000000..075efb705
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UTF16-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UTF32-H.bcmap b/static/pdf.js/cmaps/UniKS-UTF32-H.bcmap
new file mode 100644
index 000000000..769d2142c
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UTF32-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UTF32-V.bcmap b/static/pdf.js/cmaps/UniKS-UTF32-V.bcmap
new file mode 100644
index 000000000..bdab208b6
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UTF32-V.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UTF8-H.bcmap b/static/pdf.js/cmaps/UniKS-UTF8-H.bcmap
new file mode 100644
index 000000000..6ff8674af
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UTF8-H.bcmap differ
diff --git a/static/pdf.js/cmaps/UniKS-UTF8-V.bcmap b/static/pdf.js/cmaps/UniKS-UTF8-V.bcmap
new file mode 100644
index 000000000..8dfa76a58
Binary files /dev/null and b/static/pdf.js/cmaps/UniKS-UTF8-V.bcmap differ
diff --git a/static/pdf.js/cmaps/V.bcmap b/static/pdf.js/cmaps/V.bcmap
new file mode 100644
index 000000000..fdec99066
Binary files /dev/null and b/static/pdf.js/cmaps/V.bcmap differ
diff --git a/static/pdf.js/cmaps/WP-Symbol.bcmap b/static/pdf.js/cmaps/WP-Symbol.bcmap
new file mode 100644
index 000000000..46729bbf3
Binary files /dev/null and b/static/pdf.js/cmaps/WP-Symbol.bcmap differ
diff --git a/static/pdf.js/compatibility.js b/static/pdf.js/compatibility.js
index 8ca68137f..967e312a9 100644
--- a/static/pdf.js/compatibility.js
+++ b/static/pdf.js/compatibility.js
@@ -25,9 +25,10 @@ if (typeof PDFJS === 'undefined') {
}
// Checking if the typed arrays are supported
+// Support: iOS<6.0 (subarray), IE<10, Android<4.0
(function checkTypedArrayCompatibility() {
if (typeof Uint8Array !== 'undefined') {
- // some mobile versions do not support subarray (e.g. safari 5 / iOS)
+ // Support: iOS<6.0
if (typeof Uint8Array.prototype.subarray === 'undefined') {
Uint8Array.prototype.subarray = function subarray(start, end) {
return new Uint8Array(this.slice(start, end));
@@ -37,10 +38,10 @@ if (typeof PDFJS === 'undefined') {
};
}
- // some mobile version might not support Float64Array
- if (typeof Float64Array === 'undefined')
+ // Support: Android<4.1
+ if (typeof Float64Array === 'undefined') {
window.Float64Array = Float32Array;
-
+ }
return;
}
@@ -49,23 +50,26 @@ if (typeof PDFJS === 'undefined') {
}
function setArrayOffset(array, offset) {
- if (arguments.length < 2)
+ if (arguments.length < 2) {
offset = 0;
- for (var i = 0, n = array.length; i < n; ++i, ++offset)
+ }
+ for (var i = 0, n = array.length; i < n; ++i, ++offset) {
this[offset] = array[i] & 0xFF;
+ }
}
function TypedArray(arg1) {
- var result;
+ var result, i, n;
if (typeof arg1 === 'number') {
result = [];
- for (var i = 0; i < arg1; ++i)
+ for (i = 0; i < arg1; ++i) {
result[i] = 0;
+ }
} else if ('slice' in arg1) {
result = arg1.slice(0);
} else {
result = [];
- for (var i = 0, n = arg1.length; i < n; ++i) {
+ for (i = 0, n = arg1.length; i < n; ++i) {
result[i] = arg1[i];
}
}
@@ -75,13 +79,14 @@ if (typeof PDFJS === 'undefined') {
result.byteLength = result.length;
result.set = setArrayOffset;
- if (typeof arg1 === 'object' && arg1.buffer)
+ if (typeof arg1 === 'object' && arg1.buffer) {
result.buffer = arg1.buffer;
-
+ }
return result;
}
window.Uint8Array = TypedArray;
+ window.Int8Array = TypedArray;
// we don't need support for set, byteLength for 32-bit array
// so we can use the TypedArray as well
@@ -93,25 +98,15 @@ if (typeof PDFJS === 'undefined') {
})();
// URL = URL || webkitURL
+// Support: Safari<7, Android 4.2+
(function normalizeURLObject() {
if (!window.URL) {
window.URL = window.webkitURL;
}
})();
-// Object.create() ?
-(function checkObjectCreateCompatibility() {
- if (typeof Object.create !== 'undefined')
- return;
-
- Object.create = function objectCreate(proto) {
- function Constructor() {}
- Constructor.prototype = proto;
- return new Constructor();
- };
-})();
-
-// Object.defineProperty() ?
+// Object.defineProperty()?
+// Support: Android<4.0, Safari<5.1
(function checkObjectDefinePropertyCompatibility() {
if (typeof Object.defineProperty !== 'undefined') {
var definePropertyPossible = true;
@@ -127,15 +122,19 @@ if (typeof PDFJS === 'undefined') {
} catch (e) {
definePropertyPossible = false;
}
- if (definePropertyPossible) return;
+ if (definePropertyPossible) {
+ return;
+ }
}
Object.defineProperty = function objectDefineProperty(obj, name, def) {
delete obj[name];
- if ('get' in def)
+ if ('get' in def) {
obj.__defineGetter__(name, def['get']);
- if ('set' in def)
+ }
+ if ('set' in def) {
obj.__defineSetter__(name, def['set']);
+ }
if ('value' in def) {
obj.__defineSetter__(name, function objectDefinePropertySetter(value) {
this.__defineGetter__(name, function objectDefinePropertyGetter() {
@@ -148,105 +147,77 @@ if (typeof PDFJS === 'undefined') {
};
})();
-// Object.keys() ?
-(function checkObjectKeysCompatibility() {
- if (typeof Object.keys !== 'undefined')
- return;
- Object.keys = function objectKeys(obj) {
- var result = [];
- for (var i in obj) {
- if (obj.hasOwnProperty(i))
- result.push(i);
- }
- return result;
- };
-})();
-
-// No readAsArrayBuffer ?
-(function checkFileReaderReadAsArrayBuffer() {
- if (typeof FileReader === 'undefined')
- return; // FileReader is not implemented
- var frPrototype = FileReader.prototype;
- // Older versions of Firefox might not have readAsArrayBuffer
- if ('readAsArrayBuffer' in frPrototype)
- return; // readAsArrayBuffer is implemented
- Object.defineProperty(frPrototype, 'readAsArrayBuffer', {
- value: function fileReaderReadAsArrayBuffer(blob) {
- var fileReader = new FileReader();
- var originalReader = this;
- fileReader.onload = function fileReaderOnload(evt) {
- var data = evt.target.result;
- var buffer = new ArrayBuffer(data.length);
- var uint8Array = new Uint8Array(buffer);
-
- for (var i = 0, ii = data.length; i < ii; i++)
- uint8Array[i] = data.charCodeAt(i);
-
- Object.defineProperty(originalReader, 'result', {
- value: buffer,
- enumerable: true,
- writable: false,
- configurable: true
- });
-
- var event = document.createEvent('HTMLEvents');
- event.initEvent('load', false, false);
- originalReader.dispatchEvent(event);
- };
- fileReader.readAsBinaryString(blob);
- }
- });
-})();
-
-// No XMLHttpRequest.response ?
+// No XMLHttpRequest#response?
+// Support: IE<11, Android <4.0
(function checkXMLHttpRequestResponseCompatibility() {
var xhrPrototype = XMLHttpRequest.prototype;
- if (!('overrideMimeType' in xhrPrototype)) {
+ var xhr = new XMLHttpRequest();
+ if (!('overrideMimeType' in xhr)) {
// IE10 might have response, but not overrideMimeType
+ // Support: IE10
Object.defineProperty(xhrPrototype, 'overrideMimeType', {
value: function xmlHttpRequestOverrideMimeType(mimeType) {}
});
}
- if ('response' in xhrPrototype ||
- 'mozResponseArrayBuffer' in xhrPrototype ||
- 'mozResponse' in xhrPrototype ||
- 'responseArrayBuffer' in xhrPrototype)
+ if ('responseType' in xhr) {
return;
- // IE9 ?
+ }
+
+ // The worker will be using XHR, so we can save time and disable worker.
+ PDFJS.disableWorker = true;
+
+ Object.defineProperty(xhrPrototype, 'responseType', {
+ get: function xmlHttpRequestGetResponseType() {
+ return this._responseType || 'text';
+ },
+ set: function xmlHttpRequestSetResponseType(value) {
+ if (value === 'text' || value === 'arraybuffer') {
+ this._responseType = value;
+ if (value === 'arraybuffer' &&
+ typeof this.overrideMimeType === 'function') {
+ this.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+ }
+ }
+ });
+
+ // Support: IE9
if (typeof VBArray !== 'undefined') {
Object.defineProperty(xhrPrototype, 'response', {
get: function xmlHttpRequestResponseGet() {
- return new Uint8Array(new VBArray(this.responseBody).toArray());
+ if (this.responseType === 'arraybuffer') {
+ return new Uint8Array(new VBArray(this.responseBody).toArray());
+ } else {
+ return this.responseText;
+ }
}
});
return;
}
- // other browsers
- function responseTypeSetter() {
- // will be only called to set "arraybuffer"
- this.overrideMimeType('text/plain; charset=x-user-defined');
- }
- if (typeof xhrPrototype.overrideMimeType === 'function') {
- Object.defineProperty(xhrPrototype, 'responseType',
- { set: responseTypeSetter });
- }
- function responseGetter() {
- var text = this.responseText;
- var i, n = text.length;
- var result = new Uint8Array(n);
- for (i = 0; i < n; ++i)
- result[i] = text.charCodeAt(i) & 0xFF;
- return result;
- }
- Object.defineProperty(xhrPrototype, 'response', { get: responseGetter });
+ Object.defineProperty(xhrPrototype, 'response', {
+ get: function xmlHttpRequestResponseGet() {
+ if (this.responseType !== 'arraybuffer') {
+ return this.responseText;
+ }
+ var text = this.responseText;
+ var i, n = text.length;
+ var result = new Uint8Array(n);
+ for (i = 0; i < n; ++i) {
+ result[i] = text.charCodeAt(i) & 0xFF;
+ }
+ return result.buffer;
+ }
+ });
})();
// window.btoa (base64 encode function) ?
+// Support: IE<10
(function checkWindowBtoaCompatibility() {
- if ('btoa' in window)
+ if ('btoa' in window) {
return;
+ }
var digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
@@ -268,17 +239,21 @@ if (typeof PDFJS === 'undefined') {
};
})();
-// window.atob (base64 encode function) ?
+// window.atob (base64 encode function)?
+// Support: IE<10
(function checkWindowAtobCompatibility() {
- if ('atob' in window)
+ if ('atob' in window) {
return;
+ }
// https://github.com/davidchambers/Base64.js
var digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
window.atob = function (input) {
input = input.replace(/=+$/, '');
- if (input.length % 4 == 1) throw new Error('bad atob input');
+ if (input.length % 4 === 1) {
+ throw new Error('bad atob input');
+ }
for (
// initialize result and counters
var bc = 0, bs, buffer, idx = 0, output = '';
@@ -298,15 +273,17 @@ if (typeof PDFJS === 'undefined') {
};
})();
-// Function.prototype.bind ?
+// Function.prototype.bind?
+// Support: Android<4.0, iOS<6.0
(function checkFunctionPrototypeBindCompatibility() {
- if (typeof Function.prototype.bind !== 'undefined')
+ if (typeof Function.prototype.bind !== 'undefined') {
return;
+ }
Function.prototype.bind = function functionPrototypeBind(obj) {
var fn = this, headArgs = Array.prototype.slice.call(arguments, 1);
var bound = function functionPrototypeBindBound() {
- var args = Array.prototype.concat.apply(headArgs, arguments);
+ var args = headArgs.concat(Array.prototype.slice.call(arguments));
return fn.apply(obj, args);
};
return bound;
@@ -314,23 +291,29 @@ if (typeof PDFJS === 'undefined') {
})();
// HTMLElement dataset property
+// Support: IE<11, Safari<5.1, Android<4.0
(function checkDatasetProperty() {
var div = document.createElement('div');
- if ('dataset' in div)
+ if ('dataset' in div) {
return; // dataset property exists
+ }
Object.defineProperty(HTMLElement.prototype, 'dataset', {
get: function() {
- if (this._dataset)
+ if (this._dataset) {
return this._dataset;
+ }
var dataset = {};
for (var j = 0, jj = this.attributes.length; j < jj; j++) {
var attribute = this.attributes[j];
- if (attribute.name.substring(0, 5) != 'data-')
+ if (attribute.name.substring(0, 5) !== 'data-') {
continue;
+ }
var key = attribute.name.substring(5).replace(/\-([a-z])/g,
- function(all, ch) { return ch.toUpperCase(); });
+ function(all, ch) {
+ return ch.toUpperCase();
+ });
dataset[key] = attribute.value;
}
@@ -346,20 +329,26 @@ if (typeof PDFJS === 'undefined') {
})();
// HTMLElement classList property
+// Support: IE<10, Android<4.0, iOS<5.0
(function checkClassListProperty() {
var div = document.createElement('div');
- if ('classList' in div)
+ if ('classList' in div) {
return; // classList property exists
+ }
function changeList(element, itemName, add, remove) {
var s = element.className || '';
var list = s.split(/\s+/g);
- if (list[0] === '') list.shift();
+ if (list[0] === '') {
+ list.shift();
+ }
var index = list.indexOf(itemName);
- if (index < 0 && add)
+ if (index < 0 && add) {
list.push(itemName);
- if (index >= 0 && remove)
+ }
+ if (index >= 0 && remove) {
list.splice(index, 1);
+ }
element.className = list.join(' ');
return (index >= 0);
}
@@ -381,8 +370,9 @@ if (typeof PDFJS === 'undefined') {
Object.defineProperty(HTMLElement.prototype, 'classList', {
get: function() {
- if (this._classList)
+ if (this._classList) {
return this._classList;
+ }
var classList = Object.create(classListPrototype, {
element: {
@@ -403,6 +393,9 @@ if (typeof PDFJS === 'undefined') {
})();
// Check console compatibility
+// In older IE versions the console object is not available
+// unless console is open.
+// Support: IE<10
(function checkConsoleCompatibility() {
if (!('console' in window)) {
window.console = {
@@ -425,6 +418,7 @@ if (typeof PDFJS === 'undefined') {
})();
// Check onclick compatibility in Opera
+// Support: Opera<15
(function checkOnClickCompatibility() {
// workaround for reported Opera bug DSK-354448:
// onclick fires on disabled buttons with opaque content
@@ -436,30 +430,44 @@ if (typeof PDFJS === 'undefined') {
function isDisabled(node) {
return node.disabled || (node.parentNode && isDisabled(node.parentNode));
}
- if (navigator.userAgent.indexOf('Opera') != -1) {
+ if (navigator.userAgent.indexOf('Opera') !== -1) {
// use browser detection since we cannot feature-check this bug
document.addEventListener('click', ignoreIfTargetDisabled, true);
}
})();
+// Checks if possible to use URL.createObjectURL()
+// Support: IE
+(function checkOnBlobSupport() {
+ // sometimes IE loosing the data created with createObjectURL(), see #3977
+ if (navigator.userAgent.indexOf('Trident') >= 0) {
+ PDFJS.disableCreateObjectURL = true;
+ }
+})();
+
// Checks if navigator.language is supported
(function checkNavigatorLanguage() {
- if ('language' in navigator)
+ if ('language' in navigator &&
+ /^[a-z]+(-[A-Z]+)?$/.test(navigator.language)) {
return;
- Object.defineProperty(navigator, 'language', {
- get: function navigatorLanguage() {
- var language = navigator.userLanguage || 'en-US';
- return language.substring(0, 2).toLowerCase() +
- language.substring(2).toUpperCase();
- },
- enumerable: true
- });
+ }
+ function formatLocale(locale) {
+ var split = locale.split(/[-_]/);
+ split[0] = split[0].toLowerCase();
+ if (split.length > 1) {
+ split[1] = split[1].toUpperCase();
+ }
+ return split.join('-');
+ }
+ var language = navigator.language || navigator.userLanguage || 'en-US';
+ PDFJS.locale = formatLocale(language);
})();
(function checkRangeRequests() {
// Safari has issues with cached range requests see:
// https://github.com/mozilla/pdf.js/issues/3260
// Last tested with version 6.0.4.
+ // Support: Safari 6.0+
var isSafari = Object.prototype.toString.call(
window.HTMLElement).indexOf('Constructor') > 0;
@@ -467,17 +475,100 @@ if (typeof PDFJS === 'undefined') {
// https://github.com/mozilla/pdf.js/issues/3381.
// Make sure that we only match webkit-based Android browsers,
// since Firefox/Fennec works as expected.
+ // Support: Android<3.0
var regex = /Android\s[0-2][^\d]/;
var isOldAndroid = regex.test(navigator.userAgent);
if (isSafari || isOldAndroid) {
PDFJS.disableRange = true;
+ PDFJS.disableStream = true;
}
})();
// Check if the browser supports manipulation of the history.
+// Support: IE<10, Android<4.2
(function checkHistoryManipulation() {
- if (!window.history.pushState) {
+ // Android 2.x has so buggy pushState support that it was removed in
+ // Android 3.0 and restored as late as in Android 4.2.
+ // Support: Android 2.x
+ if (!history.pushState || navigator.userAgent.indexOf('Android 2.') >= 0) {
PDFJS.disableHistory = true;
}
})();
+
+// Support: IE<11, Chrome<21, Android<4.4, Safari<6
+(function checkSetPresenceInImageData() {
+ // IE < 11 will use window.CanvasPixelArray which lacks set function.
+ if (window.CanvasPixelArray) {
+ if (typeof window.CanvasPixelArray.prototype.set !== 'function') {
+ window.CanvasPixelArray.prototype.set = function(arr) {
+ for (var i = 0, ii = this.length; i < ii; i++) {
+ this[i] = arr[i];
+ }
+ };
+ }
+ } else {
+ // Old Chrome and Android use an inaccessible CanvasPixelArray prototype.
+ // Because we cannot feature detect it, we rely on user agent parsing.
+ var polyfill = false, versionMatch;
+ if (navigator.userAgent.indexOf('Chrom') >= 0) {
+ versionMatch = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
+ // Chrome < 21 lacks the set function.
+ polyfill = versionMatch && parseInt(versionMatch[2]) < 21;
+ } else if (navigator.userAgent.indexOf('Android') >= 0) {
+ // Android < 4.4 lacks the set function.
+ // Android >= 4.4 will contain Chrome in the user agent,
+ // thus pass the Chrome check above and not reach this block.
+ polyfill = /Android\s[0-4][^\d]/g.test(navigator.userAgent);
+ } else if (navigator.userAgent.indexOf('Safari') >= 0) {
+ versionMatch = navigator.userAgent.
+ match(/Version\/([0-9]+)\.([0-9]+)\.([0-9]+) Safari\//);
+ // Safari < 6 lacks the set function.
+ polyfill = versionMatch && parseInt(versionMatch[1]) < 6;
+ }
+
+ if (polyfill) {
+ var contextPrototype = window.CanvasRenderingContext2D.prototype;
+ contextPrototype._createImageData = contextPrototype.createImageData;
+ contextPrototype.createImageData = function(w, h) {
+ var imageData = this._createImageData(w, h);
+ imageData.data.set = function(arr) {
+ for (var i = 0, ii = this.length; i < ii; i++) {
+ this[i] = arr[i];
+ }
+ };
+ return imageData;
+ };
+ }
+ }
+})();
+
+// Support: IE<10, Android<4.0, iOS
+(function checkRequestAnimationFrame() {
+ function fakeRequestAnimationFrame(callback) {
+ window.setTimeout(callback, 20);
+ }
+
+ var isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
+ if (isIOS) {
+ // requestAnimationFrame on iOS is broken, replacing with fake one.
+ window.requestAnimationFrame = fakeRequestAnimationFrame;
+ return;
+ }
+ if ('requestAnimationFrame' in window) {
+ return;
+ }
+ window.requestAnimationFrame =
+ window.mozRequestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ fakeRequestAnimationFrame;
+})();
+
+(function checkCanvasSizeLimitation() {
+ var isIOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent);
+ var isAndroid = /Android/g.test(navigator.userAgent);
+ if (isIOS || isAndroid) {
+ // 5MP
+ PDFJS.maxCanvasPixels = 5242880;
+ }
+})();
diff --git a/static/pdf.js/debugger.js b/static/pdf.js/debugger.js
index a70ad0cd9..a9d173b72 100644
--- a/static/pdf.js/debugger.js
+++ b/static/pdf.js/debugger.js
@@ -20,7 +20,6 @@
var FontInspector = (function FontInspectorClosure() {
var fonts;
- var panelWidth = 300;
var active = false;
var fontAttribute = 'data-font-name';
function removeSelection() {
@@ -46,13 +45,17 @@ var FontInspector = (function FontInspectorClosure() {
}
}
function textLayerClick(e) {
- if (!e.target.dataset.fontName || e.target.tagName.toUpperCase() !== 'DIV')
+ if (!e.target.dataset.fontName ||
+ e.target.tagName.toUpperCase() !== 'DIV') {
return;
+ }
var fontName = e.target.dataset.fontName;
var selects = document.getElementsByTagName('input');
for (var i = 0; i < selects.length; ++i) {
var select = selects[i];
- if (select.dataset.fontName != fontName) continue;
+ if (select.dataset.fontName !== fontName) {
+ continue;
+ }
select.checked = !select.checked;
selectFont(fontName, select.checked);
select.scrollIntoView();
@@ -75,6 +78,9 @@ var FontInspector = (function FontInspectorClosure() {
fonts = document.createElement('div');
panel.appendChild(fonts);
},
+ cleanup: function cleanup() {
+ fonts.textContent = '';
+ },
enabled: false,
get active() {
return active;
@@ -106,13 +112,20 @@ var FontInspector = (function FontInspectorClosure() {
return moreInfo;
}
var moreInfo = properties(fontObj, ['name', 'type']);
- var m = /url\(['"]?([^\)"']+)/.exec(url);
var fontName = fontObj.loadedName;
var font = document.createElement('div');
var name = document.createElement('span');
name.textContent = fontName;
var download = document.createElement('a');
- download.href = m[1];
+ if (url) {
+ url = /url\(['"]?([^\)"']+)/.exec(url);
+ download.href = url[1];
+ } else if (fontObj.data) {
+ url = URL.createObjectURL(new Blob([fontObj.data], {
+ type: fontObj.mimeType
+ }));
+ }
+ download.href = url;
download.textContent = 'Download';
var logIt = document.createElement('a');
logIt.href = '';
@@ -140,8 +153,9 @@ var FontInspector = (function FontInspectorClosure() {
// Somewhat of a hack, should probably add a hook for when the text layer
// is done rendering.
setTimeout(function() {
- if (this.active)
+ if (this.active) {
resetSelection();
+ }
}.bind(this), 2000);
}
};
@@ -172,8 +186,14 @@ var StepperManager = (function StepperManagerClosure() {
stepperDiv = document.createElement('div');
this.panel.appendChild(stepperControls);
this.panel.appendChild(stepperDiv);
- if (sessionStorage.getItem('pdfjsBreakPoints'))
+ if (sessionStorage.getItem('pdfjsBreakPoints')) {
breakPoints = JSON.parse(sessionStorage.getItem('pdfjsBreakPoints'));
+ }
+ },
+ cleanup: function cleanup() {
+ stepperChooser.textContent = '';
+ stepperDiv.textContent = '';
+ steppers = [];
},
enabled: false,
active: false,
@@ -191,24 +211,29 @@ var StepperManager = (function StepperManagerClosure() {
var initBreakPoints = breakPoints[pageIndex] || [];
var stepper = new Stepper(debug, pageIndex, initBreakPoints);
steppers.push(stepper);
- if (steppers.length === 1)
+ if (steppers.length === 1) {
this.selectStepper(pageIndex, false);
+ }
return stepper;
},
selectStepper: function selectStepper(pageIndex, selectPanel) {
- if (selectPanel)
- this.manager.selectPanel(1);
- for (var i = 0; i < steppers.length; ++i) {
+ var i;
+ pageIndex = pageIndex | 0;
+ if (selectPanel) {
+ this.manager.selectPanel(this);
+ }
+ for (i = 0; i < steppers.length; ++i) {
var stepper = steppers[i];
- if (stepper.pageIndex == pageIndex)
+ if (stepper.pageIndex === pageIndex) {
stepper.panel.removeAttribute('hidden');
- else
+ } else {
stepper.panel.setAttribute('hidden', true);
+ }
}
var options = stepperChooser.options;
- for (var i = 0; i < options.length; ++i) {
+ for (i = 0; i < options.length; ++i) {
var option = options[i];
- option.selected = option.value == pageIndex;
+ option.selected = (option.value | 0) === pageIndex;
}
},
saveBreakPoints: function saveBreakPoints(pageIndex, bps) {
@@ -223,31 +248,40 @@ var Stepper = (function StepperClosure() {
// Shorter way to create element and optionally set textContent.
function c(tag, textContent) {
var d = document.createElement(tag);
- if (textContent)
+ if (textContent) {
d.textContent = textContent;
- return d;
- }
-
- function glyphsToString(glyphs) {
- var out = '';
- for (var i = 0; i < glyphs.length; i++) {
- if (glyphs[i] === null) {
- out += ' ';
- } else {
- out += glyphs[i].fontChar;
- }
}
- return out;
+ return d;
}
var opMap = null;
- var glyphCommands = {
- 'showText': 0,
- 'showSpacedText': 0,
- 'nextLineShowText': 0,
- 'nextLineSetSpacingShowText': 2
- };
+ function simplifyArgs(args) {
+ if (typeof args === 'string') {
+ var MAX_STRING_LENGTH = 75;
+ return args.length <= MAX_STRING_LENGTH ? args :
+ args.substr(0, MAX_STRING_LENGTH) + '...';
+ }
+ if (typeof args !== 'object' || args === null) {
+ return args;
+ }
+ if ('length' in args) { // array
+ var simpleArgs = [], i, ii;
+ var MAX_ITEMS = 10;
+ for (i = 0, ii = Math.min(MAX_ITEMS, args.length); i < ii; i++) {
+ simpleArgs.push(simplifyArgs(args[i]));
+ }
+ if (i < args.length) {
+ simpleArgs.push('...');
+ }
+ return simpleArgs;
+ }
+ var simpleObj = {};
+ for (var key in args) {
+ simpleObj[key] = simplifyArgs(args[key]);
+ }
+ return simpleObj;
+ }
function Stepper(panel, pageIndex, initialBreakPoints) {
this.panel = panel;
@@ -282,62 +316,85 @@ var Stepper = (function StepperClosure() {
},
updateOperatorList: function updateOperatorList(operatorList) {
var self = this;
- for (var i = this.operatorListIdx; i < operatorList.fnArray.length; i++) {
+
+ function cboxOnClick() {
+ var x = +this.dataset.idx;
+ if (this.checked) {
+ self.breakPoints.push(x);
+ } else {
+ self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
+ }
+ StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
+ }
+
+ var MAX_OPERATORS_COUNT = 15000;
+ if (this.operatorListIdx > MAX_OPERATORS_COUNT) {
+ return;
+ }
+
+ var chunk = document.createDocumentFragment();
+ var operatorsToDisplay = Math.min(MAX_OPERATORS_COUNT,
+ operatorList.fnArray.length);
+ for (var i = this.operatorListIdx; i < operatorsToDisplay; i++) {
var line = c('tr');
line.className = 'line';
line.dataset.idx = i;
- this.table.appendChild(line);
- var checked = this.breakPoints.indexOf(i) != -1;
- var args = operatorList.argsArray[i] ? operatorList.argsArray[i] : [];
+ chunk.appendChild(line);
+ var checked = this.breakPoints.indexOf(i) !== -1;
+ var args = operatorList.argsArray[i] || [];
var breakCell = c('td');
var cbox = c('input');
cbox.type = 'checkbox';
cbox.className = 'points';
cbox.checked = checked;
- cbox.onclick = (function(x) {
- return function() {
- if (this.checked)
- self.breakPoints.push(x);
- else
- self.breakPoints.splice(self.breakPoints.indexOf(x), 1);
- StepperManager.saveBreakPoints(self.pageIndex, self.breakPoints);
- };
- })(i);
+ cbox.dataset.idx = i;
+ cbox.onclick = cboxOnClick;
breakCell.appendChild(cbox);
line.appendChild(breakCell);
line.appendChild(c('td', i.toString()));
var fn = opMap[operatorList.fnArray[i]];
var decArgs = args;
- if (fn in glyphCommands) {
- var glyphIndex = glyphCommands[fn];
- var glyphs = args[glyphIndex];
- var decArgs = args.slice();
- var newArg;
- if (fn === 'showSpacedText') {
- newArg = [];
- for (var j = 0; j < glyphs.length; j++) {
- if (typeof glyphs[j] === 'number') {
- newArg.push(glyphs[j]);
- } else {
- newArg.push(glyphsToString(glyphs[j]));
+ if (fn === 'showText') {
+ var glyphs = args[0];
+ var newArgs = [];
+ var str = [];
+ for (var j = 0; j < glyphs.length; j++) {
+ var glyph = glyphs[j];
+ if (typeof glyph === 'object' && glyph !== null) {
+ str.push(glyph.fontChar);
+ } else {
+ if (str.length > 0) {
+ newArgs.push(str.join(''));
+ str = [];
}
+ newArgs.push(glyph); // null or number
}
- } else {
- newArg = glyphsToString(glyphs);
}
- decArgs[glyphIndex] = newArg;
+ if (str.length > 0) {
+ newArgs.push(str.join(''));
+ }
+ decArgs = [newArgs];
}
line.appendChild(c('td', fn));
- line.appendChild(c('td', JSON.stringify(decArgs)));
+ line.appendChild(c('td', JSON.stringify(simplifyArgs(decArgs))));
}
+ if (operatorsToDisplay < operatorList.fnArray.length) {
+ line = c('tr');
+ var lastCell = c('td', '...');
+ lastCell.colspan = 4;
+ chunk.appendChild(lastCell);
+ }
+ this.operatorListIdx = operatorList.fnArray.length;
+ this.table.appendChild(chunk);
},
getNextBreakPoint: function getNextBreakPoint() {
this.breakPoints.sort(function(a, b) { return a - b; });
for (var i = 0; i < this.breakPoints.length; i++) {
- if (this.breakPoints[i] > this.currentIdx)
+ if (this.breakPoints[i] > this.currentIdx) {
return this.breakPoints[i];
+ }
}
return null;
},
@@ -370,7 +427,7 @@ var Stepper = (function StepperClosure() {
var allRows = this.panel.getElementsByClassName('line');
for (var x = 0, xx = allRows.length; x < xx; ++x) {
var row = allRows[x];
- if (row.dataset.idx == idx) {
+ if ((row.dataset.idx | 0) === idx) {
row.style.backgroundColor = 'rgb(251,250,207)';
row.scrollIntoView();
} else {
@@ -385,13 +442,16 @@ var Stepper = (function StepperClosure() {
var Stats = (function Stats() {
var stats = [];
function clear(node) {
- while (node.hasChildNodes())
+ while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
+ }
}
function getStatIndex(pageNumber) {
- for (var i = 0, ii = stats.length; i < ii; ++i)
- if (stats[i].pageNumber === pageNumber)
+ for (var i = 0, ii = stats.length; i < ii; ++i) {
+ if (stats[i].pageNumber === pageNumber) {
return i;
+ }
+ }
return false;
}
return {
@@ -408,8 +468,9 @@ var Stats = (function Stats() {
active: false,
// Stats specific functions.
add: function(pageNumber, stat) {
- if (!stat)
+ if (!stat) {
return;
+ }
var statsIndex = getStatIndex(pageNumber);
if (statsIndex !== false) {
var b = stats[statsIndex];
@@ -428,8 +489,13 @@ var Stats = (function Stats() {
stats.push({ pageNumber: pageNumber, div: wrapper });
stats.sort(function(a, b) { return a.pageNumber - b.pageNumber; });
clear(this.panel);
- for (var i = 0, ii = stats.length; i < ii; ++i)
+ for (var i = 0, ii = stats.length; i < ii; ++i) {
this.panel.appendChild(stats[i].div);
+ }
+ },
+ cleanup: function () {
+ stats = [];
+ clear(this.panel);
}
};
})();
@@ -448,12 +514,14 @@ var PDFBug = (function PDFBugClosure() {
],
enable: function(ids) {
var all = false, tools = this.tools;
- if (ids.length === 1 && ids[0] === 'all')
+ if (ids.length === 1 && ids[0] === 'all') {
all = true;
+ }
for (var i = 0; i < tools.length; ++i) {
var tool = tools[i];
- if (all || ids.indexOf(tool.id) !== -1)
+ if (all || ids.indexOf(tool.id) !== -1) {
tool.enabled = true;
+ }
}
if (!all) {
// Sort the tools by the order they are enabled.
@@ -509,23 +577,35 @@ var PDFBug = (function PDFBugClosure() {
panels.appendChild(panel);
tool.panel = panel;
tool.manager = this;
- if (tool.enabled)
+ if (tool.enabled) {
tool.init();
- else
+ } else {
panel.textContent = tool.name + ' is disabled. To enable add ' +
' "' + tool.id + '" to the pdfBug parameter ' +
'and refresh (seperate multiple by commas).';
+ }
buttons.push(panelButton);
}
this.selectPanel(0);
},
+ cleanup: function cleanup() {
+ for (var i = 0, ii = this.tools.length; i < ii; i++) {
+ if (this.tools[i].enabled) {
+ this.tools[i].cleanup();
+ }
+ }
+ },
selectPanel: function selectPanel(index) {
- if (index === activePanel)
+ if (typeof index !== 'number') {
+ index = this.tools.indexOf(index);
+ }
+ if (index === activePanel) {
return;
+ }
activePanel = index;
var tools = this.tools;
for (var j = 0; j < tools.length; ++j) {
- if (j == index) {
+ if (j === index) {
buttons[j].setAttribute('class', 'active');
tools[j].active = true;
tools[j].panel.removeAttribute('hidden');
diff --git a/static/pdf.js/images/annotation-noicon.svg b/static/pdf.js/images/annotation-noicon.svg
new file mode 100644
index 000000000..c07d10808
--- /dev/null
+++ b/static/pdf.js/images/annotation-noicon.svg
@@ -0,0 +1,7 @@
+
+
diff --git a/static/pdf.js/images/findbarButton-next-rtl.png b/static/pdf.js/images/findbarButton-next-rtl.png
index 4b5551e23..bef02743f 100644
Binary files a/static/pdf.js/images/findbarButton-next-rtl.png and b/static/pdf.js/images/findbarButton-next-rtl.png differ
diff --git a/static/pdf.js/images/findbarButton-next-rtl@2x.png b/static/pdf.js/images/findbarButton-next-rtl@2x.png
new file mode 100644
index 000000000..1da6dc949
Binary files /dev/null and b/static/pdf.js/images/findbarButton-next-rtl@2x.png differ
diff --git a/static/pdf.js/images/findbarButton-next.png b/static/pdf.js/images/findbarButton-next.png
index f681e4ee4..de1d0fc90 100644
Binary files a/static/pdf.js/images/findbarButton-next.png and b/static/pdf.js/images/findbarButton-next.png differ
diff --git a/static/pdf.js/images/findbarButton-next@2x.png b/static/pdf.js/images/findbarButton-next@2x.png
new file mode 100644
index 000000000..0250307c0
Binary files /dev/null and b/static/pdf.js/images/findbarButton-next@2x.png differ
diff --git a/static/pdf.js/images/findbarButton-previous-rtl.png b/static/pdf.js/images/findbarButton-previous-rtl.png
index f681e4ee4..de1d0fc90 100644
Binary files a/static/pdf.js/images/findbarButton-previous-rtl.png and b/static/pdf.js/images/findbarButton-previous-rtl.png differ
diff --git a/static/pdf.js/images/findbarButton-previous-rtl@2x.png b/static/pdf.js/images/findbarButton-previous-rtl@2x.png
new file mode 100644
index 000000000..0250307c0
Binary files /dev/null and b/static/pdf.js/images/findbarButton-previous-rtl@2x.png differ
diff --git a/static/pdf.js/images/findbarButton-previous.png b/static/pdf.js/images/findbarButton-previous.png
index 4b5551e23..bef02743f 100644
Binary files a/static/pdf.js/images/findbarButton-previous.png and b/static/pdf.js/images/findbarButton-previous.png differ
diff --git a/static/pdf.js/images/findbarButton-previous@2x.png b/static/pdf.js/images/findbarButton-previous@2x.png
new file mode 100644
index 000000000..1da6dc949
Binary files /dev/null and b/static/pdf.js/images/findbarButton-previous@2x.png differ
diff --git a/static/pdf.js/images/loading-small.png b/static/pdf.js/images/loading-small.png
index 51848a70f..8831a8058 100644
Binary files a/static/pdf.js/images/loading-small.png and b/static/pdf.js/images/loading-small.png differ
diff --git a/static/pdf.js/images/loading-small@2x.png b/static/pdf.js/images/loading-small@2x.png
new file mode 100644
index 000000000..b25b4452a
Binary files /dev/null and b/static/pdf.js/images/loading-small@2x.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-documentProperties.png b/static/pdf.js/images/secondaryToolbarButton-documentProperties.png
new file mode 100644
index 000000000..40925e25a
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-documentProperties.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-documentProperties@2x.png b/static/pdf.js/images/secondaryToolbarButton-documentProperties@2x.png
new file mode 100644
index 000000000..adb240eaa
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-documentProperties@2x.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-firstPage.png b/static/pdf.js/images/secondaryToolbarButton-firstPage.png
index 2c1076d46..e68846aa5 100644
Binary files a/static/pdf.js/images/secondaryToolbarButton-firstPage.png and b/static/pdf.js/images/secondaryToolbarButton-firstPage.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-firstPage@2x.png b/static/pdf.js/images/secondaryToolbarButton-firstPage@2x.png
new file mode 100644
index 000000000..3ad8af517
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-firstPage@2x.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-handTool.png b/static/pdf.js/images/secondaryToolbarButton-handTool.png
index 10845c695..cb85a841b 100644
Binary files a/static/pdf.js/images/secondaryToolbarButton-handTool.png and b/static/pdf.js/images/secondaryToolbarButton-handTool.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-handTool@2x.png b/static/pdf.js/images/secondaryToolbarButton-handTool@2x.png
new file mode 100644
index 000000000..5c13f77ff
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-handTool@2x.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-lastPage.png b/static/pdf.js/images/secondaryToolbarButton-lastPage.png
index 55a9efe42..be763e0c4 100644
Binary files a/static/pdf.js/images/secondaryToolbarButton-lastPage.png and b/static/pdf.js/images/secondaryToolbarButton-lastPage.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-lastPage@2x.png b/static/pdf.js/images/secondaryToolbarButton-lastPage@2x.png
new file mode 100644
index 000000000..8570984f2
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-lastPage@2x.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-rotateCcw.png b/static/pdf.js/images/secondaryToolbarButton-rotateCcw.png
index d23d84a54..675d6da2c 100644
Binary files a/static/pdf.js/images/secondaryToolbarButton-rotateCcw.png and b/static/pdf.js/images/secondaryToolbarButton-rotateCcw.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-rotateCcw@2x.png b/static/pdf.js/images/secondaryToolbarButton-rotateCcw@2x.png
new file mode 100644
index 000000000..b9e743122
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-rotateCcw@2x.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-rotateCw.png b/static/pdf.js/images/secondaryToolbarButton-rotateCw.png
index f36bba81e..e1c759888 100644
Binary files a/static/pdf.js/images/secondaryToolbarButton-rotateCw.png and b/static/pdf.js/images/secondaryToolbarButton-rotateCw.png differ
diff --git a/static/pdf.js/images/secondaryToolbarButton-rotateCw@2x.png b/static/pdf.js/images/secondaryToolbarButton-rotateCw@2x.png
new file mode 100644
index 000000000..cb257b41c
Binary files /dev/null and b/static/pdf.js/images/secondaryToolbarButton-rotateCw@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-bookmark.png b/static/pdf.js/images/toolbarButton-bookmark.png
index b27050e21..a187be6c9 100644
Binary files a/static/pdf.js/images/toolbarButton-bookmark.png and b/static/pdf.js/images/toolbarButton-bookmark.png differ
diff --git a/static/pdf.js/images/toolbarButton-bookmark@2x.png b/static/pdf.js/images/toolbarButton-bookmark@2x.png
new file mode 100644
index 000000000..4efbaa675
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-bookmark@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-download.png b/static/pdf.js/images/toolbarButton-download.png
index 7755eee77..eaab35f09 100644
Binary files a/static/pdf.js/images/toolbarButton-download.png and b/static/pdf.js/images/toolbarButton-download.png differ
diff --git a/static/pdf.js/images/toolbarButton-download@2x.png b/static/pdf.js/images/toolbarButton-download@2x.png
new file mode 100644
index 000000000..896face45
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-download@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-menuArrows.png b/static/pdf.js/images/toolbarButton-menuArrows.png
index 63a7c320e..306eb43b8 100644
Binary files a/static/pdf.js/images/toolbarButton-menuArrows.png and b/static/pdf.js/images/toolbarButton-menuArrows.png differ
diff --git a/static/pdf.js/images/toolbarButton-menuArrows@2x.png b/static/pdf.js/images/toolbarButton-menuArrows@2x.png
new file mode 100644
index 000000000..f7570bc0d
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-menuArrows@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-openFile.png b/static/pdf.js/images/toolbarButton-openFile.png
index e139f3017..b5cf1bd06 100644
Binary files a/static/pdf.js/images/toolbarButton-openFile.png and b/static/pdf.js/images/toolbarButton-openFile.png differ
diff --git a/static/pdf.js/images/toolbarButton-openFile@2x.png b/static/pdf.js/images/toolbarButton-openFile@2x.png
new file mode 100644
index 000000000..91ab76593
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-openFile@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageDown-rtl.png b/static/pdf.js/images/toolbarButton-pageDown-rtl.png
index 9ba3667e9..1957f79ab 100644
Binary files a/static/pdf.js/images/toolbarButton-pageDown-rtl.png and b/static/pdf.js/images/toolbarButton-pageDown-rtl.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageDown-rtl@2x.png b/static/pdf.js/images/toolbarButton-pageDown-rtl@2x.png
new file mode 100644
index 000000000..16ebcb8ef
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-pageDown-rtl@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageDown.png b/static/pdf.js/images/toolbarButton-pageDown.png
index 272a3ca83..8219ecf83 100644
Binary files a/static/pdf.js/images/toolbarButton-pageDown.png and b/static/pdf.js/images/toolbarButton-pageDown.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageDown@2x.png b/static/pdf.js/images/toolbarButton-pageDown@2x.png
new file mode 100644
index 000000000..758c01d83
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-pageDown@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageUp-rtl.png b/static/pdf.js/images/toolbarButton-pageUp-rtl.png
index da02bc69f..98e7ce481 100644
Binary files a/static/pdf.js/images/toolbarButton-pageUp-rtl.png and b/static/pdf.js/images/toolbarButton-pageUp-rtl.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageUp-rtl@2x.png b/static/pdf.js/images/toolbarButton-pageUp-rtl@2x.png
new file mode 100644
index 000000000..a01b02380
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-pageUp-rtl@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageUp.png b/static/pdf.js/images/toolbarButton-pageUp.png
index a4d6c8ea7..fb9daa337 100644
Binary files a/static/pdf.js/images/toolbarButton-pageUp.png and b/static/pdf.js/images/toolbarButton-pageUp.png differ
diff --git a/static/pdf.js/images/toolbarButton-pageUp@2x.png b/static/pdf.js/images/toolbarButton-pageUp@2x.png
new file mode 100644
index 000000000..a5cfd755b
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-pageUp@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-presentationMode.png b/static/pdf.js/images/toolbarButton-presentationMode.png
index 2bd1c1dfe..3ac21244d 100644
Binary files a/static/pdf.js/images/toolbarButton-presentationMode.png and b/static/pdf.js/images/toolbarButton-presentationMode.png differ
diff --git a/static/pdf.js/images/toolbarButton-presentationMode@2x.png b/static/pdf.js/images/toolbarButton-presentationMode@2x.png
new file mode 100644
index 000000000..cada9e791
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-presentationMode@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-print.png b/static/pdf.js/images/toolbarButton-print.png
index ccc62089f..51275e54b 100644
Binary files a/static/pdf.js/images/toolbarButton-print.png and b/static/pdf.js/images/toolbarButton-print.png differ
diff --git a/static/pdf.js/images/toolbarButton-print@2x.png b/static/pdf.js/images/toolbarButton-print@2x.png
new file mode 100644
index 000000000..53d18daf7
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-print@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-search.png b/static/pdf.js/images/toolbarButton-search.png
index e52370e68..f9b75579b 100644
Binary files a/static/pdf.js/images/toolbarButton-search.png and b/static/pdf.js/images/toolbarButton-search.png differ
diff --git a/static/pdf.js/images/toolbarButton-search@2x.png b/static/pdf.js/images/toolbarButton-search@2x.png
new file mode 100644
index 000000000..456b13324
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-search@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl.png b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl.png
index 145316b83..843709527 100644
Binary files a/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl.png and b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl.png differ
diff --git a/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png
new file mode 100644
index 000000000..9d9bfa4f6
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle-rtl@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-secondaryToolbarToggle.png b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle.png
index 02ed6c62a..1f90f83da 100644
Binary files a/static/pdf.js/images/toolbarButton-secondaryToolbarToggle.png and b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle.png differ
diff --git a/static/pdf.js/images/toolbarButton-secondaryToolbarToggle@2x.png b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle@2x.png
new file mode 100644
index 000000000..b066fe5cb
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-secondaryToolbarToggle@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-sidebarToggle-rtl.png b/static/pdf.js/images/toolbarButton-sidebarToggle-rtl.png
index c308668b1..6f85ec061 100644
Binary files a/static/pdf.js/images/toolbarButton-sidebarToggle-rtl.png and b/static/pdf.js/images/toolbarButton-sidebarToggle-rtl.png differ
diff --git a/static/pdf.js/images/toolbarButton-sidebarToggle-rtl@2x.png b/static/pdf.js/images/toolbarButton-sidebarToggle-rtl@2x.png
new file mode 100644
index 000000000..291e00679
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-sidebarToggle-rtl@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-sidebarToggle.png b/static/pdf.js/images/toolbarButton-sidebarToggle.png
index be9eceba9..025dc9040 100644
Binary files a/static/pdf.js/images/toolbarButton-sidebarToggle.png and b/static/pdf.js/images/toolbarButton-sidebarToggle.png differ
diff --git a/static/pdf.js/images/toolbarButton-sidebarToggle@2x.png b/static/pdf.js/images/toolbarButton-sidebarToggle@2x.png
new file mode 100644
index 000000000..7f834df94
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-sidebarToggle@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewAttachments.png b/static/pdf.js/images/toolbarButton-viewAttachments.png
new file mode 100644
index 000000000..fcd0b268a
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-viewAttachments.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewAttachments@2x.png b/static/pdf.js/images/toolbarButton-viewAttachments@2x.png
new file mode 100644
index 000000000..b979e523e
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-viewAttachments@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewOutline-rtl.png b/static/pdf.js/images/toolbarButton-viewOutline-rtl.png
index 21ceb3b16..aaa943021 100644
Binary files a/static/pdf.js/images/toolbarButton-viewOutline-rtl.png and b/static/pdf.js/images/toolbarButton-viewOutline-rtl.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewOutline-rtl@2x.png b/static/pdf.js/images/toolbarButton-viewOutline-rtl@2x.png
new file mode 100644
index 000000000..3410f70df
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-viewOutline-rtl@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewOutline.png b/static/pdf.js/images/toolbarButton-viewOutline.png
index 9b2e2f5be..976365a50 100644
Binary files a/static/pdf.js/images/toolbarButton-viewOutline.png and b/static/pdf.js/images/toolbarButton-viewOutline.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewOutline@2x.png b/static/pdf.js/images/toolbarButton-viewOutline@2x.png
new file mode 100644
index 000000000..b6a197fdf
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-viewOutline@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewThumbnail.png b/static/pdf.js/images/toolbarButton-viewThumbnail.png
index d71dd2771..584ba5588 100644
Binary files a/static/pdf.js/images/toolbarButton-viewThumbnail.png and b/static/pdf.js/images/toolbarButton-viewThumbnail.png differ
diff --git a/static/pdf.js/images/toolbarButton-viewThumbnail@2x.png b/static/pdf.js/images/toolbarButton-viewThumbnail@2x.png
new file mode 100644
index 000000000..fb7db9383
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-viewThumbnail@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-zoomIn.png b/static/pdf.js/images/toolbarButton-zoomIn.png
index 670acd93f..513d081bc 100644
Binary files a/static/pdf.js/images/toolbarButton-zoomIn.png and b/static/pdf.js/images/toolbarButton-zoomIn.png differ
diff --git a/static/pdf.js/images/toolbarButton-zoomIn@2x.png b/static/pdf.js/images/toolbarButton-zoomIn@2x.png
new file mode 100644
index 000000000..d5d49d5ff
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-zoomIn@2x.png differ
diff --git a/static/pdf.js/images/toolbarButton-zoomOut.png b/static/pdf.js/images/toolbarButton-zoomOut.png
index 7991ee7a5..156c26b94 100644
Binary files a/static/pdf.js/images/toolbarButton-zoomOut.png and b/static/pdf.js/images/toolbarButton-zoomOut.png differ
diff --git a/static/pdf.js/images/toolbarButton-zoomOut@2x.png b/static/pdf.js/images/toolbarButton-zoomOut@2x.png
new file mode 100644
index 000000000..959e1919d
Binary files /dev/null and b/static/pdf.js/images/toolbarButton-zoomOut@2x.png differ
diff --git a/static/pdf.js/index.html b/static/pdf.js/index.html
index d2d12fe73..bebce17b2 100644
--- a/static/pdf.js/index.html
+++ b/static/pdf.js/index.html
@@ -13,6 +13,9 @@ 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.
+
+Adobe CMap resources are covered by their own copyright and license:
+http://sourceforge.net/adobe/cmap/wiki/License/
-->
@@ -24,23 +27,23 @@ limitations under the License.
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
@@ -56,6 +59,9 @@ limitations under the License.
+
+
+
+
-
+
Toggle Sidebar
-
-
-
+
@@ -259,21 +275,66 @@ limitations under the License.
-
rdf = rdf.firstChild;
- while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf')
+ while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') {
rdf = rdf.nextSibling;
+ }
}
var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null;
- if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes())
+ if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) {
return;
+ }
var children = rdf.childNodes, desc, entry, name, i, ii, length, iLength;
-
for (i = 0, length = children.length; i < length; i++) {
desc = children[i];
- if (desc.nodeName.toLowerCase() !== 'rdf:description')
+ if (desc.nodeName.toLowerCase() !== 'rdf:description') {
continue;
+ }
for (ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) {
if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') {
@@ -5390,6 +3111,7 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
// Minimal font size that would be used during canvas fillText operations.
var MIN_FONT_SIZE = 16;
+var MAX_GROUP_SIZE = 4096;
var COMPILE_TYPE3_GLYPHS = true;
@@ -5542,7 +3264,14 @@ var CachedCanvases = (function CachedCanvasesClosure() {
return canvasEntry;
},
clear: function () {
- cache = {};
+ for (var id in cache) {
+ var canvasEntry = cache[id];
+ // Zeroing the width and height causes Firefox to release graphics
+ // resources immediately, which can greatly reduce memory consumption.
+ canvasEntry.canvas.width = 0;
+ canvasEntry.canvas.height = 0;
+ delete cache[id];
+ }
}
};
})();
@@ -5555,6 +3284,18 @@ function compileType3Glyph(imgData) {
var points = new Uint8Array(width1 * (height + 1));
var POINT_TYPES =
new Uint8Array([0, 2, 4, 0, 1, 0, 5, 4, 8, 10, 0, 8, 0, 2, 1, 0]);
+
+ // decodes bit-packed mask data
+ var lineSize = (width + 7) & ~7, data0 = imgData.data;
+ var data = new Uint8Array(lineSize * height), pos = 0, ii;
+ for (i = 0, ii = data0.length; i < ii; i++) {
+ var mask = 128, elem = data0[i];
+ while (mask > 0) {
+ data[pos++] = (elem & mask) ? 0 : 255;
+ mask >>= 1;
+ }
+ }
+
// finding iteresting points: every point is located between mask pixels,
// so there will be points of the (width + 1)x(height + 1) grid. Every point
// will have flags assigned based on neighboring mask pixels:
@@ -5565,24 +3306,25 @@ function compileType3Glyph(imgData) {
// - outside corners: 1, 2, 4, 8;
// - inside corners: 7, 11, 13, 14;
// - and, intersections: 5, 10.
- var pos = 3, data = imgData.data, lineSize = width * 4, count = 0;
- if (data[3] !== 0) {
+ var count = 0;
+ pos = 0;
+ if (data[pos] !== 0) {
points[0] = 1;
++count;
}
for (j = 1; j < width; j++) {
- if (data[pos] !== data[pos + 4]) {
+ if (data[pos] !== data[pos + 1]) {
points[j] = data[pos] ? 2 : 1;
++count;
}
- pos += 4;
+ pos++;
}
if (data[pos] !== 0) {
points[j] = 2;
++count;
}
- pos += 4;
for (i = 1; i < height; i++) {
+ pos = i * lineSize;
j0 = i * width1;
if (data[pos - lineSize] !== data[pos]) {
points[j0] = data[pos] ? 1 : 8;
@@ -5592,37 +3334,36 @@ function compileType3Glyph(imgData) {
// array (in order 8-1-2-4, so we can use '>>2' to shift the column).
var sum = (data[pos] ? 4 : 0) + (data[pos - lineSize] ? 8 : 0);
for (j = 1; j < width; j++) {
- sum = (sum >> 2) + (data[pos + 4] ? 4 : 0) +
- (data[pos - lineSize + 4] ? 8 : 0);
+ sum = (sum >> 2) + (data[pos + 1] ? 4 : 0) +
+ (data[pos - lineSize + 1] ? 8 : 0);
if (POINT_TYPES[sum]) {
points[j0 + j] = POINT_TYPES[sum];
++count;
}
- pos += 4;
+ pos++;
}
if (data[pos - lineSize] !== data[pos]) {
points[j0 + j] = data[pos] ? 2 : 4;
++count;
}
- pos += 4;
if (count > POINT_TO_PROCESS_LIMIT) {
return null;
}
}
- pos -= lineSize;
+ pos = lineSize * (height - 1);
j0 = i * width1;
if (data[pos] !== 0) {
points[j0] = 8;
++count;
}
for (j = 1; j < width; j++) {
- if (data[pos] !== data[pos + 4]) {
+ if (data[pos] !== data[pos + 1]) {
points[j0 + j] = data[pos] ? 4 : 8;
++count;
}
- pos += 4;
+ pos++;
}
if (data[pos] !== 0) {
points[j0 + j] = 4;
@@ -5649,7 +3390,9 @@ function compileType3Glyph(imgData) {
var type = points[p], p0 = p, pp;
do {
var step = steps[type];
- do { p += step; } while (!points[p]);
+ do {
+ p += step;
+ } while (!points[p]);
pp = points[p];
if (pp !== 5 && pp !== 10) {
@@ -5700,6 +3443,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.fontSize = 0;
this.fontSizeScale = 1;
this.textMatrix = IDENTITY_MATRIX;
+ this.textMatrixScale = 1;
this.fontMatrix = FONT_IDENTITY_MATRIX;
this.leading = 0;
// Current point (in user coordinates)
@@ -5714,13 +3458,6 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.textHScale = 1;
this.textRenderingMode = TextRenderingMode.FILL;
this.textRise = 0;
- // Color spaces
- this.fillColorSpace = ColorSpace.singletons.gray;
- this.fillColorSpaceObj = null;
- this.strokeColorSpace = ColorSpace.singletons.gray;
- this.strokeColorSpaceObj = null;
- this.fillColorObj = null;
- this.strokeColorObj = null;
// Default fore and background colors
this.fillColor = '#000000';
this.strokeColor = '#000000';
@@ -5728,7 +3465,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.fillAlpha = 1;
this.strokeAlpha = 1;
this.lineWidth = 1;
- this.paintFormXObjectDepth = 0;
+ this.activeSMask = null; // nonclonable field (see the save method below)
this.old = old;
}
@@ -5749,8 +3486,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Defines the time the executeOperatorList is going to be executing
// before it stops and shedules a continue of execution.
var EXECUTION_TIME = 15;
+ // Defines the number of steps before checking the execution time
+ var EXECUTION_STEPS = 10;
- function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
+ function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {
this.ctx = canvasCtx;
this.current = new CanvasExtraState();
this.stateStack = [];
@@ -5760,7 +3499,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.xobjs = null;
this.commonObjs = commonObjs;
this.objs = objs;
- this.textLayer = textLayer;
this.imageLayer = imageLayer;
this.groupStack = [];
this.processingType3 = null;
@@ -5769,6 +3507,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.baseTransform = null;
this.baseTransformStack = [];
this.groupLevel = 0;
+ this.smaskStack = [];
+ this.smaskCounter = 0;
+ this.tempSMask = null;
if (canvasCtx) {
addContextCurrentTransform(canvasCtx);
}
@@ -5780,19 +3521,157 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return;
}
- var tmpImgData = ctx.createImageData(imgData.width, imgData.height);
+ // Put the image data to the canvas in chunks, rather than putting the
+ // whole image at once. This saves JS memory, because the ImageData object
+ // is smaller. It also possibly saves C++ memory within the implementation
+ // of putImageData(). (E.g. in Firefox we make two short-lived copies of
+ // the data passed to putImageData()). |n| shouldn't be too small, however,
+ // because too many putImageData() calls will slow things down.
+ //
+ // Note: as written, if the last chunk is partial, the putImageData() call
+ // will (conceptually) put pixels past the bounds of the canvas. But
+ // that's ok; any such pixels are ignored.
- var data = imgData.data;
- var tmpImgDataPixels = tmpImgData.data;
- if ('set' in tmpImgDataPixels)
- tmpImgDataPixels.set(data);
- else {
- // Copy over the imageData pixel by pixel.
- for (var i = 0, ii = tmpImgDataPixels.length; i < ii; i++)
- tmpImgDataPixels[i] = data[i];
+ var height = imgData.height, width = imgData.width;
+ var fullChunkHeight = 16;
+ var fracChunks = height / fullChunkHeight;
+ var fullChunks = Math.floor(fracChunks);
+ var totalChunks = Math.ceil(fracChunks);
+ var partialChunkHeight = height - fullChunks * fullChunkHeight;
+
+ var chunkImgData = ctx.createImageData(width, fullChunkHeight);
+ var srcPos = 0, destPos;
+ var src = imgData.data;
+ var dest = chunkImgData.data;
+ var i, j, thisChunkHeight, elemsInThisChunk;
+
+ // There are multiple forms in which the pixel data can be passed, and
+ // imgData.kind tells us which one this is.
+ if (imgData.kind === ImageKind.GRAYSCALE_1BPP) {
+ // Grayscale, 1 bit per pixel (i.e. black-and-white).
+ var srcLength = src.byteLength;
+ var dest32 = PDFJS.hasCanvasTypedArrays ? new Uint32Array(dest.buffer) :
+ new Uint32ArrayView(dest);
+ var dest32DataLength = dest32.length;
+ var fullSrcDiff = (width + 7) >> 3;
+ var white = 0xFFFFFFFF;
+ var black = (PDFJS.isLittleEndian || !PDFJS.hasCanvasTypedArrays) ?
+ 0xFF000000 : 0x000000FF;
+ for (i = 0; i < totalChunks; i++) {
+ thisChunkHeight =
+ (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
+ destPos = 0;
+ for (j = 0; j < thisChunkHeight; j++) {
+ var srcDiff = srcLength - srcPos;
+ var k = 0;
+ var kEnd = (srcDiff > fullSrcDiff) ? width : srcDiff * 8 - 7;
+ var kEndUnrolled = kEnd & ~7;
+ var mask = 0;
+ var srcByte = 0;
+ for (; k < kEndUnrolled; k += 8) {
+ srcByte = src[srcPos++];
+ dest32[destPos++] = (srcByte & 128) ? white : black;
+ dest32[destPos++] = (srcByte & 64) ? white : black;
+ dest32[destPos++] = (srcByte & 32) ? white : black;
+ dest32[destPos++] = (srcByte & 16) ? white : black;
+ dest32[destPos++] = (srcByte & 8) ? white : black;
+ dest32[destPos++] = (srcByte & 4) ? white : black;
+ dest32[destPos++] = (srcByte & 2) ? white : black;
+ dest32[destPos++] = (srcByte & 1) ? white : black;
+ }
+ for (; k < kEnd; k++) {
+ if (mask === 0) {
+ srcByte = src[srcPos++];
+ mask = 128;
+ }
+
+ dest32[destPos++] = (srcByte & mask) ? white : black;
+ mask >>= 1;
+ }
+ }
+ // We ran out of input. Make all remaining pixels transparent.
+ while (destPos < dest32DataLength) {
+ dest32[destPos++] = 0;
+ }
+
+ ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
+ }
+ } else if (imgData.kind === ImageKind.RGBA_32BPP) {
+ // RGBA, 32-bits per pixel.
+
+ j = 0;
+ elemsInThisChunk = width * fullChunkHeight * 4;
+ for (i = 0; i < fullChunks; i++) {
+ dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
+ srcPos += elemsInThisChunk;
+
+ ctx.putImageData(chunkImgData, 0, j);
+ j += fullChunkHeight;
+ }
+ if (i < totalChunks) {
+ elemsInThisChunk = width * partialChunkHeight * 4;
+ dest.set(src.subarray(srcPos, srcPos + elemsInThisChunk));
+ ctx.putImageData(chunkImgData, 0, j);
+ }
+
+ } else if (imgData.kind === ImageKind.RGB_24BPP) {
+ // RGB, 24-bits per pixel.
+ thisChunkHeight = fullChunkHeight;
+ elemsInThisChunk = width * thisChunkHeight;
+ for (i = 0; i < totalChunks; i++) {
+ if (i >= fullChunks) {
+ thisChunkHeight =partialChunkHeight;
+ elemsInThisChunk = width * thisChunkHeight;
+ }
+
+ destPos = 0;
+ for (j = elemsInThisChunk; j--;) {
+ dest[destPos++] = src[srcPos++];
+ dest[destPos++] = src[srcPos++];
+ dest[destPos++] = src[srcPos++];
+ dest[destPos++] = 255;
+ }
+ ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
+ }
+ } else {
+ error('bad image kind: ' + imgData.kind);
}
+ }
- ctx.putImageData(tmpImgData, 0, 0);
+ function putBinaryImageMask(ctx, imgData) {
+ var height = imgData.height, width = imgData.width;
+ var fullChunkHeight = 16;
+ var fracChunks = height / fullChunkHeight;
+ var fullChunks = Math.floor(fracChunks);
+ var totalChunks = Math.ceil(fracChunks);
+ var partialChunkHeight = height - fullChunks * fullChunkHeight;
+
+ var chunkImgData = ctx.createImageData(width, fullChunkHeight);
+ var srcPos = 0;
+ var src = imgData.data;
+ var dest = chunkImgData.data;
+
+ for (var i = 0; i < totalChunks; i++) {
+ var thisChunkHeight =
+ (i < fullChunks) ? fullChunkHeight : partialChunkHeight;
+
+ // Expand the mask so it can be used by the canvas. Any required
+ // inversion has already been handled.
+ var destPos = 3; // alpha component offset
+ for (var j = 0; j < thisChunkHeight; j++) {
+ var mask = 0;
+ for (var k = 0; k < width; k++) {
+ if (!mask) {
+ var elem = src[srcPos++];
+ mask = 128;
+ }
+ dest[destPos] = (elem & mask) ? 0 : 255;
+ destPos += 4;
+ mask >>= 1;
+ }
+ }
+ ctx.putImageData(chunkImgData, 0, i * fullChunkHeight);
+ }
}
function copyCtxState(sourceCtx, destCtx) {
@@ -5814,6 +3693,93 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
}
+ function composeSMaskBackdrop(bytes, r0, g0, b0) {
+ var length = bytes.length;
+ for (var i = 3; i < length; i += 4) {
+ var alpha = bytes[i];
+ if (alpha === 0) {
+ bytes[i - 3] = r0;
+ bytes[i - 2] = g0;
+ bytes[i - 1] = b0;
+ } else if (alpha < 255) {
+ var alpha_ = 255 - alpha;
+ bytes[i - 3] = (bytes[i - 3] * alpha + r0 * alpha_) >> 8;
+ bytes[i - 2] = (bytes[i - 2] * alpha + g0 * alpha_) >> 8;
+ bytes[i - 1] = (bytes[i - 1] * alpha + b0 * alpha_) >> 8;
+ }
+ }
+ }
+
+ function composeSMaskAlpha(maskData, layerData) {
+ var length = maskData.length;
+ var scale = 1 / 255;
+ for (var i = 3; i < length; i += 4) {
+ var alpha = maskData[i];
+ layerData[i] = (layerData[i] * alpha * scale) | 0;
+ }
+ }
+
+ function composeSMaskLuminosity(maskData, layerData) {
+ var length = maskData.length;
+ for (var i = 3; i < length; i += 4) {
+ var y = ((maskData[i - 3] * 77) + // * 0.3 / 255 * 0x10000
+ (maskData[i - 2] * 152) + // * 0.59 ....
+ (maskData[i - 1] * 28)) | 0; // * 0.11 ....
+ layerData[i] = (layerData[i] * y) >> 16;
+ }
+ }
+
+ function genericComposeSMask(maskCtx, layerCtx, width, height,
+ subtype, backdrop) {
+ var hasBackdrop = !!backdrop;
+ var r0 = hasBackdrop ? backdrop[0] : 0;
+ var g0 = hasBackdrop ? backdrop[1] : 0;
+ var b0 = hasBackdrop ? backdrop[2] : 0;
+
+ var composeFn;
+ if (subtype === 'Luminosity') {
+ composeFn = composeSMaskLuminosity;
+ } else {
+ composeFn = composeSMaskAlpha;
+ }
+
+ // processing image in chunks to save memory
+ var PIXELS_TO_PROCESS = 65536;
+ var chunkSize = Math.min(height, Math.ceil(PIXELS_TO_PROCESS / width));
+ for (var row = 0; row < height; row += chunkSize) {
+ var chunkHeight = Math.min(chunkSize, height - row);
+ var maskData = maskCtx.getImageData(0, row, width, chunkHeight);
+ var layerData = layerCtx.getImageData(0, row, width, chunkHeight);
+
+ if (hasBackdrop) {
+ composeSMaskBackdrop(maskData.data, r0, g0, b0);
+ }
+ composeFn(maskData.data, layerData.data);
+
+ maskCtx.putImageData(layerData, 0, row);
+ }
+ }
+
+ function composeSMask(ctx, smask, layerCtx) {
+ var mask = smask.canvas;
+ var maskCtx = smask.context;
+
+ ctx.setTransform(smask.scaleX, 0, 0, smask.scaleY,
+ smask.offsetX, smask.offsetY);
+
+ var backdrop = smask.backdrop || null;
+ if (WebGLUtils.isEnabled) {
+ var composed = WebGLUtils.composeSMask(layerCtx.canvas, mask,
+ {subtype: smask.subtype, backdrop: backdrop});
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
+ ctx.drawImage(composed, smask.offsetX, smask.offsetY);
+ return;
+ }
+ genericComposeSMask(maskCtx, layerCtx, mask.width, mask.height,
+ smask.subtype, backdrop);
+ ctx.drawImage(mask, 0, 0);
+ }
+
var LINE_CAP_STYLES = ['butt', 'round', 'square'];
var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
var NORMAL_CLIP = {};
@@ -5840,13 +3806,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
var transform = viewport.transform;
- this.baseTransform = transform.slice();
+
this.ctx.save();
this.ctx.transform.apply(this.ctx, transform);
- if (this.textLayer) {
- this.textLayer.beginLayout();
- }
+ this.baseTransform = this.ctx.mozCurrentTransform.slice();
+
if (this.imageLayer) {
this.imageLayer.beginLayout();
}
@@ -5862,20 +3827,21 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var argsArrayLen = argsArray.length;
// Sometimes the OperatorList to execute is empty.
- if (argsArrayLen == i) {
+ if (argsArrayLen === i) {
return i;
}
- var executionEndIdx;
- var endTime = Date.now() + EXECUTION_TIME;
+ var chunkOperations = (argsArrayLen - i > EXECUTION_STEPS &&
+ typeof continueCallback === 'function');
+ var endTime = chunkOperations ? Date.now() + EXECUTION_TIME : 0;
+ var steps = 0;
var commonObjs = this.commonObjs;
var objs = this.objs;
var fnId;
- var deferred = Promise.resolve();
while (true) {
- if (stepper && i === stepper.nextBreakPoint) {
+ if (stepper !== undefined && i === stepper.nextBreakPoint) {
stepper.breakIt(i, continueCallback);
return i;
}
@@ -5888,16 +3854,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var deps = argsArray[i];
for (var n = 0, nn = deps.length; n < nn; n++) {
var depObjId = deps[n];
- var common = depObjId.substring(0, 2) == 'g_';
+ var common = depObjId[0] === 'g' && depObjId[1] === '_';
+ var objsPool = common ? commonObjs : objs;
// If the promise isn't resolved yet, add the continueCallback
// to the promise and bail out.
- if (!common && !objs.isResolved(depObjId)) {
- objs.get(depObjId, continueCallback);
- return i;
- }
- if (common && !commonObjs.isResolved(depObjId)) {
- commonObjs.get(depObjId, continueCallback);
+ if (!objsPool.isResolved(depObjId)) {
+ objsPool.get(depObjId, continueCallback);
return i;
}
}
@@ -5906,16 +3869,18 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
i++;
// If the entire operatorList was executed, stop as were done.
- if (i == argsArrayLen) {
+ if (i === argsArrayLen) {
return i;
}
- // If the execution took longer then a certain amount of time, schedule
- // to continue exeution after a short delay.
- // However, this is only possible if a 'continueCallback' is passed in.
- if (continueCallback && Date.now() > endTime) {
- deferred.then(continueCallback);
- return i;
+ // If the execution took longer then a certain amount of time and
+ // `continueCallback` is specified, interrupt the execution.
+ if (chunkOperations && ++steps > EXECUTION_STEPS) {
+ if (Date.now() > endTime) {
+ continueCallback();
+ return i;
+ }
+ steps = 0;
}
// If the operatorList isn't executed completely yet OR the execution
@@ -5926,10 +3891,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
endDrawing: function CanvasGraphics_endDrawing() {
this.ctx.restore();
CachedCanvases.clear();
+ WebGLUtils.clear();
- if (this.textLayer) {
- this.textLayer.endLayout();
- }
if (this.imageLayer) {
this.imageLayer.endLayout();
}
@@ -6022,19 +3985,69 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.globalCompositeOperation = 'source-over';
}
break;
+ case 'SMask':
+ if (this.current.activeSMask) {
+ this.endSMaskGroup();
+ }
+ this.current.activeSMask = value ? this.tempSMask : null;
+ if (this.current.activeSMask) {
+ this.beginSMaskGroup();
+ }
+ this.tempSMask = null;
+ break;
}
}
},
+ beginSMaskGroup: function CanvasGraphics_beginSMaskGroup() {
+
+ var activeSMask = this.current.activeSMask;
+ var drawnWidth = activeSMask.canvas.width;
+ var drawnHeight = activeSMask.canvas.height;
+ var cacheId = 'smaskGroupAt' + this.groupLevel;
+ var scratchCanvas = CachedCanvases.getCanvas(
+ cacheId, drawnWidth, drawnHeight, true);
+
+ var currentCtx = this.ctx;
+ var currentTransform = currentCtx.mozCurrentTransform;
+ this.ctx.save();
+
+ var groupCtx = scratchCanvas.context;
+ groupCtx.scale(1 / activeSMask.scaleX, 1 / activeSMask.scaleY);
+ groupCtx.translate(-activeSMask.offsetX, -activeSMask.offsetY);
+ groupCtx.transform.apply(groupCtx, currentTransform);
+
+ copyCtxState(currentCtx, groupCtx);
+ this.ctx = groupCtx;
+ this.setGState([
+ ['BM', 'Normal'],
+ ['ca', 1],
+ ['CA', 1]
+ ]);
+ this.groupStack.push(currentCtx);
+ this.groupLevel++;
+ },
+ endSMaskGroup: function CanvasGraphics_endSMaskGroup() {
+ var groupCtx = this.ctx;
+ this.groupLevel--;
+ this.ctx = this.groupStack.pop();
+
+ composeSMask(this.ctx, this.current.activeSMask, groupCtx);
+ this.ctx.restore();
+ },
save: function CanvasGraphics_save() {
this.ctx.save();
var old = this.current;
this.stateStack.push(old);
this.current = old.clone();
+ this.current.activeSMask = null;
},
restore: function CanvasGraphics_restore() {
- var prev = this.stateStack.pop();
- if (prev) {
- this.current = prev;
+ if (this.stateStack.length !== 0) {
+ if (this.current.activeSMask !== null) {
+ this.endSMaskGroup();
+ }
+
+ this.current = this.stateStack.pop();
this.ctx.restore();
}
},
@@ -6043,39 +4056,79 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
// Path
- moveTo: function CanvasGraphics_moveTo(x, y) {
- this.ctx.moveTo(x, y);
- this.current.setCurrentPoint(x, y);
- },
- lineTo: function CanvasGraphics_lineTo(x, y) {
- this.ctx.lineTo(x, y);
- this.current.setCurrentPoint(x, y);
- },
- curveTo: function CanvasGraphics_curveTo(x1, y1, x2, y2, x3, y3) {
- this.ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
- this.current.setCurrentPoint(x3, y3);
- },
- curveTo2: function CanvasGraphics_curveTo2(x2, y2, x3, y3) {
+ constructPath: function CanvasGraphics_constructPath(ops, args) {
+ var ctx = this.ctx;
var current = this.current;
- this.ctx.bezierCurveTo(current.x, current.y, x2, y2, x3, y3);
- current.setCurrentPoint(x3, y3);
- },
- curveTo3: function CanvasGraphics_curveTo3(x1, y1, x3, y3) {
- this.curveTo(x1, y1, x3, y3, x3, y3);
- this.current.setCurrentPoint(x3, y3);
+ var x = current.x, y = current.y;
+ for (var i = 0, j = 0, ii = ops.length; i < ii; i++) {
+ switch (ops[i] | 0) {
+ case OPS.rectangle:
+ x = args[j++];
+ y = args[j++];
+ var width = args[j++];
+ var height = args[j++];
+ if (width === 0) {
+ width = this.getSinglePixelWidth();
+ }
+ if (height === 0) {
+ height = this.getSinglePixelWidth();
+ }
+ var xw = x + width;
+ var yh = y + height;
+ this.ctx.moveTo(x, y);
+ this.ctx.lineTo(xw, y);
+ this.ctx.lineTo(xw, yh);
+ this.ctx.lineTo(x, yh);
+ this.ctx.lineTo(x, y);
+ this.ctx.closePath();
+ break;
+ case OPS.moveTo:
+ x = args[j++];
+ y = args[j++];
+ ctx.moveTo(x, y);
+ break;
+ case OPS.lineTo:
+ x = args[j++];
+ y = args[j++];
+ ctx.lineTo(x, y);
+ break;
+ case OPS.curveTo:
+ x = args[j + 4];
+ y = args[j + 5];
+ ctx.bezierCurveTo(args[j], args[j + 1], args[j + 2], args[j + 3],
+ x, y);
+ j += 6;
+ break;
+ case OPS.curveTo2:
+ ctx.bezierCurveTo(x, y, args[j], args[j + 1],
+ args[j + 2], args[j + 3]);
+ x = args[j + 2];
+ y = args[j + 3];
+ j += 4;
+ break;
+ case OPS.curveTo3:
+ x = args[j + 2];
+ y = args[j + 3];
+ ctx.bezierCurveTo(args[j], args[j + 1], x, y, x, y);
+ j += 4;
+ break;
+ case OPS.closePath:
+ ctx.closePath();
+ break;
+ }
+ }
+ current.setCurrentPoint(x, y);
},
closePath: function CanvasGraphics_closePath() {
this.ctx.closePath();
},
- rectangle: function CanvasGraphics_rectangle(x, y, width, height) {
- this.ctx.rect(x, y, width, height);
- },
stroke: function CanvasGraphics_stroke(consumePath) {
consumePath = typeof consumePath !== 'undefined' ? consumePath : true;
var ctx = this.ctx;
var strokeColor = this.current.strokeColor;
- if (this.current.lineWidth === 0)
+ if (this.current.lineWidth === 0) {
ctx.lineWidth = this.getSinglePixelWidth();
+ }
// For stroke we want to temporarily change the global alpha to the
// stroking alpha.
ctx.globalAlpha = this.current.strokeAlpha;
@@ -6090,8 +4143,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
} else {
ctx.stroke();
}
- if (consumePath)
+ if (consumePath) {
this.consumePath();
+ }
// Restore the global alpha to the fill alpha
ctx.globalAlpha = this.current.fillAlpha;
},
@@ -6113,21 +4167,21 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
if (this.pendingEOFill) {
- if ('mozFillRule' in this.ctx) {
- this.ctx.mozFillRule = 'evenodd';
- this.ctx.fill();
- this.ctx.mozFillRule = 'nonzero';
+ if (ctx.mozFillRule !== undefined) {
+ ctx.mozFillRule = 'evenodd';
+ ctx.fill();
+ ctx.mozFillRule = 'nonzero';
} else {
try {
- this.ctx.fill('evenodd');
+ ctx.fill('evenodd');
} catch (ex) {
// shouldn't really happen, but browsers might think differently
- this.ctx.fill();
+ ctx.fill();
}
}
this.pendingEOFill = false;
} else {
- this.ctx.fill();
+ ctx.fill();
}
if (needRestore) {
@@ -6175,16 +4229,17 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Text
beginText: function CanvasGraphics_beginText() {
this.current.textMatrix = IDENTITY_MATRIX;
+ this.current.textMatrixScale = 1;
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
},
endText: function CanvasGraphics_endText() {
- if (!('pendingTextPaths' in this)) {
- this.ctx.beginPath();
- return;
- }
var paths = this.pendingTextPaths;
var ctx = this.ctx;
+ if (paths === undefined) {
+ ctx.beginPath();
+ return;
+ }
ctx.save();
ctx.beginPath();
@@ -6215,11 +4270,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var fontObj = this.commonObjs.get(fontRefName);
var current = this.current;
- if (!fontObj)
+ if (!fontObj) {
error('Can\'t find font for ' + fontRefName);
+ }
- current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix :
- FONT_IDENTITY_MATRIX;
+ current.fontMatrix = (fontObj.fontMatrix ?
+ fontObj.fontMatrix : FONT_IDENTITY_MATRIX);
// A valid matrix needs all main diagonal elements to be non-zero
// This also ensures we bypass FF bugzilla bug #719844.
@@ -6240,8 +4296,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.current.font = fontObj;
this.current.fontSize = size;
- if (fontObj.coded)
+ if (fontObj.isType3Font) {
return; // we don't need ctx.font for Type3 fonts
+ }
var name = fontObj.loadedName || 'sans-serif';
var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
@@ -6255,7 +4312,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// the current transformation matrix before the fillText/strokeText.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=726227
var browserFontSize = size >= MIN_FONT_SIZE ? size : MIN_FONT_SIZE;
- this.current.fontSizeScale = browserFontSize != MIN_FONT_SIZE ? 1.0 :
+ this.current.fontSizeScale = browserFontSize !== MIN_FONT_SIZE ? 1.0 :
size / MIN_FONT_SIZE;
var rule = italic + ' ' + bold + ' ' + browserFontSize + 'px ' + typeface;
@@ -6277,6 +4334,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
},
setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
this.current.textMatrix = [a, b, c, d, e, f];
+ this.current.textMatrixScale = Math.sqrt(a * a + b * b);
this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0;
@@ -6284,49 +4342,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
nextLine: function CanvasGraphics_nextLine() {
this.moveText(0, this.current.leading);
},
- applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
- var ctx = this.ctx;
- var current = this.current;
- ctx.transform.apply(ctx, current.textMatrix);
- ctx.translate(current.x, current.y + current.textRise);
- if (current.fontDirection > 0) {
- ctx.scale(current.textHScale, -1);
- } else {
- ctx.scale(-current.textHScale, 1);
- }
- },
- createTextGeometry: function CanvasGraphics_createTextGeometry() {
- var geometry = {};
- var ctx = this.ctx;
- var font = this.current.font;
- var ctxMatrix = ctx.mozCurrentTransform;
- var a = ctxMatrix[0], b = ctxMatrix[1], c = ctxMatrix[2];
- var d = ctxMatrix[3], e = ctxMatrix[4], f = ctxMatrix[5];
- var sx = (a >= 0) ?
- Math.sqrt((a * a) + (b * b)) : -Math.sqrt((a * a) + (b * b));
- var sy = (d >= 0) ?
- Math.sqrt((c * c) + (d * d)) : -Math.sqrt((c * c) + (d * d));
- var angle = Math.atan2(b, a);
- var x = e;
- var y = f;
- geometry.x = x;
- geometry.y = y;
- geometry.hScale = sx;
- geometry.vScale = sy;
- geometry.angle = angle;
- geometry.spaceWidth = font.spaceWidth;
- geometry.fontName = font.loadedName;
- geometry.fontFamily = font.fallbackName;
- geometry.fontSize = this.current.fontSize;
- return geometry;
- },
- paintChar: function (character, x, y) {
+ paintChar: function CanvasGraphics_paintChar(character, x, y) {
var ctx = this.ctx;
var current = this.current;
var font = current.font;
- var fontSize = current.fontSize / current.fontSizeScale;
var textRenderingMode = current.textRenderingMode;
+ var fontSize = current.fontSize / current.fontSizeScale;
var fillStrokeMode = textRenderingMode &
TextRenderingMode.FILL_STROKE_MASK;
var isAddToPathSet = !!(textRenderingMode &
@@ -6374,234 +4396,205 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
},
- showText: function CanvasGraphics_showText(glyphs, skipTextSelection) {
- var ctx = this.ctx;
+ get isFontSubpixelAAEnabled() {
+ // Checks if anti-aliasing is enabled when scaled text is painted.
+ // On Windows GDI scaled fonts looks bad.
+ var ctx = document.createElement('canvas').getContext('2d');
+ ctx.scale(1.5, 1);
+ ctx.fillText('I', 0, 10);
+ var data = ctx.getImageData(0, 0, 10, 10).data;
+ var enabled = false;
+ for (var i = 3; i < data.length; i += 4) {
+ if (data[i] > 0 && data[i] < 255) {
+ enabled = true;
+ break;
+ }
+ }
+ return shadow(this, 'isFontSubpixelAAEnabled', enabled);
+ },
+
+ showText: function CanvasGraphics_showText(glyphs) {
var current = this.current;
var font = current.font;
+ if (font.isType3Font) {
+ return this.showType3Text(glyphs);
+ }
+
var fontSize = current.fontSize;
+ if (fontSize === 0) {
+ return;
+ }
+
+ var ctx = this.ctx;
var fontSizeScale = current.fontSizeScale;
var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing;
- var textHScale = current.textHScale * current.fontDirection;
- var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
+ var fontDirection = current.fontDirection;
+ var textHScale = current.textHScale * fontDirection;
var glyphsLength = glyphs.length;
- var textLayer = this.textLayer;
- var geom;
- var textSelection = textLayer && !skipTextSelection ? true : false;
- var canvasWidth = 0.0;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
+ var widthAdvanceScale = fontSize * current.fontMatrix[0];
- // Type3 fonts - each glyph is a "mini-PDF"
- if (font.coded) {
- ctx.save();
- ctx.transform.apply(ctx, current.textMatrix);
- ctx.translate(current.x, current.y);
+ var simpleFillText =
+ current.textRenderingMode === TextRenderingMode.FILL &&
+ !font.disableFontFace;
- ctx.scale(textHScale, 1);
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y + current.textRise);
- if (textSelection) {
- this.save();
- ctx.scale(1, -1);
- geom = this.createTextGeometry();
- this.restore();
- }
- for (var i = 0; i < glyphsLength; ++i) {
-
- var glyph = glyphs[i];
- if (glyph === null) {
- // word break
- this.ctx.translate(wordSpacing, 0);
- current.x += wordSpacing * textHScale;
- continue;
- }
-
- this.processingType3 = glyph;
- this.save();
- ctx.scale(fontSize, fontSize);
- ctx.transform.apply(ctx, fontMatrix);
- this.executeOperatorList(glyph.operatorList);
- this.restore();
-
- var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
- var width = (transformed[0] * fontSize + charSpacing) *
- current.fontDirection;
-
- ctx.translate(width, 0);
- current.x += width * textHScale;
-
- canvasWidth += width;
- }
- ctx.restore();
- this.processingType3 = null;
+ if (fontDirection > 0) {
+ ctx.scale(textHScale, -1);
} else {
- ctx.save();
- this.applyTextTransforms();
+ ctx.scale(textHScale, 1);
+ }
- var lineWidth = current.lineWidth;
- var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
- var scale = Math.sqrt(a1 * a1 + b1 * b1);
- if (scale === 0 || lineWidth === 0)
- lineWidth = this.getSinglePixelWidth();
- else
- lineWidth /= scale;
+ var lineWidth = current.lineWidth;
+ var scale = current.textMatrixScale;
+ if (scale === 0 || lineWidth === 0) {
+ lineWidth = this.getSinglePixelWidth();
+ } else {
+ lineWidth /= scale;
+ }
- if (textSelection)
- geom = this.createTextGeometry();
+ if (fontSizeScale !== 1.0) {
+ ctx.scale(fontSizeScale, fontSizeScale);
+ lineWidth /= fontSizeScale;
+ }
- if (fontSizeScale != 1.0) {
- ctx.scale(fontSizeScale, fontSizeScale);
- lineWidth /= fontSizeScale;
+ ctx.lineWidth = lineWidth;
+
+ var x = 0, i;
+ for (i = 0; i < glyphsLength; ++i) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ x += fontDirection * wordSpacing;
+ continue;
+ } else if (isNum(glyph)) {
+ x += -glyph * fontSize * 0.001;
+ continue;
}
- ctx.lineWidth = lineWidth;
-
- var x = 0;
- for (var i = 0; i < glyphsLength; ++i) {
- var glyph = glyphs[i];
- if (glyph === null) {
- // word break
- x += current.fontDirection * wordSpacing;
- continue;
- }
-
- var restoreNeeded = false;
- var character = glyph.fontChar;
- var vmetric = glyph.vmetric || defaultVMetrics;
- if (vertical) {
- var vx = glyph.vmetric ? vmetric[1] : glyph.width * 0.5;
- vx = -vx * fontSize * current.fontMatrix[0];
- var vy = vmetric[2] * fontSize * current.fontMatrix[0];
- }
- var width = vmetric ? -vmetric[0] : glyph.width;
- var charWidth = width * fontSize * current.fontMatrix[0] +
- charSpacing * current.fontDirection;
- var accent = glyph.accent;
-
- var scaledX, scaledY, scaledAccentX, scaledAccentY;
- if (!glyph.disabled) {
- if (vertical) {
- scaledX = vx / fontSizeScale;
- scaledY = (x + vy) / fontSizeScale;
- } else {
- scaledX = x / fontSizeScale;
- scaledY = 0;
- }
-
- if (font.remeasure && width > 0) {
- // some standard fonts may not have the exact width, trying to
- // rescale per character
- var measuredWidth = ctx.measureText(character).width * 1000 /
- current.fontSize * current.fontSizeScale;
- var characterScaleX = width / measuredWidth;
- restoreNeeded = true;
- ctx.save();
- ctx.scale(characterScaleX, 1);
- scaledX /= characterScaleX;
- if (accent) {
- scaledAccentX /= characterScaleX;
- }
- }
-
- this.paintChar(character, scaledX, scaledY);
- if (accent) {
- scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
- scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
- this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
- }
- }
-
- x += charWidth;
-
- canvasWidth += charWidth;
-
- if (restoreNeeded) {
- ctx.restore();
- }
- }
+ var restoreNeeded = false;
+ var character = glyph.fontChar;
+ var accent = glyph.accent;
+ var scaledX, scaledY, scaledAccentX, scaledAccentY;
+ var width = glyph.width;
if (vertical) {
- current.y -= x * textHScale;
+ var vmetric, vx, vy;
+ vmetric = glyph.vmetric || defaultVMetrics;
+ vx = glyph.vmetric ? vmetric[1] : width * 0.5;
+ vx = -vx * widthAdvanceScale;
+ vy = vmetric[2] * widthAdvanceScale;
+
+ width = vmetric ? -vmetric[0] : width;
+ scaledX = vx / fontSizeScale;
+ scaledY = (x + vy) / fontSizeScale;
} else {
- current.x += x * textHScale;
+ scaledX = x / fontSizeScale;
+ scaledY = 0;
}
- ctx.restore();
- }
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
+ if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
+ // some standard fonts may not have the exact width, trying to
+ // rescale per character
+ var measuredWidth = ctx.measureText(character).width * 1000 /
+ fontSize * fontSizeScale;
+ var characterScaleX = width / measuredWidth;
+ restoreNeeded = true;
+ ctx.save();
+ ctx.scale(characterScaleX, 1);
+ scaledX /= characterScaleX;
}
- this.textLayer.appendText(geom);
- }
- return canvasWidth;
+ if (simpleFillText && !accent) {
+ // common case
+ ctx.fillText(character, scaledX, scaledY);
+ } else {
+ this.paintChar(character, scaledX, scaledY);
+ if (accent) {
+ scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
+ scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
+ this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
+ }
+ }
+
+ var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
+ x += charWidth;
+
+ if (restoreNeeded) {
+ ctx.restore();
+ }
+ }
+ if (vertical) {
+ current.y -= x * textHScale;
+ } else {
+ current.x += x * textHScale;
+ }
+ ctx.restore();
},
- showSpacedText: function CanvasGraphics_showSpacedText(arr) {
+
+ showType3Text: function CanvasGraphics_showType3Text(glyphs) {
+ // Type3 fonts - each glyph is a "mini-PDF"
var ctx = this.ctx;
var current = this.current;
var font = current.font;
var fontSize = current.fontSize;
- // TJ array's number is independent from fontMatrix
- var textHScale = current.textHScale * 0.001 * current.fontDirection;
- var arrLength = arr.length;
- var textLayer = this.textLayer;
- var geom;
- var canvasWidth = 0.0;
- var textSelection = textLayer ? true : false;
- var vertical = font.vertical;
- var spacingAccumulator = 0;
+ var fontDirection = current.fontDirection;
+ var charSpacing = current.charSpacing;
+ var wordSpacing = current.wordSpacing;
+ var textHScale = current.textHScale * fontDirection;
+ var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
+ var glyphsLength = glyphs.length;
+ var i, glyph, width;
- if (textSelection) {
- ctx.save();
- this.applyTextTransforms();
- geom = this.createTextGeometry();
- ctx.restore();
+ if (fontSize === 0) {
+ return;
}
- for (var i = 0; i < arrLength; ++i) {
- var e = arr[i];
- if (isNum(e)) {
- var spacingLength = -e * fontSize * textHScale;
- if (vertical) {
- current.y += spacingLength;
- } else {
- current.x += spacingLength;
- }
+ ctx.save();
+ ctx.transform.apply(ctx, current.textMatrix);
+ ctx.translate(current.x, current.y);
- if (textSelection)
- spacingAccumulator += spacingLength;
- } else {
- var shownCanvasWidth = this.showText(e, true);
+ ctx.scale(textHScale, fontDirection);
- if (textSelection) {
- canvasWidth += spacingAccumulator + shownCanvasWidth;
- spacingAccumulator = 0;
- }
+ for (i = 0; i < glyphsLength; ++i) {
+ glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ this.ctx.translate(wordSpacing, 0);
+ current.x += wordSpacing * textHScale;
+ continue;
+ } else if (isNum(glyph)) {
+ var spacingLength = -glyph * 0.001 * fontSize;
+ this.ctx.translate(spacingLength, 0);
+ current.x += spacingLength * textHScale;
+ continue;
}
- }
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
+ var operatorList = font.charProcOperatorList[glyph.operatorListId];
+ if (!operatorList) {
+ warn('Type3 character \"' + glyph.operatorListId +
+ '\" is not available');
+ continue;
}
- this.textLayer.appendText(geom);
+ this.processingType3 = glyph;
+ this.save();
+ ctx.scale(fontSize, fontSize);
+ ctx.transform.apply(ctx, fontMatrix);
+ this.executeOperatorList(operatorList);
+ this.restore();
+
+ var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
+ width = transformed[0] * fontSize + charSpacing;
+
+ ctx.translate(width, 0);
+ current.x += width * textHScale;
}
- },
- nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
- this.nextLine();
- this.showText(text);
- },
- nextLineSetSpacingShowText:
- function CanvasGraphics_nextLineSetSpacingShowText(wordSpacing,
- charSpacing,
- text) {
- this.setWordSpacing(wordSpacing);
- this.setCharSpacing(charSpacing);
- this.nextLineShowText(text);
+ ctx.restore();
+ this.processingType3 = null;
},
// Type3 fonts
@@ -6617,112 +4610,36 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
ury) {
// TODO According to the spec we're also suppose to ignore any operators
// that set color or include images while processing this type3 font.
- this.rectangle(llx, lly, urx - llx, ury - lly);
+ this.ctx.rect(llx, lly, urx - llx, ury - lly);
this.clip();
this.endPath();
},
// Color
- setStrokeColorSpace: function CanvasGraphics_setStrokeColorSpace(raw) {
- this.current.strokeColorSpace = ColorSpace.fromIR(raw);
- },
- setFillColorSpace: function CanvasGraphics_setFillColorSpace(raw) {
- this.current.fillColorSpace = ColorSpace.fromIR(raw);
- },
- setStrokeColor: function CanvasGraphics_setStrokeColor(/*...*/) {
- var cs = this.current.strokeColorSpace;
- var rgbColor = cs.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR, cs) {
- if (IR[0] == 'TilingPattern') {
- var args = IR[1];
- var base = cs.base;
- var color;
- if (base) {
- var baseComps = base.numComps;
-
- color = base.getRgb(args, 0);
- }
- var pattern = new TilingPattern(IR, color, this.ctx, this.objs,
- this.commonObjs, this.baseTransform);
- } else if (IR[0] == 'RadialAxial' || IR[0] == 'Dummy') {
- var pattern = Pattern.shadingFromIR(IR);
+ getColorN_Pattern: function CanvasGraphics_getColorN_Pattern(IR) {
+ var pattern;
+ if (IR[0] === 'TilingPattern') {
+ var color = IR[1];
+ pattern = new TilingPattern(IR, color, this.ctx, this.objs,
+ this.commonObjs, this.baseTransform);
} else {
- error('Unkown IR type ' + IR[0]);
+ pattern = getShadingPatternFromIR(IR);
}
return pattern;
},
setStrokeColorN: function CanvasGraphics_setStrokeColorN(/*...*/) {
- var cs = this.current.strokeColorSpace;
-
- if (cs.name == 'Pattern') {
- this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
- } else {
- this.setStrokeColor.apply(this, arguments);
- }
- },
- setFillColor: function CanvasGraphics_setFillColor(/*...*/) {
- var cs = this.current.fillColorSpace;
- var rgbColor = cs.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
+ this.current.strokeColor = this.getColorN_Pattern(arguments);
},
setFillColorN: function CanvasGraphics_setFillColorN(/*...*/) {
- var cs = this.current.fillColorSpace;
-
- if (cs.name == 'Pattern') {
- this.current.fillColor = this.getColorN_Pattern(arguments, cs);
- } else {
- this.setFillColor.apply(this, arguments);
- }
- },
- setStrokeGray: function CanvasGraphics_setStrokeGray(gray) {
- this.current.strokeColorSpace = ColorSpace.singletons.gray;
-
- var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- setFillGray: function CanvasGraphics_setFillGray(gray) {
- this.current.fillColorSpace = ColorSpace.singletons.gray;
-
- var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
+ this.current.fillColor = this.getColorN_Pattern(arguments);
},
setStrokeRGBColor: function CanvasGraphics_setStrokeRGBColor(r, g, b) {
- this.current.strokeColorSpace = ColorSpace.singletons.rgb;
-
- var rgbColor = this.current.strokeColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
+ var color = Util.makeCssRgb(arguments);
this.ctx.strokeStyle = color;
this.current.strokeColor = color;
},
setFillRGBColor: function CanvasGraphics_setFillRGBColor(r, g, b) {
- this.current.fillColorSpace = ColorSpace.singletons.rgb;
-
- var rgbColor = this.current.fillColorSpace.getRgb(arguments, 0);
- var color = Util.makeCssRgb(rgbColor);
- this.ctx.fillStyle = color;
- this.current.fillColor = color;
- },
- setStrokeCMYKColor: function CanvasGraphics_setStrokeCMYKColor(c, m, y, k) {
- this.current.strokeColorSpace = ColorSpace.singletons.cmyk;
-
- var color = Util.makeCssCmyk(arguments);
- this.ctx.strokeStyle = color;
- this.current.strokeColor = color;
- },
- setFillCMYKColor: function CanvasGraphics_setFillCMYKColor(c, m, y, k) {
- this.current.fillColorSpace = ColorSpace.singletons.cmyk;
-
- var color = Util.makeCssCmyk(arguments);
+ var color = Util.makeCssRgb(arguments);
this.ctx.fillStyle = color;
this.current.fillColor = color;
},
@@ -6731,8 +4648,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var ctx = this.ctx;
this.save();
- var pattern = Pattern.shadingFromIR(patternIR);
- ctx.fillStyle = pattern.getPattern(ctx, this);
+ var pattern = getShadingPatternFromIR(patternIR);
+ ctx.fillStyle = pattern.getPattern(ctx, this, true);
var inv = ctx.mozCurrentTransformInverse;
if (inv) {
@@ -6775,30 +4692,25 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintFormXObjectBegin: function CanvasGraphics_paintFormXObjectBegin(matrix,
bbox) {
this.save();
- this.current.paintFormXObjectDepth++;
this.baseTransformStack.push(this.baseTransform);
- if (matrix && isArray(matrix) && 6 == matrix.length)
+ if (isArray(matrix) && 6 === matrix.length) {
this.transform.apply(this, matrix);
+ }
this.baseTransform = this.ctx.mozCurrentTransform;
- if (bbox && isArray(bbox) && 4 == bbox.length) {
+ if (isArray(bbox) && 4 === bbox.length) {
var width = bbox[2] - bbox[0];
var height = bbox[3] - bbox[1];
- this.rectangle(bbox[0], bbox[1], width, height);
+ this.ctx.rect(bbox[0], bbox[1], width, height);
this.clip();
this.endPath();
}
},
paintFormXObjectEnd: function CanvasGraphics_paintFormXObjectEnd() {
- var depth = this.current.paintFormXObjectDepth;
- do {
- this.restore();
- // some pdf don't close all restores inside object
- // closing those for them
- } while (this.current.paintFormXObjectDepth >= depth);
+ this.restore();
this.baseTransform = this.baseTransformStack.pop();
},
@@ -6847,29 +4759,59 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
bounds = Util.intersect(bounds, canvasBounds) || [0, 0, 0, 0];
// Use ceil in case we're between sizes so we don't create canvas that is
// too small and make the canvas at least 1x1 pixels.
- var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
- var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
+ var offsetX = Math.floor(bounds[0]);
+ var offsetY = Math.floor(bounds[1]);
+ var drawnWidth = Math.max(Math.ceil(bounds[2]) - offsetX, 1);
+ var drawnHeight = Math.max(Math.ceil(bounds[3]) - offsetY, 1);
+ var scaleX = 1, scaleY = 1;
+ if (drawnWidth > MAX_GROUP_SIZE) {
+ scaleX = drawnWidth / MAX_GROUP_SIZE;
+ drawnWidth = MAX_GROUP_SIZE;
+ }
+ if (drawnHeight > MAX_GROUP_SIZE) {
+ scaleY = drawnHeight / MAX_GROUP_SIZE;
+ drawnHeight = MAX_GROUP_SIZE;
+ }
+ var cacheId = 'groupAt' + this.groupLevel;
+ if (group.smask) {
+ // Using two cache entries is case if masks are used one after another.
+ cacheId += '_smask_' + ((this.smaskCounter++) % 2);
+ }
var scratchCanvas = CachedCanvases.getCanvas(
- 'groupAt' + this.groupLevel, drawnWidth, drawnHeight, true);
+ cacheId, drawnWidth, drawnHeight, true);
var groupCtx = scratchCanvas.context;
+
// Since we created a new canvas that is just the size of the bounding box
// we have to translate the group ctx.
- var offsetX = bounds[0];
- var offsetY = bounds[1];
+ groupCtx.scale(1 / scaleX, 1 / scaleY);
groupCtx.translate(-offsetX, -offsetY);
groupCtx.transform.apply(groupCtx, currentTransform);
- // Setup the current ctx so when the group is popped we draw it the right
- // location.
- currentCtx.setTransform(1, 0, 0, 1, 0, 0);
- currentCtx.translate(offsetX, offsetY);
+ if (group.smask) {
+ // Saving state and cached mask to be used in setGState.
+ this.smaskStack.push({
+ canvas: scratchCanvas.canvas,
+ context: groupCtx,
+ offsetX: offsetX,
+ offsetY: offsetY,
+ scaleX: scaleX,
+ scaleY: scaleY,
+ subtype: group.smask.subtype,
+ backdrop: group.smask.backdrop
+ });
+ } else {
+ // Setup the current ctx so when the group is popped we draw it at the
+ // right location.
+ currentCtx.setTransform(1, 0, 0, 1, 0, 0);
+ currentCtx.translate(offsetX, offsetY);
+ currentCtx.scale(scaleX, scaleY);
+ }
// The transparency group inherits all off the current graphics state
// except the blend mode, soft mask, and alpha constants.
copyCtxState(currentCtx, groupCtx);
this.ctx = groupCtx;
this.setGState([
- ['SMask', 'None'],
['BM', 'Normal'],
['ca', 1],
['CA', 1]
@@ -6884,12 +4826,16 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx = this.groupStack.pop();
// Turn off image smoothing to avoid sub pixel interpolation which can
// look kind of blurry for some pdfs.
- if ('imageSmoothingEnabled' in this.ctx) {
+ if (this.ctx.imageSmoothingEnabled !== undefined) {
this.ctx.imageSmoothingEnabled = false;
} else {
this.ctx.mozImageSmoothingEnabled = false;
}
- this.ctx.drawImage(groupCtx.canvas, 0, 0);
+ if (group.smask) {
+ this.tempSMask = this.smaskStack.pop();
+ } else {
+ this.ctx.drawImage(groupCtx.canvas, 0, 0);
+ }
this.restore();
},
@@ -6906,10 +4852,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
matrix) {
this.save();
- if (rect && isArray(rect) && 4 == rect.length) {
+ if (isArray(rect) && 4 === rect.length) {
var width = rect[2] - rect[0];
var height = rect[3] - rect[1];
- this.rectangle(rect[0], rect[1], width, height);
+ this.ctx.rect(rect[0], rect[1], width, height);
this.clip();
this.endPath();
}
@@ -6925,7 +4871,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintJpegXObject: function CanvasGraphics_paintJpegXObject(objId, w, h) {
var domImage = this.objs.get(objId);
if (!domImage) {
- error('Dependent image isn\'t ready yet');
+ warn('Dependent image isn\'t ready yet');
+ return;
}
this.save();
@@ -6975,7 +4922,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var maskCtx = maskCanvas.context;
maskCtx.save();
- putBinaryImageData(maskCtx, img);
+ putBinaryImageMask(maskCtx, img);
maskCtx.globalCompositeOperation = 'source-in';
@@ -6990,6 +4937,39 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.paintInlineImageXObject(maskCanvas.canvas);
},
+ paintImageMaskXObjectRepeat:
+ function CanvasGraphics_paintImageMaskXObjectRepeat(imgData, scaleX,
+ scaleY, positions) {
+ var width = imgData.width;
+ var height = imgData.height;
+ var ctx = this.ctx;
+
+ var maskCanvas = CachedCanvases.getCanvas('maskCanvas', width, height);
+ var maskCtx = maskCanvas.context;
+ maskCtx.save();
+
+ putBinaryImageMask(maskCtx, imgData);
+
+ maskCtx.globalCompositeOperation = 'source-in';
+
+ var fillColor = this.current.fillColor;
+ maskCtx.fillStyle = (fillColor && fillColor.hasOwnProperty('type') &&
+ fillColor.type === 'Pattern') ?
+ fillColor.getPattern(maskCtx, this) : fillColor;
+ maskCtx.fillRect(0, 0, width, height);
+
+ maskCtx.restore();
+
+ for (var i = 0, ii = positions.length; i < ii; i += 2) {
+ ctx.save();
+ ctx.transform(scaleX, 0, 0, scaleY, positions[i], positions[i + 1]);
+ ctx.scale(1, -1);
+ ctx.drawImage(maskCanvas.canvas, 0, 0, width, height,
+ 0, -1, 1, 1);
+ ctx.restore();
+ }
+ },
+
paintImageMaskXObjectGroup:
function CanvasGraphics_paintImageMaskXObjectGroup(images) {
var ctx = this.ctx;
@@ -7002,7 +4982,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var maskCtx = maskCanvas.context;
maskCtx.save();
- putBinaryImageData(maskCtx, image);
+ putBinaryImageMask(maskCtx, image);
maskCtx.globalCompositeOperation = 'source-in';
@@ -7025,12 +5005,33 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
paintImageXObject: function CanvasGraphics_paintImageXObject(objId) {
var imgData = this.objs.get(objId);
- if (!imgData)
- error('Dependent image isn\'t ready yet');
+ if (!imgData) {
+ warn('Dependent image isn\'t ready yet');
+ return;
+ }
this.paintInlineImageXObject(imgData);
},
+ paintImageXObjectRepeat:
+ function CanvasGraphics_paintImageXObjectRepeat(objId, scaleX, scaleY,
+ positions) {
+ var imgData = this.objs.get(objId);
+ if (!imgData) {
+ warn('Dependent image isn\'t ready yet');
+ return;
+ }
+
+ var width = imgData.width;
+ var height = imgData.height;
+ var map = [];
+ for (var i = 0, ii = positions.length; i < ii; i += 2) {
+ map.push({transform: [scaleX, 0, 0, scaleY, positions[i],
+ positions[i + 1]], x: 0, y: 0, w: width, h: height});
+ }
+ this.paintInlineImageXObjectGroup(imgData, map);
+ },
+
paintInlineImageXObject:
function CanvasGraphics_paintInlineImageXObject(imgData) {
var width = imgData.width;
@@ -7047,12 +5048,12 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var c = currentTransform[2], d = currentTransform[3];
var heightScale = Math.max(Math.sqrt(c * c + d * d), 1);
- var imgToPaint;
+ var imgToPaint, tmpCanvas;
// instanceof HTMLElement does not work in jsdom node.js module
if (imgData instanceof HTMLElement || !imgData.data) {
imgToPaint = imgData;
} else {
- var tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
+ tmpCanvas = CachedCanvases.getCanvas('inlineImage', width, height);
var tmpCtx = tmpCanvas.context;
putBinaryImageData(tmpCtx, imgData);
imgToPaint = tmpCanvas.canvas;
@@ -7074,8 +5075,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
newHeight = Math.ceil(paintHeight / 2);
heightScale /= paintHeight / newHeight;
}
- var tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId,
- newWidth, newHeight);
+ tmpCanvas = CachedCanvases.getCanvas(tmpCanvasId, newWidth, newHeight);
tmpCtx = tmpCanvas.context;
tmpCtx.clearRect(0, 0, newWidth, newHeight);
tmpCtx.drawImage(imgToPaint, 0, 0, paintWidth, paintHeight,
@@ -7132,6 +5132,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
},
+ paintSolidColorImageMask:
+ function CanvasGraphics_paintSolidColorImageMask() {
+ this.ctx.fillRect(0, 0, 1, 1);
+ },
+
// Marked content
markPoint: function CanvasGraphics_markPoint(tag) {
@@ -7163,26 +5168,27 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Helper functions
consumePath: function CanvasGraphics_consumePath() {
+ var ctx = this.ctx;
if (this.pendingClip) {
- if (this.pendingClip == EO_CLIP) {
- if ('mozFillRule' in this.ctx) {
- this.ctx.mozFillRule = 'evenodd';
- this.ctx.clip();
- this.ctx.mozFillRule = 'nonzero';
+ if (this.pendingClip === EO_CLIP) {
+ if (ctx.mozFillRule !== undefined) {
+ ctx.mozFillRule = 'evenodd';
+ ctx.clip();
+ ctx.mozFillRule = 'nonzero';
} else {
try {
- this.ctx.clip('evenodd');
+ ctx.clip('evenodd');
} catch (ex) {
// shouldn't really happen, but browsers might think differently
- this.ctx.clip();
+ ctx.clip();
}
}
} else {
- this.ctx.clip();
+ ctx.clip();
}
this.pendingClip = null;
}
- this.ctx.beginPath();
+ ctx.beginPath();
},
getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) {
var inverse = this.ctx.mozCurrentTransformInverse;
@@ -7209,26 +5215,855 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
+var WebGLUtils = (function WebGLUtilsClosure() {
+ function loadShader(gl, code, shaderType) {
+ var shader = gl.createShader(shaderType);
+ gl.shaderSource(shader, code);
+ gl.compileShader(shader);
+ var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
+ if (!compiled) {
+ var errorMsg = gl.getShaderInfoLog(shader);
+ throw new Error('Error during shader compilation: ' + errorMsg);
+ }
+ return shader;
+ }
+ function createVertexShader(gl, code) {
+ return loadShader(gl, code, gl.VERTEX_SHADER);
+ }
+ function createFragmentShader(gl, code) {
+ return loadShader(gl, code, gl.FRAGMENT_SHADER);
+ }
+ function createProgram(gl, shaders) {
+ var program = gl.createProgram();
+ for (var i = 0, ii = shaders.length; i < ii; ++i) {
+ gl.attachShader(program, shaders[i]);
+ }
+ gl.linkProgram(program);
+ var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
+ if (!linked) {
+ var errorMsg = gl.getProgramInfoLog(program);
+ throw new Error('Error during program linking: ' + errorMsg);
+ }
+ return program;
+ }
+ function createTexture(gl, image, textureId) {
+ gl.activeTexture(textureId);
+ var texture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+
+ // Set the parameters so we can render any size image.
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+ // Upload the image into the texture.
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
+ return texture;
+ }
+
+ var currentGL, currentCanvas;
+ function generageGL() {
+ if (currentGL) {
+ return;
+ }
+ currentCanvas = document.createElement('canvas');
+ currentGL = currentCanvas.getContext('webgl',
+ { premultipliedalpha: false });
+ }
+
+ var smaskVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec2 a_texCoord; \
+ \
+ uniform vec2 u_resolution; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec2 clipSpace = (a_position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_texCoord = a_texCoord; \
+ } ';
+
+ var smaskFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ uniform vec4 u_backdrop; \
+ uniform int u_subtype; \
+ uniform sampler2D u_image; \
+ uniform sampler2D u_mask; \
+ \
+ varying vec2 v_texCoord; \
+ \
+ void main() { \
+ vec4 imageColor = texture2D(u_image, v_texCoord); \
+ vec4 maskColor = texture2D(u_mask, v_texCoord); \
+ if (u_backdrop.a > 0.0) { \
+ maskColor.rgb = maskColor.rgb * maskColor.a + \
+ u_backdrop.rgb * (1.0 - maskColor.a); \
+ } \
+ float lum; \
+ if (u_subtype == 0) { \
+ lum = maskColor.a; \
+ } else { \
+ lum = maskColor.r * 0.3 + maskColor.g * 0.59 + \
+ maskColor.b * 0.11; \
+ } \
+ imageColor.a *= lum; \
+ imageColor.rgb *= imageColor.a; \
+ gl_FragColor = imageColor; \
+ } ';
+
+ var smaskCache = null;
+
+ function initSmaskGL() {
+ var canvas, gl;
+
+ generageGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, smaskVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, smaskFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.backdropLocation = gl.getUniformLocation(program, 'u_backdrop');
+ cache.subtypeLocation = gl.getUniformLocation(program, 'u_subtype');
+
+ var texCoordLocation = gl.getAttribLocation(program, 'a_texCoord');
+ var texLayerLocation = gl.getUniformLocation(program, 'u_image');
+ var texMaskLocation = gl.getUniformLocation(program, 'u_mask');
+
+ // provide texture coordinates for the rectangle.
+ var texCoordBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(texCoordLocation);
+ gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
+
+ gl.uniform1i(texLayerLocation, 0);
+ gl.uniform1i(texMaskLocation, 1);
+
+ smaskCache = cache;
+ }
+
+ function composeSMask(layer, mask, properties) {
+ var width = layer.width, height = layer.height;
+
+ if (!smaskCache) {
+ initSmaskGL();
+ }
+ var cache = smaskCache,canvas = cache.canvas, gl = cache.gl;
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ if (properties.backdrop) {
+ gl.uniform4f(cache.resolutionLocation, properties.backdrop[0],
+ properties.backdrop[1], properties.backdrop[2], 1);
+ } else {
+ gl.uniform4f(cache.resolutionLocation, 0, 0, 0, 0);
+ }
+ gl.uniform1i(cache.subtypeLocation,
+ properties.subtype === 'Luminosity' ? 1 : 0);
+
+ // Create a textures
+ var texture = createTexture(gl, layer, gl.TEXTURE0);
+ var maskTexture = createTexture(gl, mask, gl.TEXTURE1);
+
+
+ // Create a buffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ 0, 0,
+ width, 0,
+ 0, height,
+ 0, height,
+ width, 0,
+ width, height]), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ // draw
+ gl.clearColor(0, 0, 0, 0);
+ gl.enable(gl.BLEND);
+ gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ gl.flush();
+
+ gl.deleteTexture(texture);
+ gl.deleteTexture(maskTexture);
+ gl.deleteBuffer(buffer);
+
+ return canvas;
+ }
+
+ var figuresVertexShaderCode = '\
+ attribute vec2 a_position; \
+ attribute vec3 a_color; \
+ \
+ uniform vec2 u_resolution; \
+ uniform vec2 u_scale; \
+ uniform vec2 u_offset; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ vec2 position = (a_position + u_offset) * u_scale; \
+ vec2 clipSpace = (position / u_resolution) * 2.0 - 1.0; \
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); \
+ \
+ v_color = vec4(a_color / 255.0, 1.0); \
+ } ';
+
+ var figuresFragmentShaderCode = '\
+ precision mediump float; \
+ \
+ varying vec4 v_color; \
+ \
+ void main() { \
+ gl_FragColor = v_color; \
+ } ';
+
+ var figuresCache = null;
+
+ function initFiguresGL() {
+ var canvas, gl;
+
+ generageGL();
+ canvas = currentCanvas;
+ currentCanvas = null;
+ gl = currentGL;
+ currentGL = null;
+
+ // setup a GLSL program
+ var vertexShader = createVertexShader(gl, figuresVertexShaderCode);
+ var fragmentShader = createFragmentShader(gl, figuresFragmentShaderCode);
+ var program = createProgram(gl, [vertexShader, fragmentShader]);
+ gl.useProgram(program);
+
+ var cache = {};
+ cache.gl = gl;
+ cache.canvas = canvas;
+ cache.resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
+ cache.scaleLocation = gl.getUniformLocation(program, 'u_scale');
+ cache.offsetLocation = gl.getUniformLocation(program, 'u_offset');
+ cache.positionLocation = gl.getAttribLocation(program, 'a_position');
+ cache.colorLocation = gl.getAttribLocation(program, 'a_color');
+
+ figuresCache = cache;
+ }
+
+ function drawFigures(width, height, backgroundColor, figures, context) {
+ if (!figuresCache) {
+ initFiguresGL();
+ }
+ var cache = figuresCache, canvas = cache.canvas, gl = cache.gl;
+
+ canvas.width = width;
+ canvas.height = height;
+ gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
+ gl.uniform2f(cache.resolutionLocation, width, height);
+
+ // count triangle points
+ var count = 0;
+ var i, ii, rows;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ switch (figures[i].type) {
+ case 'lattice':
+ rows = (figures[i].coords.length / figures[i].verticesPerRow) | 0;
+ count += (rows - 1) * (figures[i].verticesPerRow - 1) * 6;
+ break;
+ case 'triangles':
+ count += figures[i].coords.length;
+ break;
+ }
+ }
+ // transfer data
+ var coords = new Float32Array(count * 2);
+ var colors = new Uint8Array(count * 3);
+ var coordsMap = context.coords, colorsMap = context.colors;
+ var pIndex = 0, cIndex = 0;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ var figure = figures[i], ps = figure.coords, cs = figure.colors;
+ switch (figure.type) {
+ case 'lattice':
+ var cols = figure.verticesPerRow;
+ rows = (ps.length / cols) | 0;
+ for (var row = 1; row < rows; row++) {
+ var offset = row * cols + 1;
+ for (var col = 1; col < cols; col++, offset++) {
+ coords[pIndex] = coordsMap[ps[offset - cols - 1]];
+ coords[pIndex + 1] = coordsMap[ps[offset - cols - 1] + 1];
+ coords[pIndex + 2] = coordsMap[ps[offset - cols]];
+ coords[pIndex + 3] = coordsMap[ps[offset - cols] + 1];
+ coords[pIndex + 4] = coordsMap[ps[offset - 1]];
+ coords[pIndex + 5] = coordsMap[ps[offset - 1] + 1];
+ colors[cIndex] = colorsMap[cs[offset - cols - 1]];
+ colors[cIndex + 1] = colorsMap[cs[offset - cols - 1] + 1];
+ colors[cIndex + 2] = colorsMap[cs[offset - cols - 1] + 2];
+ colors[cIndex + 3] = colorsMap[cs[offset - cols]];
+ colors[cIndex + 4] = colorsMap[cs[offset - cols] + 1];
+ colors[cIndex + 5] = colorsMap[cs[offset - cols] + 2];
+ colors[cIndex + 6] = colorsMap[cs[offset - 1]];
+ colors[cIndex + 7] = colorsMap[cs[offset - 1] + 1];
+ colors[cIndex + 8] = colorsMap[cs[offset - 1] + 2];
+
+ coords[pIndex + 6] = coords[pIndex + 2];
+ coords[pIndex + 7] = coords[pIndex + 3];
+ coords[pIndex + 8] = coords[pIndex + 4];
+ coords[pIndex + 9] = coords[pIndex + 5];
+ coords[pIndex + 10] = coordsMap[ps[offset]];
+ coords[pIndex + 11] = coordsMap[ps[offset] + 1];
+ colors[cIndex + 9] = colors[cIndex + 3];
+ colors[cIndex + 10] = colors[cIndex + 4];
+ colors[cIndex + 11] = colors[cIndex + 5];
+ colors[cIndex + 12] = colors[cIndex + 6];
+ colors[cIndex + 13] = colors[cIndex + 7];
+ colors[cIndex + 14] = colors[cIndex + 8];
+ colors[cIndex + 15] = colorsMap[cs[offset]];
+ colors[cIndex + 16] = colorsMap[cs[offset] + 1];
+ colors[cIndex + 17] = colorsMap[cs[offset] + 2];
+ pIndex += 12;
+ cIndex += 18;
+ }
+ }
+ break;
+ case 'triangles':
+ for (var j = 0, jj = ps.length; j < jj; j++) {
+ coords[pIndex] = coordsMap[ps[j]];
+ coords[pIndex + 1] = coordsMap[ps[j] + 1];
+ colors[cIndex] = colorsMap[cs[i]];
+ colors[cIndex + 1] = colorsMap[cs[j] + 1];
+ colors[cIndex + 2] = colorsMap[cs[j] + 2];
+ pIndex += 2;
+ cIndex += 3;
+ }
+ break;
+ }
+ }
+
+ // draw
+ if (backgroundColor) {
+ gl.clearColor(backgroundColor[0] / 255, backgroundColor[1] / 255,
+ backgroundColor[2] / 255, 1.0);
+ } else {
+ gl.clearColor(0, 0, 0, 0);
+ }
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ var coordsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, coordsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, coords, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.positionLocation);
+ gl.vertexAttribPointer(cache.positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ var colorsBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorsBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(cache.colorLocation);
+ gl.vertexAttribPointer(cache.colorLocation, 3, gl.UNSIGNED_BYTE, false,
+ 0, 0);
+
+ gl.uniform2f(cache.scaleLocation, context.scaleX, context.scaleY);
+ gl.uniform2f(cache.offsetLocation, context.offsetX, context.offsetY);
+
+ gl.drawArrays(gl.TRIANGLES, 0, count);
+
+ gl.flush();
+
+ gl.deleteBuffer(coordsBuffer);
+ gl.deleteBuffer(colorsBuffer);
+
+ return canvas;
+ }
+
+ function cleanup() {
+ if (smaskCache && smaskCache.canvas) {
+ smaskCache.canvas.width = 0;
+ smaskCache.canvas.height = 0;
+ }
+ if (figuresCache && figuresCache.canvas) {
+ figuresCache.canvas.width = 0;
+ figuresCache.canvas.height = 0;
+ }
+ smaskCache = null;
+ figuresCache = null;
+ }
+
+ return {
+ get isEnabled() {
+ if (PDFJS.disableWebGL) {
+ return false;
+ }
+ var enabled = false;
+ try {
+ generageGL();
+ enabled = !!currentGL;
+ } catch (e) { }
+ return shadow(this, 'isEnabled', enabled);
+ },
+ composeSMask: composeSMask,
+ drawFigures: drawFigures,
+ clear: cleanup
+ };
+})();
+
+
+var ShadingIRs = {};
+
+ShadingIRs.RadialAxial = {
+ fromIR: function RadialAxial_fromIR(raw) {
+ var type = raw[1];
+ var colorStops = raw[2];
+ var p0 = raw[3];
+ var p1 = raw[4];
+ var r0 = raw[5];
+ var r1 = raw[6];
+ return {
+ type: 'Pattern',
+ getPattern: function RadialAxial_getPattern(ctx) {
+ var grad;
+ if (type === 'axial') {
+ grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
+ } else if (type === 'radial') {
+ grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
+ }
+
+ for (var i = 0, ii = colorStops.length; i < ii; ++i) {
+ var c = colorStops[i];
+ grad.addColorStop(c[0], c[1]);
+ }
+ return grad;
+ }
+ };
+ }
+};
+
+var createMeshCanvas = (function createMeshCanvasClosure() {
+ function drawTriangle(data, context, p1, p2, p3, c1, c2, c3) {
+ // Very basic Gouraud-shaded triangle rasterization algorithm.
+ var coords = context.coords, colors = context.colors;
+ var bytes = data.data, rowSize = data.width * 4;
+ var tmp;
+ if (coords[p1 + 1] > coords[p2 + 1]) {
+ tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
+ }
+ if (coords[p2 + 1] > coords[p3 + 1]) {
+ tmp = p2; p2 = p3; p3 = tmp; tmp = c2; c2 = c3; c3 = tmp;
+ }
+ if (coords[p1 + 1] > coords[p2 + 1]) {
+ tmp = p1; p1 = p2; p2 = tmp; tmp = c1; c1 = c2; c2 = tmp;
+ }
+ var x1 = (coords[p1] + context.offsetX) * context.scaleX;
+ var y1 = (coords[p1 + 1] + context.offsetY) * context.scaleY;
+ var x2 = (coords[p2] + context.offsetX) * context.scaleX;
+ var y2 = (coords[p2 + 1] + context.offsetY) * context.scaleY;
+ var x3 = (coords[p3] + context.offsetX) * context.scaleX;
+ var y3 = (coords[p3 + 1] + context.offsetY) * context.scaleY;
+ if (y1 >= y3) {
+ return;
+ }
+ var c1r = colors[c1], c1g = colors[c1 + 1], c1b = colors[c1 + 2];
+ var c2r = colors[c2], c2g = colors[c2 + 1], c2b = colors[c2 + 2];
+ var c3r = colors[c3], c3g = colors[c3 + 1], c3b = colors[c3 + 2];
+
+ var minY = Math.round(y1), maxY = Math.round(y3);
+ var xa, car, cag, cab;
+ var xb, cbr, cbg, cbb;
+ var k;
+ for (var y = minY; y <= maxY; y++) {
+ if (y < y2) {
+ k = y < y1 ? 0 : y1 === y2 ? 1 : (y1 - y) / (y1 - y2);
+ xa = x1 - (x1 - x2) * k;
+ car = c1r - (c1r - c2r) * k;
+ cag = c1g - (c1g - c2g) * k;
+ cab = c1b - (c1b - c2b) * k;
+ } else {
+ k = y > y3 ? 1 : y2 === y3 ? 0 : (y2 - y) / (y2 - y3);
+ xa = x2 - (x2 - x3) * k;
+ car = c2r - (c2r - c3r) * k;
+ cag = c2g - (c2g - c3g) * k;
+ cab = c2b - (c2b - c3b) * k;
+ }
+ k = y < y1 ? 0 : y > y3 ? 1 : (y1 - y) / (y1 - y3);
+ xb = x1 - (x1 - x3) * k;
+ cbr = c1r - (c1r - c3r) * k;
+ cbg = c1g - (c1g - c3g) * k;
+ cbb = c1b - (c1b - c3b) * k;
+ var x1_ = Math.round(Math.min(xa, xb));
+ var x2_ = Math.round(Math.max(xa, xb));
+ var j = rowSize * y + x1_ * 4;
+ for (var x = x1_; x <= x2_; x++) {
+ k = (xa - x) / (xa - xb);
+ k = k < 0 ? 0 : k > 1 ? 1 : k;
+ bytes[j++] = (car - (car - cbr) * k) | 0;
+ bytes[j++] = (cag - (cag - cbg) * k) | 0;
+ bytes[j++] = (cab - (cab - cbb) * k) | 0;
+ bytes[j++] = 255;
+ }
+ }
+ }
+
+ function drawFigure(data, figure, context) {
+ var ps = figure.coords;
+ var cs = figure.colors;
+ var i, ii;
+ switch (figure.type) {
+ case 'lattice':
+ var verticesPerRow = figure.verticesPerRow;
+ var rows = Math.floor(ps.length / verticesPerRow) - 1;
+ var cols = verticesPerRow - 1;
+ for (i = 0; i < rows; i++) {
+ var q = i * verticesPerRow;
+ for (var j = 0; j < cols; j++, q++) {
+ drawTriangle(data, context,
+ ps[q], ps[q + 1], ps[q + verticesPerRow],
+ cs[q], cs[q + 1], cs[q + verticesPerRow]);
+ drawTriangle(data, context,
+ ps[q + verticesPerRow + 1], ps[q + 1], ps[q + verticesPerRow],
+ cs[q + verticesPerRow + 1], cs[q + 1], cs[q + verticesPerRow]);
+ }
+ }
+ break;
+ case 'triangles':
+ for (i = 0, ii = ps.length; i < ii; i += 3) {
+ drawTriangle(data, context,
+ ps[i], ps[i + 1], ps[i + 2],
+ cs[i], cs[i + 1], cs[i + 2]);
+ }
+ break;
+ default:
+ error('illigal figure');
+ break;
+ }
+ }
+
+ function createMeshCanvas(bounds, combinesScale, coords, colors, figures,
+ backgroundColor) {
+ // we will increase scale on some weird factor to let antialiasing take
+ // care of "rough" edges
+ var EXPECTED_SCALE = 1.1;
+ // MAX_PATTERN_SIZE is used to avoid OOM situation.
+ var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
+
+ var offsetX = Math.floor(bounds[0]);
+ var offsetY = Math.floor(bounds[1]);
+ var boundsWidth = Math.ceil(bounds[2]) - offsetX;
+ var boundsHeight = Math.ceil(bounds[3]) - offsetY;
+
+ var width = Math.min(Math.ceil(Math.abs(boundsWidth * combinesScale[0] *
+ EXPECTED_SCALE)), MAX_PATTERN_SIZE);
+ var height = Math.min(Math.ceil(Math.abs(boundsHeight * combinesScale[1] *
+ EXPECTED_SCALE)), MAX_PATTERN_SIZE);
+ var scaleX = boundsWidth / width;
+ var scaleY = boundsHeight / height;
+
+ var context = {
+ coords: coords,
+ colors: colors,
+ offsetX: -offsetX,
+ offsetY: -offsetY,
+ scaleX: 1 / scaleX,
+ scaleY: 1 / scaleY
+ };
+
+ var canvas, tmpCanvas, i, ii;
+ if (WebGLUtils.isEnabled) {
+ canvas = WebGLUtils.drawFigures(width, height, backgroundColor,
+ figures, context);
+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=972126
+ tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
+ tmpCanvas.context.drawImage(canvas, 0, 0);
+ canvas = tmpCanvas.canvas;
+ } else {
+ tmpCanvas = CachedCanvases.getCanvas('mesh', width, height, false);
+ var tmpCtx = tmpCanvas.context;
+
+ var data = tmpCtx.createImageData(width, height);
+ if (backgroundColor) {
+ var bytes = data.data;
+ for (i = 0, ii = bytes.length; i < ii; i += 4) {
+ bytes[i] = backgroundColor[0];
+ bytes[i + 1] = backgroundColor[1];
+ bytes[i + 2] = backgroundColor[2];
+ bytes[i + 3] = 255;
+ }
+ }
+ for (i = 0; i < figures.length; i++) {
+ drawFigure(data, figures[i], context);
+ }
+ tmpCtx.putImageData(data, 0, 0);
+ canvas = tmpCanvas.canvas;
+ }
+
+ return {canvas: canvas, offsetX: offsetX, offsetY: offsetY,
+ scaleX: scaleX, scaleY: scaleY};
+ }
+ return createMeshCanvas;
+})();
+
+ShadingIRs.Mesh = {
+ fromIR: function Mesh_fromIR(raw) {
+ //var type = raw[1];
+ var coords = raw[2];
+ var colors = raw[3];
+ var figures = raw[4];
+ var bounds = raw[5];
+ var matrix = raw[6];
+ //var bbox = raw[7];
+ var background = raw[8];
+ return {
+ type: 'Pattern',
+ getPattern: function Mesh_getPattern(ctx, owner, shadingFill) {
+ var scale;
+ if (shadingFill) {
+ scale = Util.singularValueDecompose2dScale(ctx.mozCurrentTransform);
+ } else {
+ // Obtain scale from matrix and current transformation matrix.
+ scale = Util.singularValueDecompose2dScale(owner.baseTransform);
+ if (matrix) {
+ var matrixScale = Util.singularValueDecompose2dScale(matrix);
+ scale = [scale[0] * matrixScale[0],
+ scale[1] * matrixScale[1]];
+ }
+ }
+
+
+ // Rasterizing on the main thread since sending/queue large canvases
+ // might cause OOM.
+ var temporaryPatternCanvas = createMeshCanvas(bounds, scale, coords,
+ colors, figures, shadingFill ? null : background);
+
+ if (!shadingFill) {
+ ctx.setTransform.apply(ctx, owner.baseTransform);
+ if (matrix) {
+ ctx.transform.apply(ctx, matrix);
+ }
+ }
+
+ ctx.translate(temporaryPatternCanvas.offsetX,
+ temporaryPatternCanvas.offsetY);
+ ctx.scale(temporaryPatternCanvas.scaleX,
+ temporaryPatternCanvas.scaleY);
+
+ return ctx.createPattern(temporaryPatternCanvas.canvas, 'no-repeat');
+ }
+ };
+ }
+};
+
+ShadingIRs.Dummy = {
+ fromIR: function Dummy_fromIR() {
+ return {
+ type: 'Pattern',
+ getPattern: function Dummy_fromIR_getPattern() {
+ return 'hotpink';
+ }
+ };
+ }
+};
+
+function getShadingPatternFromIR(raw) {
+ var shadingIR = ShadingIRs[raw[0]];
+ if (!shadingIR) {
+ error('Unknown IR type: ' + raw[0]);
+ }
+ return shadingIR.fromIR(raw);
+}
+
+var TilingPattern = (function TilingPatternClosure() {
+ var PaintType = {
+ COLORED: 1,
+ UNCOLORED: 2
+ };
+
+ var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
+
+ function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
+ this.operatorList = IR[2];
+ this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
+ this.bbox = IR[4];
+ this.xstep = IR[5];
+ this.ystep = IR[6];
+ this.paintType = IR[7];
+ this.tilingType = IR[8];
+ this.color = color;
+ this.objs = objs;
+ this.commonObjs = commonObjs;
+ this.baseTransform = baseTransform;
+ this.type = 'Pattern';
+ this.ctx = ctx;
+ }
+
+ TilingPattern.prototype = {
+ createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {
+ var operatorList = this.operatorList;
+ var bbox = this.bbox;
+ var xstep = this.xstep;
+ var ystep = this.ystep;
+ var paintType = this.paintType;
+ var tilingType = this.tilingType;
+ var color = this.color;
+ var objs = this.objs;
+ var commonObjs = this.commonObjs;
+
+ info('TilingType: ' + tilingType);
+
+ var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
+
+ var topLeft = [x0, y0];
+ // we want the canvas to be as large as the step size
+ var botRight = [x0 + xstep, y0 + ystep];
+
+ var width = botRight[0] - topLeft[0];
+ var height = botRight[1] - topLeft[1];
+
+ // Obtain scale from matrix and current transformation matrix.
+ var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
+ var curMatrixScale = Util.singularValueDecompose2dScale(
+ this.baseTransform);
+ var combinedScale = [matrixScale[0] * curMatrixScale[0],
+ matrixScale[1] * curMatrixScale[1]];
+
+ // MAX_PATTERN_SIZE is used to avoid OOM situation.
+ // Use width and height values that are as close as possible to the end
+ // result when the pattern is used. Too low value makes the pattern look
+ // blurry. Too large value makes it look too crispy.
+ width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),
+ MAX_PATTERN_SIZE);
+
+ height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
+ MAX_PATTERN_SIZE);
+
+ var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
+ var tmpCtx = tmpCanvas.context;
+ var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
+ graphics.groupLevel = owner.groupLevel;
+
+ this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
+
+ this.setScale(width, height, xstep, ystep);
+ this.transformToScale(graphics);
+
+ // transform coordinates to pattern space
+ var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
+ graphics.transform.apply(graphics, tmpTranslate);
+
+ this.clipBbox(graphics, bbox, x0, y0, x1, y1);
+
+ graphics.executeOperatorList(operatorList);
+ return tmpCanvas.canvas;
+ },
+
+ setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
+ this.scale = [width / xstep, height / ystep];
+ },
+
+ transformToScale: function TilingPattern_transformToScale(graphics) {
+ var scale = this.scale;
+ var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
+ graphics.transform.apply(graphics, tmpScale);
+ },
+
+ scaleToContext: function TilingPattern_scaleToContext() {
+ var scale = this.scale;
+ this.ctx.scale(1 / scale[0], 1 / scale[1]);
+ },
+
+ clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
+ if (bbox && isArray(bbox) && bbox.length === 4) {
+ var bboxWidth = x1 - x0;
+ var bboxHeight = y1 - y0;
+ graphics.ctx.rect(x0, y0, bboxWidth, bboxHeight);
+ graphics.clip();
+ graphics.endPath();
+ }
+ },
+
+ setFillAndStrokeStyleToContext:
+ function setFillAndStrokeStyleToContext(context, paintType, color) {
+ switch (paintType) {
+ case PaintType.COLORED:
+ var ctx = this.ctx;
+ context.fillStyle = ctx.fillStyle;
+ context.strokeStyle = ctx.strokeStyle;
+ break;
+ case PaintType.UNCOLORED:
+ var cssColor = Util.makeCssRgb(color);
+ context.fillStyle = cssColor;
+ context.strokeStyle = cssColor;
+ break;
+ default:
+ error('Unsupported paint type: ' + paintType);
+ }
+ },
+
+ getPattern: function TilingPattern_getPattern(ctx, owner) {
+ var temporaryPatternCanvas = this.createPatternCanvas(owner);
+
+ ctx = this.ctx;
+ ctx.setTransform.apply(ctx, this.baseTransform);
+ ctx.transform.apply(ctx, this.matrix);
+ this.scaleToContext();
+
+ return ctx.createPattern(temporaryPatternCanvas, 'repeat');
+ }
+ };
+
+ return TilingPattern;
+})();
+
+
PDFJS.disableFontFace = false;
var FontLoader = {
insertRule: function fontLoaderInsertRule(rule) {
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
if (!styleElement) {
- styleElement = document.createElement('style');
- styleElement.id = 'PDFJS_FONT_STYLE_TAG';
- document.documentElement.getElementsByTagName('head')[0].appendChild(
- styleElement);
+ styleElement = document.createElement('style');
+ styleElement.id = 'PDFJS_FONT_STYLE_TAG';
+ document.documentElement.getElementsByTagName('head')[0].appendChild(
+ styleElement);
}
var styleSheet = styleElement.sheet;
styleSheet.insertRule(rule, styleSheet.cssRules.length);
},
+
clear: function fontLoaderClear() {
var styleElement = document.getElementById('PDFJS_FONT_STYLE_TAG');
if (styleElement) {
styleElement.parentNode.removeChild(styleElement);
}
+ this.nativeFontFaces.forEach(function(nativeFontFace) {
+ document.fonts.delete(nativeFontFace);
+ });
+ this.nativeFontFaces.length = 0;
},
get loadTestFont() {
// This is a CFF font with 1 glyph for '.' that fills its entire width and
@@ -7267,23 +6102,39 @@ var FontLoader = {
},
isSyncFontLoadingSupported: (function detectSyncFontLoadingSupport() {
- if (isWorker)
+ if (isWorker) {
return false;
+ }
// User agent string sniffing is bad, but there is no reliable way to tell
// if font is fully loaded and ready to be used with canvas.
var userAgent = window.navigator.userAgent;
var m = /Mozilla\/5.0.*?rv:(\d+).*? Gecko/.exec(userAgent);
- if (m && m[1] >= 14)
+ if (m && m[1] >= 14) {
return true;
+ }
// TODO other browsers
+ if (userAgent === 'node') {
+ return true;
+ }
return false;
})(),
+ nativeFontFaces: [],
+
+ isFontLoadingAPISupported: !isWorker && !!document.fonts,
+
+ addNativeFontFace: function fontLoader_addNativeFontFace(nativeFontFace) {
+ this.nativeFontFaces.push(nativeFontFace);
+ document.fonts.add(nativeFontFace);
+ },
+
bind: function fontLoaderBind(fonts, callback) {
assert(!isWorker, 'bind() shall be called from main thread');
- var rules = [], fontsToLoad = [];
+ var rules = [];
+ var fontsToLoad = [];
+ var fontLoadPromises = [];
for (var i = 0, ii = fonts.length; i < ii; i++) {
var font = fonts[i];
@@ -7294,15 +6145,26 @@ var FontLoader = {
}
font.attached = true;
- var rule = font.bindDOM();
- if (rule) {
- rules.push(rule);
- fontsToLoad.push(font);
+ if (this.isFontLoadingAPISupported) {
+ var nativeFontFace = font.createNativeFontFace();
+ if (nativeFontFace) {
+ fontLoadPromises.push(nativeFontFace.loaded);
+ }
+ } else {
+ var rule = font.bindDOM();
+ if (rule) {
+ rules.push(rule);
+ fontsToLoad.push(font);
+ }
}
}
var request = FontLoader.queueLoadingCallback(callback);
- if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
+ if (this.isFontLoadingAPISupported) {
+ Promise.all(fontsToLoad).then(function() {
+ request.complete();
+ });
+ } else if (rules.length > 0 && !this.isSyncFontLoadingSupported) {
FontLoader.prepareFontLoadEvent(rules, fontsToLoad, request);
} else {
request.complete();
@@ -7350,16 +6212,9 @@ var FontLoader = {
(data.charCodeAt(offset + 3) & 0xff);
}
- function string32(value) {
- return String.fromCharCode((value >> 24) & 0xff) +
- String.fromCharCode((value >> 16) & 0xff) +
- String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
- }
-
function spliceString(s, offset, remove, insert) {
- var chunk1 = data.substr(0, offset);
- var chunk2 = data.substr(offset + remove);
+ var chunk1 = s.substr(0, offset);
+ var chunk2 = s.substr(offset + remove);
return chunk1 + insert + chunk2;
}
@@ -7444,8 +6299,8 @@ var FontLoader = {
}
};
-var FontFace = (function FontFaceClosure() {
- function FontFace(name, file, properties) {
+var FontFaceObject = (function FontFaceObjectClosure() {
+ function FontFaceObject(name, file, properties) {
this.compiledGlyphs = {};
if (arguments.length === 1) {
// importing translated data
@@ -7456,33 +6311,56 @@ var FontFace = (function FontFaceClosure() {
return;
}
}
- FontFace.prototype = {
- bindDOM: function FontFace_bindDOM() {
- if (!this.data)
+ FontFaceObject.prototype = {
+ createNativeFontFace: function FontFaceObject_createNativeFontFace() {
+ if (!this.data) {
return null;
+ }
if (PDFJS.disableFontFace) {
this.disableFontFace = true;
return null;
}
- var data = bytesToString(this.data);
+ var nativeFontFace = new FontFace(this.loadedName, this.data, {});
+
+ FontLoader.addNativeFontFace(nativeFontFace);
+
+ if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
+ globalScope['FontInspector'].enabled) {
+ globalScope['FontInspector'].fontAdded(this);
+ }
+ return nativeFontFace;
+ },
+
+ bindDOM: function FontFaceObject_bindDOM() {
+ if (!this.data) {
+ return null;
+ }
+
+ if (PDFJS.disableFontFace) {
+ this.disableFontFace = true;
+ return null;
+ }
+
+ var data = bytesToString(new Uint8Array(this.data));
var fontName = this.loadedName;
// Add the font-face rule to the document
var url = ('url(data:' + this.mimetype + ';base64,' +
window.btoa(data) + ');');
var rule = '@font-face { font-family:"' + fontName + '";src:' + url + '}';
-
FontLoader.insertRule(rule);
if (PDFJS.pdfBug && 'FontInspector' in globalScope &&
- globalScope['FontInspector'].enabled)
+ globalScope['FontInspector'].enabled) {
globalScope['FontInspector'].fontAdded(this, url);
+ }
return rule;
},
- getPathGenerator: function (objs, character) {
+
+ getPathGenerator: function FontLoader_getPathGenerator(objs, character) {
if (!(character in this.compiledGlyphs)) {
var js = objs.get(this.loadedName + '_path_' + character);
/*jshint -W054 */
@@ -7491,10 +6369,1414 @@ var FontFace = (function FontFaceClosure() {
return this.compiledGlyphs[character];
}
};
- return FontFace;
+ return FontFaceObject;
})();
+var HIGHLIGHT_OFFSET = 4; // px
+var ANNOT_MIN_SIZE = 10; // px
+
+var AnnotationUtils = (function AnnotationUtilsClosure() {
+ // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
+ function setTextStyles(element, item, fontObj) {
+
+ var style = element.style;
+ style.fontSize = item.fontSize + 'px';
+ style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
+
+ if (!fontObj) {
+ return;
+ }
+
+ style.fontWeight = fontObj.black ?
+ (fontObj.bold ? 'bolder' : 'bold') :
+ (fontObj.bold ? 'bold' : 'normal');
+ style.fontStyle = fontObj.italic ? 'italic' : 'normal';
+
+ var fontName = fontObj.loadedName;
+ var fontFamily = fontName ? '"' + fontName + '", ' : '';
+ // Use a reasonable default font if the font doesn't specify a fallback
+ var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
+ style.fontFamily = fontFamily + fallbackName;
+ }
+
+ // TODO(mack): Remove this, it's not really that helpful.
+ function getEmptyContainer(tagName, rect, borderWidth) {
+ var bWidth = borderWidth || 0;
+ var element = document.createElement(tagName);
+ element.style.borderWidth = bWidth + 'px';
+ var width = rect[2] - rect[0] - 2 * bWidth;
+ var height = rect[3] - rect[1] - 2 * bWidth;
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+ return element;
+ }
+
+ function initContainer(item) {
+ var container = getEmptyContainer('section', item.rect, item.borderWidth);
+ container.style.backgroundColor = item.color;
+
+ var color = item.color;
+ var rgb = [];
+ for (var i = 0; i < 3; ++i) {
+ rgb[i] = Math.round(color[i] * 255);
+ }
+ item.colorCssRgb = Util.makeCssRgb(rgb);
+
+ var highlight = document.createElement('div');
+ highlight.className = 'annotationHighlight';
+ highlight.style.left = highlight.style.top = -HIGHLIGHT_OFFSET + 'px';
+ highlight.style.right = highlight.style.bottom = -HIGHLIGHT_OFFSET + 'px';
+ highlight.setAttribute('hidden', true);
+
+ item.highlightElement = highlight;
+ container.appendChild(item.highlightElement);
+
+ return container;
+ }
+
+ function getHtmlElementForTextWidgetAnnotation(item, commonObjs) {
+ var element = getEmptyContainer('div', item.rect, 0);
+ element.style.display = 'table';
+
+ var content = document.createElement('div');
+ content.textContent = item.fieldValue;
+ var textAlignment = item.textAlignment;
+ content.style.textAlign = ['left', 'center', 'right'][textAlignment];
+ content.style.verticalAlign = 'middle';
+ content.style.display = 'table-cell';
+
+ var fontObj = item.fontRefName ?
+ commonObjs.getData(item.fontRefName) : null;
+ setTextStyles(content, item, fontObj);
+
+ element.appendChild(content);
+
+ return element;
+ }
+
+ function getHtmlElementForTextAnnotation(item) {
+ var rect = item.rect;
+
+ // sanity check because of OOo-generated PDFs
+ if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
+ rect[3] = rect[1] + ANNOT_MIN_SIZE;
+ }
+ if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
+ rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
+ }
+
+ var container = initContainer(item);
+ container.className = 'annotText';
+
+ var image = document.createElement('img');
+ image.style.height = container.style.height;
+ image.style.width = container.style.width;
+ var iconName = item.name;
+ image.src = PDFJS.imageResourcesPath + 'annotation-' +
+ iconName.toLowerCase() + '.svg';
+ image.alt = '[{{type}} Annotation]';
+ image.dataset.l10nId = 'text_annotation_type';
+ image.dataset.l10nArgs = JSON.stringify({type: iconName});
+
+ var contentWrapper = document.createElement('div');
+ contentWrapper.className = 'annotTextContentWrapper';
+ contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px';
+ contentWrapper.style.top = '-10px';
+
+ var content = document.createElement('div');
+ content.className = 'annotTextContent';
+ content.setAttribute('hidden', true);
+
+ var i, ii;
+ if (item.hasBgColor) {
+ var color = item.color;
+ var rgb = [];
+ for (i = 0; i < 3; ++i) {
+ // Enlighten the color (70%)
+ var c = Math.round(color[i] * 255);
+ rgb[i] = Math.round((255 - c) * 0.7) + c;
+ }
+ content.style.backgroundColor = Util.makeCssRgb(rgb);
+ }
+
+ var title = document.createElement('h1');
+ var text = document.createElement('p');
+ title.textContent = item.title;
+
+ if (!item.content && !item.title) {
+ content.setAttribute('hidden', true);
+ } else {
+ var e = document.createElement('span');
+ var lines = item.content.split(/(?:\r\n?|\n)/);
+ for (i = 0, ii = lines.length; i < ii; ++i) {
+ var line = lines[i];
+ e.appendChild(document.createTextNode(line));
+ if (i < (ii - 1)) {
+ e.appendChild(document.createElement('br'));
+ }
+ }
+ text.appendChild(e);
+
+ var pinned = false;
+
+ var showAnnotation = function showAnnotation(pin) {
+ if (pin) {
+ pinned = true;
+ }
+ if (content.hasAttribute('hidden')) {
+ container.style.zIndex += 1;
+ content.removeAttribute('hidden');
+ }
+ };
+
+ var hideAnnotation = function hideAnnotation(unpin) {
+ if (unpin) {
+ pinned = false;
+ }
+ if (!content.hasAttribute('hidden') && !pinned) {
+ container.style.zIndex -= 1;
+ content.setAttribute('hidden', true);
+ }
+ };
+
+ var toggleAnnotation = function toggleAnnotation() {
+ if (pinned) {
+ hideAnnotation(true);
+ } else {
+ showAnnotation(true);
+ }
+ };
+
+ image.addEventListener('click', function image_clickHandler() {
+ toggleAnnotation();
+ }, false);
+ image.addEventListener('mouseover', function image_mouseOverHandler() {
+ showAnnotation();
+ }, false);
+ image.addEventListener('mouseout', function image_mouseOutHandler() {
+ hideAnnotation();
+ }, false);
+
+ content.addEventListener('click', function content_clickHandler() {
+ hideAnnotation(true);
+ }, false);
+ }
+
+ content.appendChild(title);
+ content.appendChild(text);
+ contentWrapper.appendChild(content);
+ container.appendChild(image);
+ container.appendChild(contentWrapper);
+
+ return container;
+ }
+
+ function getHtmlElementForLinkAnnotation(item) {
+ var container = initContainer(item);
+ container.className = 'annotLink';
+
+ container.style.borderColor = item.colorCssRgb;
+ container.style.borderStyle = 'solid';
+
+ var link = document.createElement('a');
+ link.href = link.title = item.url || '';
+
+ container.appendChild(link);
+
+ return container;
+ }
+
+ function getHtmlElement(data, objs) {
+ switch (data.annotationType) {
+ case AnnotationType.WIDGET:
+ return getHtmlElementForTextWidgetAnnotation(data, objs);
+ case AnnotationType.TEXT:
+ return getHtmlElementForTextAnnotation(data);
+ case AnnotationType.LINK:
+ return getHtmlElementForLinkAnnotation(data);
+ default:
+ throw new Error('Unsupported annotationType: ' + data.annotationType);
+ }
+ }
+
+ return {
+ getHtmlElement: getHtmlElement
+ };
+})();
+PDFJS.AnnotationUtils = AnnotationUtils;
+
+
+var SVG_DEFAULTS = {
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fillColor: '#000000'
+};
+
+var convertImgDataToPng = (function convertImgDataToPngClosure() {
+ var PNG_HEADER =
+ new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
+
+ var CHUNK_WRAPPER_SIZE = 12;
+
+ var crcTable = new Int32Array(256);
+ for (var i = 0; i < 256; i++) {
+ var c = i;
+ for (var h = 0; h < 8; h++) {
+ if (c & 1) {
+ c = 0xedB88320 ^ ((c >> 1) & 0x7fffffff);
+ } else {
+ c = (c >> 1) & 0x7fffffff;
+ }
+ }
+ crcTable[i] = c;
+ }
+
+ function crc32(data, start, end) {
+ var crc = -1;
+ for (var i = start; i < end; i++) {
+ var a = (crc ^ data[i]) & 0xff;
+ var b = crcTable[a];
+ crc = (crc >>> 8) ^ b;
+ }
+ return crc ^ -1;
+ }
+
+ function writePngChunk(type, body, data, offset) {
+ var p = offset;
+ var len = body.length;
+
+ data[p] = len >> 24 & 0xff;
+ data[p + 1] = len >> 16 & 0xff;
+ data[p + 2] = len >> 8 & 0xff;
+ data[p + 3] = len & 0xff;
+ p += 4;
+
+ data[p] = type.charCodeAt(0) & 0xff;
+ data[p + 1] = type.charCodeAt(1) & 0xff;
+ data[p + 2] = type.charCodeAt(2) & 0xff;
+ data[p + 3] = type.charCodeAt(3) & 0xff;
+ p += 4;
+
+ data.set(body, p);
+ p += body.length;
+
+ var crc = crc32(data, offset + 4, p);
+
+ data[p] = crc >> 24 & 0xff;
+ data[p + 1] = crc >> 16 & 0xff;
+ data[p + 2] = crc >> 8 & 0xff;
+ data[p + 3] = crc & 0xff;
+ }
+
+ function adler32(data, start, end) {
+ var a = 1;
+ var b = 0;
+ for (var i = start; i < end; ++i) {
+ a = (a + (data[i] & 0xff)) % 65521;
+ b = (b + a) % 65521;
+ }
+ return (b << 16) | a;
+ }
+
+ function encode(imgData, kind) {
+ var width = imgData.width;
+ var height = imgData.height;
+ var bitDepth, colorType, lineSize;
+ var bytes = imgData.data;
+
+ switch (kind) {
+ case ImageKind.GRAYSCALE_1BPP:
+ colorType = 0;
+ bitDepth = 1;
+ lineSize = (width + 7) >> 3;
+ break;
+ case ImageKind.RGB_24BPP:
+ colorType = 2;
+ bitDepth = 8;
+ lineSize = width * 3;
+ break;
+ case ImageKind.RGBA_32BPP:
+ colorType = 6;
+ bitDepth = 8;
+ lineSize = width * 4;
+ break;
+ default:
+ throw new Error('invalid format');
+ }
+
+ // prefix every row with predictor 0
+ var literals = new Uint8Array((1 + lineSize) * height);
+ var offsetLiterals = 0, offsetBytes = 0;
+ var y, i;
+ for (y = 0; y < height; ++y) {
+ literals[offsetLiterals++] = 0; // no prediction
+ literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize),
+ offsetLiterals);
+ offsetBytes += lineSize;
+ offsetLiterals += lineSize;
+ }
+
+ if (kind === ImageKind.GRAYSCALE_1BPP) {
+ // inverting for B/W
+ offsetLiterals = 0;
+ for (y = 0; y < height; y++) {
+ offsetLiterals++; // skipping predictor
+ for (i = 0; i < lineSize; i++) {
+ literals[offsetLiterals++] ^= 0xFF;
+ }
+ }
+ }
+
+ var ihdr = new Uint8Array([
+ width >> 24 & 0xff,
+ width >> 16 & 0xff,
+ width >> 8 & 0xff,
+ width & 0xff,
+ height >> 24 & 0xff,
+ height >> 16 & 0xff,
+ height >> 8 & 0xff,
+ height & 0xff,
+ bitDepth, // bit depth
+ colorType, // color type
+ 0x00, // compression method
+ 0x00, // filter method
+ 0x00 // interlace method
+ ]);
+
+ var len = literals.length;
+ var maxBlockLength = 0xFFFF;
+
+ var deflateBlocks = Math.ceil(len / maxBlockLength);
+ var idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4);
+ var pi = 0;
+ idat[pi++] = 0x78; // compression method and flags
+ idat[pi++] = 0x9c; // flags
+
+ var pos = 0;
+ while (len > maxBlockLength) {
+ // writing non-final DEFLATE blocks type 0 and length of 65535
+ idat[pi++] = 0x00;
+ idat[pi++] = 0xff;
+ idat[pi++] = 0xff;
+ idat[pi++] = 0x00;
+ idat[pi++] = 0x00;
+ idat.set(literals.subarray(pos, pos + maxBlockLength), pi);
+ pi += maxBlockLength;
+ pos += maxBlockLength;
+ len -= maxBlockLength;
+ }
+
+ // writing non-final DEFLATE blocks type 0
+ idat[pi++] = 0x01;
+ idat[pi++] = len & 0xff;
+ idat[pi++] = len >> 8 & 0xff;
+ idat[pi++] = (~len & 0xffff) & 0xff;
+ idat[pi++] = (~len & 0xffff) >> 8 & 0xff;
+ idat.set(literals.subarray(pos), pi);
+ pi += literals.length - pos;
+
+ var adler = adler32(literals, 0, literals.length); // checksum
+ idat[pi++] = adler >> 24 & 0xff;
+ idat[pi++] = adler >> 16 & 0xff;
+ idat[pi++] = adler >> 8 & 0xff;
+ idat[pi++] = adler & 0xff;
+
+ // PNG will consists: header, IHDR+data, IDAT+data, and IEND.
+ var pngLength = PNG_HEADER.length + (CHUNK_WRAPPER_SIZE * 3) +
+ ihdr.length + idat.length;
+ var data = new Uint8Array(pngLength);
+ var offset = 0;
+ data.set(PNG_HEADER, offset);
+ offset += PNG_HEADER.length;
+ writePngChunk('IHDR', ihdr, data, offset);
+ offset += CHUNK_WRAPPER_SIZE + ihdr.length;
+ writePngChunk('IDATA', idat, data, offset);
+ offset += CHUNK_WRAPPER_SIZE + idat.length;
+ writePngChunk('IEND', new Uint8Array(0), data, offset);
+
+ return PDFJS.createObjectURL(data, 'image/png');
+ }
+
+ return function convertImgDataToPng(imgData) {
+ var kind = (imgData.kind === undefined ?
+ ImageKind.GRAYSCALE_1BPP : imgData.kind);
+ return encode(imgData, kind);
+ };
+})();
+
+var SVGExtraState = (function SVGExtraStateClosure() {
+ function SVGExtraState() {
+ this.fontSizeScale = 1;
+ this.fontWeight = SVG_DEFAULTS.fontWeight;
+ this.fontSize = 0;
+
+ this.textMatrix = IDENTITY_MATRIX;
+ this.fontMatrix = FONT_IDENTITY_MATRIX;
+ this.leading = 0;
+
+ // Current point (in user coordinates)
+ this.x = 0;
+ this.y = 0;
+
+ // Start of text line (in text coordinates)
+ this.lineX = 0;
+ this.lineY = 0;
+
+ // Character and word spacing
+ this.charSpacing = 0;
+ this.wordSpacing = 0;
+ this.textHScale = 1;
+ this.textRise = 0;
+
+ // Default foreground and background colors
+ this.fillColor = SVG_DEFAULTS.fillColor;
+ this.strokeColor = '#000000';
+
+ this.fillAlpha = 1;
+ this.strokeAlpha = 1;
+ this.lineWidth = 1;
+ this.lineJoin = '';
+ this.lineCap = '';
+ this.miterLimit = 0;
+
+ this.dashArray = [];
+ this.dashPhase = 0;
+
+ this.dependencies = [];
+
+ // Clipping
+ this.clipId = '';
+ this.pendingClip = false;
+
+ this.maskId = '';
+ }
+
+ SVGExtraState.prototype = {
+ clone: function SVGExtraState_clone() {
+ return Object.create(this);
+ },
+ setCurrentPoint: function SVGExtraState_setCurrentPoint(x, y) {
+ this.x = x;
+ this.y = y;
+ }
+ };
+ return SVGExtraState;
+})();
+
+var SVGGraphics = (function SVGGraphicsClosure() {
+ function createScratchSVG(width, height) {
+ var NS = 'http://www.w3.org/2000/svg';
+ var svg = document.createElementNS(NS, 'svg:svg');
+ svg.setAttributeNS(null, 'version', '1.1');
+ svg.setAttributeNS(null, 'width', width + 'px');
+ svg.setAttributeNS(null, 'height', height + 'px');
+ svg.setAttributeNS(null, 'viewBox', '0 0 ' + width + ' ' + height);
+ return svg;
+ }
+
+ function opListToTree(opList) {
+ var opTree = [];
+ var tmp = [];
+ var opListLen = opList.length;
+
+ for (var x = 0; x < opListLen; x++) {
+ if (opList[x].fn === 'save') {
+ opTree.push({'fnId': 92, 'fn': 'group', 'items': []});
+ tmp.push(opTree);
+ opTree = opTree[opTree.length - 1].items;
+ continue;
+ }
+
+ if(opList[x].fn === 'restore') {
+ opTree = tmp.pop();
+ } else {
+ opTree.push(opList[x]);
+ }
+ }
+ return opTree;
+ }
+
+ /**
+ * Formats float number.
+ * @param value {number} number to format.
+ * @returns {string}
+ */
+ function pf(value) {
+ if (value === (value | 0)) { // integer number
+ return value.toString();
+ }
+ var s = value.toFixed(10);
+ var i = s.length - 1;
+ if (s[i] !== '0') {
+ return s;
+ }
+ // removing trailing zeros
+ do {
+ i--;
+ } while (s[i] === '0');
+ return s.substr(0, s[i] === '.' ? i : i + 1);
+ }
+
+ /**
+ * Formats transform matrix. The standard rotation, scale and translate
+ * matrices are replaced by their shorter forms, and for identity matrix
+ * returns empty string to save the memory.
+ * @param m {Array} matrix to format.
+ * @returns {string}
+ */
+ function pm(m) {
+ if (m[4] === 0 && m[5] === 0) {
+ if (m[1] === 0 && m[2] === 0) {
+ if (m[0] === 1 && m[3] === 1) {
+ return '';
+ }
+ return 'scale(' + pf(m[0]) + ' ' + pf(m[3]) + ')';
+ }
+ if (m[0] === m[3] && m[1] === -m[2]) {
+ var a = Math.acos(m[0]) * 180 / Math.PI;
+ return 'rotate(' + pf(a) + ')';
+ }
+ } else {
+ if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) {
+ return 'translate(' + pf(m[4]) + ' ' + pf(m[5]) + ')';
+ }
+ }
+ return 'matrix(' + pf(m[0]) + ' ' + pf(m[1]) + ' ' + pf(m[2]) + ' ' +
+ pf(m[3]) + ' ' + pf(m[4]) + ' ' + pf(m[5]) + ')';
+ }
+
+ function SVGGraphics(commonObjs, objs) {
+ this.current = new SVGExtraState();
+ this.transformMatrix = IDENTITY_MATRIX; // Graphics state matrix
+ this.transformStack = [];
+ this.extraStack = [];
+ this.commonObjs = commonObjs;
+ this.objs = objs;
+ this.pendingEOFill = false;
+
+ this.embedFonts = false;
+ this.embeddedFonts = {};
+ this.cssStyle = null;
+ }
+
+ var NS = 'http://www.w3.org/2000/svg';
+ var XML_NS = 'http://www.w3.org/XML/1998/namespace';
+ var XLINK_NS = 'http://www.w3.org/1999/xlink';
+ var LINE_CAP_STYLES = ['butt', 'round', 'square'];
+ var LINE_JOIN_STYLES = ['miter', 'round', 'bevel'];
+ var clipCount = 0;
+ var maskCount = 0;
+
+ SVGGraphics.prototype = {
+ save: function SVGGraphics_save() {
+ this.transformStack.push(this.transformMatrix);
+ var old = this.current;
+ this.extraStack.push(old);
+ this.current = old.clone();
+ },
+
+ restore: function SVGGraphics_restore() {
+ this.transformMatrix = this.transformStack.pop();
+ this.current = this.extraStack.pop();
+
+ this.tgrp = document.createElementNS(NS, 'svg:g');
+ this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
+ this.pgrp.appendChild(this.tgrp);
+ },
+
+ group: function SVGGraphics_group(items) {
+ this.save();
+ this.executeOpTree(items);
+ this.restore();
+ },
+
+ loadDependencies: function SVGGraphics_loadDependencies(operatorList) {
+ var fnArray = operatorList.fnArray;
+ var fnArrayLen = fnArray.length;
+ var argsArray = operatorList.argsArray;
+
+ var self = this;
+ for (var i = 0; i < fnArrayLen; i++) {
+ if (OPS.dependency === fnArray[i]) {
+ var deps = argsArray[i];
+ for (var n = 0, nn = deps.length; n < nn; n++) {
+ var obj = deps[n];
+ var common = obj.substring(0, 2) === 'g_';
+ var promise;
+ if (common) {
+ promise = new Promise(function(resolve) {
+ self.commonObjs.get(obj, resolve);
+ });
+ } else {
+ promise = new Promise(function(resolve) {
+ self.objs.get(obj, resolve);
+ });
+ }
+ this.current.dependencies.push(promise);
+ }
+ }
+ }
+ return Promise.all(this.current.dependencies);
+ },
+
+ transform: function SVGGraphics_transform(a, b, c, d, e, f) {
+ var transformMatrix = [a, b, c, d, e, f];
+ this.transformMatrix = PDFJS.Util.transform(this.transformMatrix,
+ transformMatrix);
+
+ this.tgrp = document.createElementNS(NS, 'svg:g');
+ this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
+ },
+
+ getSVG: function SVGGraphics_getSVG(operatorList, viewport) {
+ this.svg = createScratchSVG(viewport.width, viewport.height);
+ this.viewport = viewport;
+
+ return this.loadDependencies(operatorList).then(function () {
+ this.transformMatrix = IDENTITY_MATRIX;
+ this.pgrp = document.createElementNS(NS, 'svg:g'); // Parent group
+ this.pgrp.setAttributeNS(null, 'transform', pm(viewport.transform));
+ this.tgrp = document.createElementNS(NS, 'svg:g'); // Transform group
+ this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
+ this.defs = document.createElementNS(NS, 'svg:defs');
+ this.pgrp.appendChild(this.defs);
+ this.pgrp.appendChild(this.tgrp);
+ this.svg.appendChild(this.pgrp);
+ var opTree = this.convertOpList(operatorList);
+ this.executeOpTree(opTree);
+ return this.svg;
+ }.bind(this));
+ },
+
+ convertOpList: function SVGGraphics_convertOpList(operatorList) {
+ var argsArray = operatorList.argsArray;
+ var fnArray = operatorList.fnArray;
+ var fnArrayLen = fnArray.length;
+ var REVOPS = [];
+ var opList = [];
+
+ for (var op in OPS) {
+ REVOPS[OPS[op]] = op;
+ }
+
+ for (var x = 0; x < fnArrayLen; x++) {
+ var fnId = fnArray[x];
+ opList.push({'fnId' : fnId, 'fn': REVOPS[fnId], 'args': argsArray[x]});
+ }
+ return opListToTree(opList);
+ },
+
+ executeOpTree: function SVGGraphics_executeOpTree(opTree) {
+ var opTreeLen = opTree.length;
+ for(var x = 0; x < opTreeLen; x++) {
+ var fn = opTree[x].fn;
+ var fnId = opTree[x].fnId;
+ var args = opTree[x].args;
+
+ switch (fnId | 0) {
+ case OPS.beginText:
+ this.beginText();
+ break;
+ case OPS.setLeading:
+ this.setLeading(args);
+ break;
+ case OPS.setLeadingMoveText:
+ this.setLeadingMoveText(args[0], args[1]);
+ break;
+ case OPS.setFont:
+ this.setFont(args);
+ break;
+ case OPS.showText:
+ this.showText(args[0]);
+ break;
+ case OPS.showSpacedText:
+ this.showText(args[0]);
+ break;
+ case OPS.endText:
+ this.endText();
+ break;
+ case OPS.moveText:
+ this.moveText(args[0], args[1]);
+ break;
+ case OPS.setCharSpacing:
+ this.setCharSpacing(args[0]);
+ break;
+ case OPS.setWordSpacing:
+ this.setWordSpacing(args[0]);
+ break;
+ case OPS.setTextMatrix:
+ this.setTextMatrix(args[0], args[1], args[2],
+ args[3], args[4], args[5]);
+ break;
+ case OPS.setLineWidth:
+ this.setLineWidth(args[0]);
+ break;
+ case OPS.setLineJoin:
+ this.setLineJoin(args[0]);
+ break;
+ case OPS.setLineCap:
+ this.setLineCap(args[0]);
+ break;
+ case OPS.setMiterLimit:
+ this.setMiterLimit(args[0]);
+ break;
+ case OPS.setFillRGBColor:
+ this.setFillRGBColor(args[0], args[1], args[2]);
+ break;
+ case OPS.setStrokeRGBColor:
+ this.setStrokeRGBColor(args[0], args[1], args[2]);
+ break;
+ case OPS.setDash:
+ this.setDash(args[0], args[1]);
+ break;
+ case OPS.setGState:
+ this.setGState(args[0]);
+ break;
+ case OPS.fill:
+ this.fill();
+ break;
+ case OPS.eoFill:
+ this.eoFill();
+ break;
+ case OPS.stroke:
+ this.stroke();
+ break;
+ case OPS.fillStroke:
+ this.fillStroke();
+ break;
+ case OPS.eoFillStroke:
+ this.eoFillStroke();
+ break;
+ case OPS.clip:
+ this.clip('nonzero');
+ break;
+ case OPS.eoClip:
+ this.clip('evenodd');
+ break;
+ case OPS.paintSolidColorImageMask:
+ this.paintSolidColorImageMask();
+ break;
+ case OPS.paintJpegXObject:
+ this.paintJpegXObject(args[0], args[1], args[2]);
+ break;
+ case OPS.paintImageXObject:
+ this.paintImageXObject(args[0]);
+ break;
+ case OPS.paintInlineImageXObject:
+ this.paintInlineImageXObject(args[0]);
+ break;
+ case OPS.paintImageMaskXObject:
+ this.paintImageMaskXObject(args[0]);
+ break;
+ case OPS.paintFormXObjectBegin:
+ this.paintFormXObjectBegin(args[0], args[1]);
+ break;
+ case OPS.paintFormXObjectEnd:
+ this.paintFormXObjectEnd();
+ break;
+ case OPS.closePath:
+ this.closePath();
+ break;
+ case OPS.closeStroke:
+ this.closeStroke();
+ break;
+ case OPS.closeFillStroke:
+ this.closeFillStroke();
+ break;
+ case OPS.nextLine:
+ this.nextLine();
+ break;
+ case OPS.transform:
+ this.transform(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
+ break;
+ case OPS.constructPath:
+ this.constructPath(args[0], args[1]);
+ break;
+ case OPS.endPath:
+ this.endPath();
+ break;
+ case 92:
+ this.group(opTree[x].items);
+ break;
+ default:
+ warn('Unimplemented method '+ fn);
+ break;
+ }
+ }
+ },
+
+ setWordSpacing: function SVGGraphics_setWordSpacing(wordSpacing) {
+ this.current.wordSpacing = wordSpacing;
+ },
+
+ setCharSpacing: function SVGGraphics_setCharSpacing(charSpacing) {
+ this.current.charSpacing = charSpacing;
+ },
+
+ nextLine: function SVGGraphics_nextLine() {
+ this.moveText(0, this.current.leading);
+ },
+
+ setTextMatrix: function SVGGraphics_setTextMatrix(a, b, c, d, e, f) {
+ var current = this.current;
+ this.current.textMatrix = this.current.lineMatrix = [a, b, c, d, e, f];
+
+ this.current.x = this.current.lineX = 0;
+ this.current.y = this.current.lineY = 0;
+
+ current.xcoords = [];
+ current.tspan = document.createElementNS(NS, 'svg:tspan');
+ current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
+ current.tspan.setAttributeNS(null, 'font-size',
+ pf(current.fontSize) + 'px');
+ current.tspan.setAttributeNS(null, 'y', pf(-current.y));
+
+ current.txtElement = document.createElementNS(NS, 'svg:text');
+ current.txtElement.appendChild(current.tspan);
+ },
+
+ beginText: function SVGGraphics_beginText() {
+ this.current.x = this.current.lineX = 0;
+ this.current.y = this.current.lineY = 0;
+ this.current.textMatrix = IDENTITY_MATRIX;
+ this.current.lineMatrix = IDENTITY_MATRIX;
+ this.current.tspan = document.createElementNS(NS, 'svg:tspan');
+ this.current.txtElement = document.createElementNS(NS, 'svg:text');
+ this.current.txtgrp = document.createElementNS(NS, 'svg:g');
+ this.current.xcoords = [];
+ },
+
+ moveText: function SVGGraphics_moveText(x, y) {
+ var current = this.current;
+ this.current.x = this.current.lineX += x;
+ this.current.y = this.current.lineY += y;
+
+ current.xcoords = [];
+ current.tspan = document.createElementNS(NS, 'svg:tspan');
+ current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
+ current.tspan.setAttributeNS(null, 'font-size',
+ pf(current.fontSize) + 'px');
+ current.tspan.setAttributeNS(null, 'y', pf(-current.y));
+ },
+
+ showText: function SVGGraphics_showText(glyphs) {
+ var current = this.current;
+ var font = current.font;
+ var fontSize = current.fontSize;
+
+ if (fontSize === 0) {
+ return;
+ }
+
+ var charSpacing = current.charSpacing;
+ var wordSpacing = current.wordSpacing;
+ var fontDirection = current.fontDirection;
+ var textHScale = current.textHScale * fontDirection;
+ var glyphsLength = glyphs.length;
+ var vertical = font.vertical;
+ var widthAdvanceScale = fontSize * current.fontMatrix[0];
+
+ var x = 0, i;
+ for (i = 0; i < glyphsLength; ++i) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ // word break
+ x += fontDirection * wordSpacing;
+ continue;
+ } else if (isNum(glyph)) {
+ x += -glyph * fontSize * 0.001;
+ continue;
+ }
+ current.xcoords.push(current.x + x * textHScale);
+
+ var width = glyph.width;
+ var character = glyph.fontChar;
+ var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
+ x += charWidth;
+
+ current.tspan.textContent += character;
+ }
+ if (vertical) {
+ current.y -= x * textHScale;
+ } else {
+ current.x += x * textHScale;
+ }
+
+ current.tspan.setAttributeNS(null, 'x',
+ current.xcoords.map(pf).join(' '));
+ current.tspan.setAttributeNS(null, 'y', pf(-current.y));
+ current.tspan.setAttributeNS(null, 'font-family', current.fontFamily);
+ current.tspan.setAttributeNS(null, 'font-size',
+ pf(current.fontSize) + 'px');
+ if (current.fontStyle !== SVG_DEFAULTS.fontStyle) {
+ current.tspan.setAttributeNS(null, 'font-style', current.fontStyle);
+ }
+ if (current.fontWeight !== SVG_DEFAULTS.fontWeight) {
+ current.tspan.setAttributeNS(null, 'font-weight', current.fontWeight);
+ }
+ if (current.fillColor !== SVG_DEFAULTS.fillColor) {
+ current.tspan.setAttributeNS(null, 'fill', current.fillColor);
+ }
+
+ current.txtElement.setAttributeNS(null, 'transform',
+ pm(current.textMatrix) +
+ ' scale(1, -1)' );
+ current.txtElement.setAttributeNS(XML_NS, 'xml:space', 'preserve');
+ current.txtElement.appendChild(current.tspan);
+ current.txtgrp.appendChild(current.txtElement);
+
+ this.tgrp.appendChild(current.txtElement);
+
+ },
+
+ setLeadingMoveText: function SVGGraphics_setLeadingMoveText(x, y) {
+ this.setLeading(-y);
+ this.moveText(x, y);
+ },
+
+ addFontStyle: function SVGGraphics_addFontStyle(fontObj) {
+ if (!this.cssStyle) {
+ this.cssStyle = document.createElementNS(NS, 'svg:style');
+ this.cssStyle.setAttributeNS(null, 'type', 'text/css');
+ this.defs.appendChild(this.cssStyle);
+ }
+
+ var url = PDFJS.createObjectURL(fontObj.data, fontObj.mimetype);
+ this.cssStyle.textContent +=
+ '@font-face { font-family: "' + fontObj.loadedName + '";' +
+ ' src: url(' + url + '); }\n';
+ },
+
+ setFont: function SVGGraphics_setFont(details) {
+ var current = this.current;
+ var fontObj = this.commonObjs.get(details[0]);
+ var size = details[1];
+ this.current.font = fontObj;
+
+ if (this.embedFonts && fontObj.data &&
+ !this.embeddedFonts[fontObj.loadedName]) {
+ this.addFontStyle(fontObj);
+ this.embeddedFonts[fontObj.loadedName] = fontObj;
+ }
+
+ current.fontMatrix = (fontObj.fontMatrix ?
+ fontObj.fontMatrix : FONT_IDENTITY_MATRIX);
+
+ var bold = fontObj.black ? (fontObj.bold ? 'bolder' : 'bold') :
+ (fontObj.bold ? 'bold' : 'normal');
+ var italic = fontObj.italic ? 'italic' : 'normal';
+
+ if (size < 0) {
+ size = -size;
+ current.fontDirection = -1;
+ } else {
+ current.fontDirection = 1;
+ }
+ current.fontSize = size;
+ current.fontFamily = fontObj.loadedName;
+ current.fontWeight = bold;
+ current.fontStyle = italic;
+
+ current.tspan = document.createElementNS(NS, 'svg:tspan');
+ current.tspan.setAttributeNS(null, 'y', pf(-current.y));
+ current.xcoords = [];
+ },
+
+ endText: function SVGGraphics_endText() {
+ if (this.current.pendingClip) {
+ this.cgrp.appendChild(this.tgrp);
+ this.pgrp.appendChild(this.cgrp);
+ } else {
+ this.pgrp.appendChild(this.tgrp);
+ }
+ this.tgrp = document.createElementNS(NS, 'svg:g');
+ this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
+ },
+
+ // Path properties
+ setLineWidth: function SVGGraphics_setLineWidth(width) {
+ this.current.lineWidth = width;
+ },
+ setLineCap: function SVGGraphics_setLineCap(style) {
+ this.current.lineCap = LINE_CAP_STYLES[style];
+ },
+ setLineJoin: function SVGGraphics_setLineJoin(style) {
+ this.current.lineJoin = LINE_JOIN_STYLES[style];
+ },
+ setMiterLimit: function SVGGraphics_setMiterLimit(limit) {
+ this.current.miterLimit = limit;
+ },
+ setStrokeRGBColor: function SVGGraphics_setStrokeRGBColor(r, g, b) {
+ var color = Util.makeCssRgb(arguments);
+ this.current.strokeColor = color;
+ },
+ setFillRGBColor: function SVGGraphics_setFillRGBColor(r, g, b) {
+ var color = Util.makeCssRgb(arguments);
+ this.current.fillColor = color;
+ this.current.tspan = document.createElementNS(NS, 'svg:tspan');
+ this.current.xcoords = [];
+ },
+ setDash: function SVGGraphics_setDash(dashArray, dashPhase) {
+ this.current.dashArray = dashArray;
+ this.current.dashPhase = dashPhase;
+ },
+
+ constructPath: function SVGGraphics_constructPath(ops, args) {
+ var current = this.current;
+ var x = current.x, y = current.y;
+ current.path = document.createElementNS(NS, 'svg:path');
+ var d = [];
+ var opLength = ops.length;
+
+ for (var i = 0, j = 0; i < opLength; i++) {
+ switch (ops[i] | 0) {
+ case OPS.rectangle:
+ x = args[j++];
+ y = args[j++];
+ var width = args[j++];
+ var height = args[j++];
+ var xw = x + width;
+ var yh = y + height;
+ d.push('M', pf(x), pf(y), 'L', pf(xw) , pf(y), 'L', pf(xw), pf(yh),
+ 'L', pf(x), pf(yh), 'Z');
+ break;
+ case OPS.moveTo:
+ x = args[j++];
+ y = args[j++];
+ d.push('M', pf(x), pf(y));
+ break;
+ case OPS.lineTo:
+ x = args[j++];
+ y = args[j++];
+ d.push('L', pf(x) , pf(y));
+ break;
+ case OPS.curveTo:
+ x = args[j + 4];
+ y = args[j + 5];
+ d.push('C', pf(args[j]), pf(args[j + 1]), pf(args[j + 2]),
+ pf(args[j + 3]), pf(x), pf(y));
+ j += 6;
+ break;
+ case OPS.curveTo2:
+ x = args[j + 2];
+ y = args[j + 3];
+ d.push('C', pf(x), pf(y), pf(args[j]), pf(args[j + 1]),
+ pf(args[j + 2]), pf(args[j + 3]));
+ j += 4;
+ break;
+ case OPS.curveTo3:
+ x = args[j + 2];
+ y = args[j + 3];
+ d.push('C', pf(args[j]), pf(args[j + 1]), pf(x), pf(y),
+ pf(x), pf(y));
+ j += 4;
+ break;
+ case OPS.closePath:
+ d.push('Z');
+ break;
+ }
+ }
+ current.path.setAttributeNS(null, 'd', d.join(' '));
+ current.path.setAttributeNS(null, 'stroke-miterlimit',
+ pf(current.miterLimit));
+ current.path.setAttributeNS(null, 'stroke-linecap', current.lineCap);
+ current.path.setAttributeNS(null, 'stroke-linejoin', current.lineJoin);
+ current.path.setAttributeNS(null, 'stroke-width',
+ pf(current.lineWidth) + 'px');
+ current.path.setAttributeNS(null, 'stroke-dasharray',
+ current.dashArray.map(pf).join(' '));
+ current.path.setAttributeNS(null, 'stroke-dashoffset',
+ pf(current.dashPhase) + 'px');
+ current.path.setAttributeNS(null, 'fill', 'none');
+
+ this.tgrp.appendChild(current.path);
+ if (current.pendingClip) {
+ this.cgrp.appendChild(this.tgrp);
+ this.pgrp.appendChild(this.cgrp);
+ } else {
+ this.pgrp.appendChild(this.tgrp);
+ }
+ // Saving a reference in current.element so that it can be addressed
+ // in 'fill' and 'stroke'
+ current.element = current.path;
+ current.setCurrentPoint(x, y);
+ },
+
+ endPath: function SVGGraphics_endPath() {
+ var current = this.current;
+ if (current.pendingClip) {
+ this.cgrp.appendChild(this.tgrp);
+ this.pgrp.appendChild(this.cgrp);
+ } else {
+ this.pgrp.appendChild(this.tgrp);
+ }
+ this.tgrp = document.createElementNS(NS, 'svg:g');
+ this.tgrp.setAttributeNS(null, 'transform', pm(this.transformMatrix));
+ },
+
+ clip: function SVGGraphics_clip(type) {
+ var current = this.current;
+ // Add current path to clipping path
+ current.clipId = 'clippath' + clipCount;
+ clipCount++;
+ this.clippath = document.createElementNS(NS, 'svg:clipPath');
+ this.clippath.setAttributeNS(null, 'id', current.clipId);
+ var clipElement = current.element.cloneNode();
+ if (type === 'evenodd') {
+ clipElement.setAttributeNS(null, 'clip-rule', 'evenodd');
+ } else {
+ clipElement.setAttributeNS(null, 'clip-rule', 'nonzero');
+ }
+ this.clippath.setAttributeNS(null, 'transform', pm(this.transformMatrix));
+ this.clippath.appendChild(clipElement);
+ this.defs.appendChild(this.clippath);
+
+ // Create a new group with that attribute
+ current.pendingClip = true;
+ this.cgrp = document.createElementNS(NS, 'svg:g');
+ this.cgrp.setAttributeNS(null, 'clip-path',
+ 'url(#' + current.clipId + ')');
+ this.pgrp.appendChild(this.cgrp);
+ },
+
+ closePath: function SVGGraphics_closePath() {
+ var current = this.current;
+ var d = current.path.getAttributeNS(null, 'd');
+ d += 'Z';
+ current.path.setAttributeNS(null, 'd', d);
+ },
+
+ setLeading: function SVGGraphics_setLeading(leading) {
+ this.current.leading = -leading;
+ },
+
+ setTextRise: function SVGGraphics_setTextRise(textRise) {
+ this.current.textRise = textRise;
+ },
+
+ setHScale: function SVGGraphics_setHScale(scale) {
+ this.current.textHScale = scale / 100;
+ },
+
+ setGState: function SVGGraphics_setGState(states) {
+ for (var i = 0, ii = states.length; i < ii; i++) {
+ var state = states[i];
+ var key = state[0];
+ var value = state[1];
+
+ switch (key) {
+ case 'LW':
+ this.setLineWidth(value);
+ break;
+ case 'LC':
+ this.setLineCap(value);
+ break;
+ case 'LJ':
+ this.setLineJoin(value);
+ break;
+ case 'ML':
+ this.setMiterLimit(value);
+ break;
+ case 'D':
+ this.setDash(value[0], value[1]);
+ break;
+ case 'RI':
+ break;
+ case 'FL':
+ break;
+ case 'Font':
+ this.setFont(value);
+ break;
+ case 'CA':
+ break;
+ case 'ca':
+ break;
+ case 'BM':
+ break;
+ case 'SMask':
+ break;
+ }
+ }
+ },
+
+ fill: function SVGGraphics_fill() {
+ var current = this.current;
+ current.element.setAttributeNS(null, 'fill', current.fillColor);
+ },
+
+ stroke: function SVGGraphics_stroke() {
+ var current = this.current;
+ current.element.setAttributeNS(null, 'stroke', current.strokeColor);
+ current.element.setAttributeNS(null, 'fill', 'none');
+ },
+
+ eoFill: function SVGGraphics_eoFill() {
+ var current = this.current;
+ current.element.setAttributeNS(null, 'fill', current.fillColor);
+ current.element.setAttributeNS(null, 'fill-rule', 'evenodd');
+ },
+
+ fillStroke: function SVGGraphics_fillStroke() {
+ // Order is important since stroke wants fill to be none.
+ // First stroke, then if fill needed, it will be overwritten.
+ this.stroke();
+ this.fill();
+ },
+
+ eoFillStroke: function SVGGraphics_eoFillStroke() {
+ this.current.element.setAttributeNS(null, 'fill-rule', 'evenodd');
+ this.fillStroke();
+ },
+
+ closeStroke: function SVGGraphics_closeStroke() {
+ this.closePath();
+ this.stroke();
+ },
+
+ closeFillStroke: function SVGGraphics_closeFillStroke() {
+ this.closePath();
+ this.fillStroke();
+ },
+
+ paintSolidColorImageMask:
+ function SVGGraphics_paintSolidColorImageMask() {
+ var current = this.current;
+ var rect = document.createElementNS(NS, 'svg:rect');
+ rect.setAttributeNS(null, 'x', '0');
+ rect.setAttributeNS(null, 'y', '0');
+ rect.setAttributeNS(null, 'width', '1px');
+ rect.setAttributeNS(null, 'height', '1px');
+ rect.setAttributeNS(null, 'fill', current.fillColor);
+ this.tgrp.appendChild(rect);
+ },
+
+ paintJpegXObject: function SVGGraphics_paintJpegXObject(objId, w, h) {
+ var current = this.current;
+ var imgObj = this.objs.get(objId);
+ var imgEl = document.createElementNS(NS, 'svg:image');
+ imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgObj.src);
+ imgEl.setAttributeNS(null, 'width', imgObj.width + 'px');
+ imgEl.setAttributeNS(null, 'height', imgObj.height + 'px');
+ imgEl.setAttributeNS(null, 'x', '0');
+ imgEl.setAttributeNS(null, 'y', pf(-h));
+ imgEl.setAttributeNS(null, 'transform',
+ 'scale(' + pf(1 / w) + ' ' + pf(-1 / h) + ')');
+
+ this.tgrp.appendChild(imgEl);
+ if (current.pendingClip) {
+ this.cgrp.appendChild(this.tgrp);
+ this.pgrp.appendChild(this.cgrp);
+ } else {
+ this.pgrp.appendChild(this.tgrp);
+ }
+ },
+
+ paintImageXObject: function SVGGraphics_paintImageXObject(objId) {
+ var imgData = this.objs.get(objId);
+ if (!imgData) {
+ warn('Dependent image isn\'t ready yet');
+ return;
+ }
+ this.paintInlineImageXObject(imgData);
+ },
+
+ paintInlineImageXObject:
+ function SVGGraphics_paintInlineImageXObject(imgData, mask) {
+ var current = this.current;
+ var width = imgData.width;
+ var height = imgData.height;
+
+ var imgSrc = convertImgDataToPng(imgData);
+ var cliprect = document.createElementNS(NS, 'svg:rect');
+ cliprect.setAttributeNS(null, 'x', '0');
+ cliprect.setAttributeNS(null, 'y', '0');
+ cliprect.setAttributeNS(null, 'width', pf(width));
+ cliprect.setAttributeNS(null, 'height', pf(height));
+ current.element = cliprect;
+ this.clip('nonzero');
+ var imgEl = document.createElementNS(NS, 'svg:image');
+ imgEl.setAttributeNS(XLINK_NS, 'xlink:href', imgSrc);
+ imgEl.setAttributeNS(null, 'x', '0');
+ imgEl.setAttributeNS(null, 'y', pf(-height));
+ imgEl.setAttributeNS(null, 'width', pf(width) + 'px');
+ imgEl.setAttributeNS(null, 'height', pf(height) + 'px');
+ imgEl.setAttributeNS(null, 'transform',
+ 'scale(' + pf(1 / width) + ' ' +
+ pf(-1 / height) + ')');
+ if (mask) {
+ mask.appendChild(imgEl);
+ } else {
+ this.tgrp.appendChild(imgEl);
+ }
+ if (current.pendingClip) {
+ this.cgrp.appendChild(this.tgrp);
+ this.pgrp.appendChild(this.cgrp);
+ } else {
+ this.pgrp.appendChild(this.tgrp);
+ }
+ },
+
+ paintImageMaskXObject:
+ function SVGGraphics_paintImageMaskXObject(imgData) {
+ var current = this.current;
+ var width = imgData.width;
+ var height = imgData.height;
+ var fillColor = current.fillColor;
+
+ current.maskId = 'mask' + maskCount++;
+ var mask = document.createElementNS(NS, 'svg:mask');
+ mask.setAttributeNS(null, 'id', current.maskId);
+
+ var rect = document.createElementNS(NS, 'svg:rect');
+ rect.setAttributeNS(null, 'x', '0');
+ rect.setAttributeNS(null, 'y', '0');
+ rect.setAttributeNS(null, 'width', pf(width));
+ rect.setAttributeNS(null, 'height', pf(height));
+ rect.setAttributeNS(null, 'fill', fillColor);
+ rect.setAttributeNS(null, 'mask', 'url(#' + current.maskId +')');
+ this.defs.appendChild(mask);
+ this.tgrp.appendChild(rect);
+
+ this.paintInlineImageXObject(imgData, mask);
+ },
+
+ paintFormXObjectBegin:
+ function SVGGraphics_paintFormXObjectBegin(matrix, bbox) {
+ this.save();
+
+ if (isArray(matrix) && matrix.length === 6) {
+ this.transform(matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+ }
+
+ if (isArray(bbox) && bbox.length === 4) {
+ var width = bbox[2] - bbox[0];
+ var height = bbox[3] - bbox[1];
+
+ var cliprect = document.createElementNS(NS, 'svg:rect');
+ cliprect.setAttributeNS(null, 'x', bbox[0]);
+ cliprect.setAttributeNS(null, 'y', bbox[1]);
+ cliprect.setAttributeNS(null, 'width', pf(width));
+ cliprect.setAttributeNS(null, 'height', pf(height));
+ this.current.element = cliprect;
+ this.clip('nonzero');
+ this.endPath();
+ }
+ },
+
+ paintFormXObjectEnd:
+ function SVGGraphics_paintFormXObjectEnd() {
+ this.restore();
+ }
+ };
+ return SVGGraphics;
+})();
+
+PDFJS.SVGGraphics = SVGGraphics;
+
+
}).call((typeof window === 'undefined') ? this : window);
if (!PDFJS.workerSrc && typeof document !== 'undefined') {
diff --git a/static/pdf.js/pdf.worker.js b/static/pdf.js/pdf.worker.js
index 1d984a552..cdb21230b 100644
--- a/static/pdf.js/pdf.worker.js
+++ b/static/pdf.js/pdf.worker.js
@@ -14,14 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/*jshint globalstrict: false */
+/* globals PDFJS */
// Initializing PDFJS global object (if still undefined)
if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '0.8.846';
-PDFJS.build = '05f937e';
+PDFJS.version = '1.0.908';
+PDFJS.build = '291671c';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@@ -50,7 +52,7 @@ PDFJS.build = '05f937e';
var globalScope = (typeof window === 'undefined') ? this : window;
-var isWorker = (typeof window == 'undefined');
+var isWorker = (typeof window === 'undefined');
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
@@ -67,6 +69,45 @@ var TextRenderingMode = {
ADD_TO_PATH_FLAG: 4
};
+var ImageKind = {
+ GRAYSCALE_1BPP: 1,
+ RGB_24BPP: 2,
+ RGBA_32BPP: 3
+};
+
+var AnnotationType = {
+ WIDGET: 1,
+ TEXT: 2,
+ LINK: 3
+};
+
+var StreamType = {
+ UNKNOWN: 0,
+ FLATE: 1,
+ LZW: 2,
+ DCT: 3,
+ JPX: 4,
+ JBIG: 5,
+ A85: 6,
+ AHX: 7,
+ CCF: 8,
+ RL: 9
+};
+
+var FontType = {
+ UNKNOWN: 0,
+ TYPE1: 1,
+ TYPE1C: 2,
+ CIDFONTTYPE0: 3,
+ CIDFONTTYPE0C: 4,
+ TRUETYPE: 5,
+ CIDFONTTYPE2: 6,
+ TYPE3: 7,
+ OPENTYPE: 8,
+ TYPE0: 9,
+ MMTYPE1: 10
+};
+
// The global PDFJS object exposes the API
// In production, it will be declared outside a global wrapper
// In development, it will be declared here
@@ -172,33 +213,26 @@ var OPS = PDFJS.OPS = {
paintImageMaskXObjectGroup: 84,
paintImageXObject: 85,
paintInlineImageXObject: 86,
- paintInlineImageXObjectGroup: 87
+ paintInlineImageXObjectGroup: 87,
+ paintImageXObjectRepeat: 88,
+ paintImageMaskXObjectRepeat: 89,
+ paintSolidColorImageMask: 90,
+ constructPath: 91
};
-// Use only for debugging purposes. This should not be used in any code that is
-// in mozilla master.
-var log = (function() {
- if ('console' in globalScope && 'log' in globalScope['console']) {
- return globalScope['console']['log'].bind(globalScope['console']);
- } else {
- return function nop() {
- };
- }
-})();
-
// A notice for devs. These are good for things that are helpful to devs, such
// as warning that Workers were disabled, which is important to devs but not
// end users.
function info(msg) {
if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
- log('Info: ' + msg);
+ console.log('Info: ' + msg);
}
}
// Non-fatal warnings.
function warn(msg) {
if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
- log('Warning: ' + msg);
+ console.log('Warning: ' + msg);
}
}
@@ -209,13 +243,13 @@ function error(msg) {
if (arguments.length > 1) {
var logArguments = ['Error:'];
logArguments.push.apply(logArguments, arguments);
- log.apply(null, logArguments);
+ console.log.apply(console, logArguments);
// Join the arguments into a single string for the lines below.
msg = [].join.call(arguments, ' ');
} else {
- log('Error: ' + msg);
+ console.log('Error: ' + msg);
}
- log(backtrace());
+ console.log(backtrace());
UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
throw new Error(msg);
}
@@ -229,8 +263,9 @@ function backtrace() {
}
function assert(cond, msg) {
- if (!cond)
+ if (!cond) {
error(msg);
+ }
}
var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
@@ -261,18 +296,25 @@ var UnsupportedManager = PDFJS.UnsupportedManager =
// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
// absolute URL, it will be returned as is.
function combineUrl(baseUrl, url) {
- if (!url)
+ if (!url) {
return baseUrl;
- if (url.indexOf(':') >= 0)
+ }
+ if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
return url;
- if (url.charAt(0) == '/') {
+ }
+ var i;
+ if (url.charAt(0) === '/') {
// absolute path
- var i = baseUrl.indexOf('://');
- i = baseUrl.indexOf('/', i + 3);
+ i = baseUrl.indexOf('://');
+ if (url.charAt(1) === '/') {
+ ++i;
+ } else {
+ i = baseUrl.indexOf('/', i + 3);
+ }
return baseUrl.substring(0, i) + url;
} else {
// relative path
- var pathLength = baseUrl.length, i;
+ var pathLength = baseUrl.length;
i = baseUrl.lastIndexOf('#');
pathLength = i >= 0 ? i : pathLength;
i = baseUrl.lastIndexOf('?', pathLength);
@@ -287,11 +329,13 @@ function isValidUrl(url, allowRelative) {
if (!url) {
return false;
}
- var colon = url.indexOf(':');
- if (colon < 0) {
+ // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
+ // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
+ if (!protocol) {
return allowRelative;
}
- var protocol = url.substr(0, colon);
+ protocol = protocol[0].toLowerCase();
switch (protocol) {
case 'http':
case 'https':
@@ -304,13 +348,6 @@ function isValidUrl(url, allowRelative) {
}
PDFJS.isValidUrl = isValidUrl;
-// In a well-formed PDF, |cond| holds. If it doesn't, subsequent
-// behavior is undefined.
-function assertWellFormed(cond, msg) {
- if (!cond)
- error(msg);
-}
-
function shadow(obj, prop, value) {
Object.defineProperty(obj, prop, { value: value,
enumerable: true,
@@ -336,6 +373,7 @@ var PasswordException = (function PasswordExceptionClosure() {
return PasswordException;
})();
+PDFJS.PasswordException = PasswordException;
var UnknownErrorException = (function UnknownErrorExceptionClosure() {
function UnknownErrorException(msg, details) {
@@ -349,6 +387,7 @@ var UnknownErrorException = (function UnknownErrorExceptionClosure() {
return UnknownErrorException;
})();
+PDFJS.UnknownErrorException = UnknownErrorException;
var InvalidPDFException = (function InvalidPDFExceptionClosure() {
function InvalidPDFException(msg) {
@@ -361,6 +400,7 @@ var InvalidPDFException = (function InvalidPDFExceptionClosure() {
return InvalidPDFException;
})();
+PDFJS.InvalidPDFException = InvalidPDFException;
var MissingPDFException = (function MissingPDFExceptionClosure() {
function MissingPDFException(msg) {
@@ -373,6 +413,22 @@ var MissingPDFException = (function MissingPDFExceptionClosure() {
return MissingPDFException;
})();
+PDFJS.MissingPDFException = MissingPDFException;
+
+var UnexpectedResponseException =
+ (function UnexpectedResponseExceptionClosure() {
+ function UnexpectedResponseException(msg, status) {
+ this.name = 'UnexpectedResponseException';
+ this.message = msg;
+ this.status = status;
+ }
+
+ UnexpectedResponseException.prototype = new Error();
+ UnexpectedResponseException.constructor = UnexpectedResponseException;
+
+ return UnexpectedResponseException;
+})();
+PDFJS.UnexpectedResponseException = UnexpectedResponseException;
var NotImplementedException = (function NotImplementedExceptionClosure() {
function NotImplementedException(msg) {
@@ -414,33 +470,142 @@ var XRefParseException = (function XRefParseExceptionClosure() {
function bytesToString(bytes) {
- var str = '';
var length = bytes.length;
- for (var n = 0; n < length; ++n)
- str += String.fromCharCode(bytes[n]);
- return str;
+ var MAX_ARGUMENT_COUNT = 8192;
+ if (length < MAX_ARGUMENT_COUNT) {
+ return String.fromCharCode.apply(null, bytes);
+ }
+ var strBuf = [];
+ for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
+ var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
+ var chunk = bytes.subarray(i, chunkEnd);
+ strBuf.push(String.fromCharCode.apply(null, chunk));
+ }
+ return strBuf.join('');
}
function stringToBytes(str) {
var length = str.length;
var bytes = new Uint8Array(length);
- for (var n = 0; n < length; ++n)
- bytes[n] = str.charCodeAt(n) & 0xFF;
+ for (var i = 0; i < length; ++i) {
+ bytes[i] = str.charCodeAt(i) & 0xFF;
+ }
return bytes;
}
+function string32(value) {
+ return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
+ (value >> 8) & 0xff, value & 0xff);
+}
+
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
+// Lazy test the endianness of the platform
+// NOTE: This will be 'true' for simulated TypedArrays
+function isLittleEndian() {
+ var buffer8 = new Uint8Array(2);
+ buffer8[0] = 1;
+ var buffer16 = new Uint16Array(buffer8.buffer);
+ return (buffer16[0] === 1);
+}
+
+Object.defineProperty(PDFJS, 'isLittleEndian', {
+ configurable: true,
+ get: function PDFJS_isLittleEndian() {
+ return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
+ }
+});
+
+ // Lazy test if the userAgant support CanvasTypedArrays
+function hasCanvasTypedArrays() {
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.createImageData(1, 1);
+ return (typeof imageData.data.buffer !== 'undefined');
+}
+
+Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
+ configurable: true,
+ get: function PDFJS_hasCanvasTypedArrays() {
+ return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
+ }
+});
+
+var Uint32ArrayView = (function Uint32ArrayViewClosure() {
+
+ function Uint32ArrayView(buffer, length) {
+ this.buffer = buffer;
+ this.byteLength = buffer.length;
+ this.length = length === undefined ? (this.byteLength >> 2) : length;
+ ensureUint32ArrayViewProps(this.length);
+ }
+ Uint32ArrayView.prototype = Object.create(null);
+
+ var uint32ArrayViewSetters = 0;
+ function createUint32ArrayProp(index) {
+ return {
+ get: function () {
+ var buffer = this.buffer, offset = index << 2;
+ return (buffer[offset] | (buffer[offset + 1] << 8) |
+ (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
+ },
+ set: function (value) {
+ var buffer = this.buffer, offset = index << 2;
+ buffer[offset] = value & 255;
+ buffer[offset + 1] = (value >> 8) & 255;
+ buffer[offset + 2] = (value >> 16) & 255;
+ buffer[offset + 3] = (value >>> 24) & 255;
+ }
+ };
+ }
+
+ function ensureUint32ArrayViewProps(length) {
+ while (uint32ArrayViewSetters < length) {
+ Object.defineProperty(Uint32ArrayView.prototype,
+ uint32ArrayViewSetters,
+ createUint32ArrayProp(uint32ArrayViewSetters));
+ uint32ArrayViewSetters++;
+ }
+ }
+
+ return Uint32ArrayView;
+})();
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = PDFJS.Util = (function UtilClosure() {
function Util() {}
- Util.makeCssRgb = function Util_makeCssRgb(rgb) {
- return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
- };
+ var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
- Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
- var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
- return Util.makeCssRgb(rgb);
+ // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
+ // creating many intermediate strings.
+ Util.makeCssRgb = function Util_makeCssRgb(rgb) {
+ rgbBuf[1] = rgb[0];
+ rgbBuf[3] = rgb[1];
+ rgbBuf[5] = rgb[2];
+ return rgbBuf.join('');
};
// Concatenates two transformation matrices together and returns the result.
@@ -590,12 +755,11 @@ var Util = PDFJS.Util = (function UtilClosure() {
return num < 0 ? -1 : 1;
};
- // TODO(mack): Rename appendToArray
- Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
+ Util.appendToArray = function Util_appendToArray(arr1, arr2) {
Array.prototype.push.apply(arr1, arr2);
};
- Util.prependToArray = function concatenateToArray(arr1, arr2) {
+ Util.prependToArray = function Util_prependToArray(arr1, arr2) {
Array.prototype.unshift.apply(arr1, arr2);
};
@@ -642,7 +806,22 @@ var Util = PDFJS.Util = (function UtilClosure() {
return Util;
})();
+/**
+ * PDF page viewport created based on scale, rotation and offset.
+ * @class
+ * @alias PDFJS.PageViewport
+ */
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
+ /**
+ * @constructor
+ * @private
+ * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
+ * @param scale {number} scale of the viewport.
+ * @param rotation {number} rotations of the viewport in degrees.
+ * @param offsetX {number} offset X
+ * @param offsetY {number} offset Y
+ * @param dontFlip {boolean} if true, axis Y will not be flipped.
+ */
function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
this.viewBox = viewBox;
this.scale = scale;
@@ -706,7 +885,14 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
this.height = height;
this.fontScale = scale;
}
- PageViewport.prototype = {
+ PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+ /**
+ * Clones viewport with additional properties.
+ * @param args {Object} (optional) If specified, may contain the 'scale' or
+ * 'rotation' properties to override the corresponding properties in
+ * the cloned viewport.
+ * @returns {PDFJS.PageViewport} Cloned viewport.
+ */
clone: function PageViewPort_clone(args) {
args = args || {};
var scale = 'scale' in args ? args.scale : this.scale;
@@ -714,15 +900,41 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
return new PageViewport(this.viewBox.slice(), scale, rotation,
this.offsetX, this.offsetY, args.dontFlip);
},
+ /**
+ * Converts PDF point to the viewport coordinates. For examples, useful for
+ * converting PDF location into canvas pixel coordinates.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the viewport coordinate space.
+ * @see {@link convertToPdfPoint}
+ * @see {@link convertToViewportRectangle}
+ */
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
return Util.applyTransform([x, y], this.transform);
},
+ /**
+ * Converts PDF rectangle to the viewport coordinates.
+ * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
+ * @returns {Array} Contains corresponding coordinates of the rectangle
+ * in the viewport coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToViewportRectangle:
function PageViewport_convertToViewportRectangle(rect) {
var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
var br = Util.applyTransform([rect[2], rect[3]], this.transform);
return [tl[0], tl[1], br[0], br[1]];
},
+ /**
+ * Converts viewport coordinates to the PDF location. For examples, useful
+ * for converting canvas pixel location into PDF one.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the PDF coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
return Util.applyInverseTransform([x, y], this.transform);
}
@@ -743,19 +955,20 @@ var PDFStringTranslateTable = [
];
function stringToPDFString(str) {
- var i, n = str.length, str2 = '';
+ var i, n = str.length, strBuf = [];
if (str[0] === '\xFE' && str[1] === '\xFF') {
// UTF16BE BOM
- for (i = 2; i < n; i += 2)
- str2 += String.fromCharCode(
- (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1));
+ for (i = 2; i < n; i += 2) {
+ strBuf.push(String.fromCharCode(
+ (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
+ }
} else {
for (i = 0; i < n; ++i) {
var code = PDFStringTranslateTable[str.charCodeAt(i)];
- str2 += code ? String.fromCharCode(code) : str.charAt(i);
+ strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
}
}
- return str2;
+ return strBuf.join('');
}
function stringToUTF8String(str) {
@@ -770,19 +983,19 @@ function isEmptyObj(obj) {
}
function isBool(v) {
- return typeof v == 'boolean';
+ return typeof v === 'boolean';
}
function isInt(v) {
- return typeof v == 'number' && ((v | 0) == v);
+ return typeof v === 'number' && ((v | 0) === v);
}
function isNum(v) {
- return typeof v == 'number';
+ return typeof v === 'number';
}
function isString(v) {
- return typeof v == 'string';
+ return typeof v === 'string';
}
function isNull(v) {
@@ -794,7 +1007,7 @@ function isName(v) {
}
function isCmd(v, cmd) {
- return v instanceof Cmd && (!cmd || v.cmd == cmd);
+ return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
}
function isDict(v, type) {
@@ -805,7 +1018,7 @@ function isDict(v, type) {
return true;
}
var dictType = v.get('Type');
- return isName(dictType) && dictType.name == type;
+ return isName(dictType) && dictType.name === type;
}
function isArray(v) {
@@ -813,52 +1026,47 @@ function isArray(v) {
}
function isStream(v) {
- return typeof v == 'object' && v !== null && v !== undefined &&
- ('getBytes' in v);
+ return typeof v === 'object' && v !== null && v.getBytes !== undefined;
}
function isArrayBuffer(v) {
- return typeof v == 'object' && v !== null && v !== undefined &&
- ('byteLength' in v);
+ return typeof v === 'object' && v !== null && v.byteLength !== undefined;
}
function isRef(v) {
return v instanceof Ref;
}
-function isPDFFunction(v) {
- var fnDict;
- if (typeof v != 'object')
- return false;
- else if (isDict(v))
- fnDict = v;
- else if (isStream(v))
- fnDict = v.dict;
- else
- return false;
- return fnDict.has('FunctionType');
-}
+/**
+ * Promise Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
/**
- * Legacy support for PDFJS Promise implementation.
- * TODO remove eventually
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
*/
-var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
- return function LegacyPromise() {
- var resolve, reject;
- var promise = new Promise(function (resolve_, reject_) {
- resolve = resolve_;
- reject = reject_;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- };
-})();
+function createPromiseCapability() {
+ var capability = {};
+ capability.promise = new Promise(function (resolve, reject) {
+ capability.resolve = resolve;
+ capability.reject = reject;
+ });
+ return capability;
+}
+
+PDFJS.createPromiseCapability = createPromiseCapability;
/**
* Polyfill for Promises:
- * The following promise implementation tries to generally implment the
+ * The following promise implementation tries to generally implement the
* Promise/A+ spec. Some notable differences from other promise libaries are:
* - There currently isn't a seperate deferred and promise object.
* - Unhandled rejections eventually show an error if they aren't handled.
@@ -893,8 +1101,20 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
};
}
if (typeof globalScope.Promise.resolve !== 'function') {
- globalScope.Promise.resolve = function (x) {
- return new globalScope.Promise(function (resolve) { resolve(x); });
+ globalScope.Promise.resolve = function (value) {
+ return new globalScope.Promise(function (resolve) { resolve(value); });
+ };
+ }
+ if (typeof globalScope.Promise.reject !== 'function') {
+ globalScope.Promise.reject = function (reason) {
+ return new globalScope.Promise(function (resolve, reject) {
+ reject(reason);
+ });
+ };
+ }
+ if (typeof globalScope.Promise.prototype.catch !== 'function') {
+ globalScope.Promise.prototype.catch = function (onReject) {
+ return globalScope.Promise.prototype.then(undefined, onReject);
};
}
return;
@@ -915,7 +1135,7 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
pendingRejectionCheck: false,
scheduleHandlers: function scheduleHandlers(promise) {
- if (promise._status == STATUS_PENDING) {
+ if (promise._status === STATUS_PENDING) {
return;
}
@@ -941,10 +1161,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
try {
if (nextStatus === STATUS_RESOLVED) {
- if (typeof(handler.onResolve) == 'function') {
+ if (typeof handler.onResolve === 'function') {
nextValue = handler.onResolve(nextValue);
}
- } else if (typeof(handler.onReject) === 'function') {
+ } else if (typeof handler.onReject === 'function') {
nextValue = handler.onReject(nextValue);
nextStatus = STATUS_RESOLVED;
@@ -1019,7 +1239,11 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
function Promise(resolver) {
this._status = STATUS_PENDING;
this._handlers = [];
- resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ try {
+ resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ } catch (e) {
+ this._reject(e);
+ }
}
/**
* Builds a promise that is resolved when all the passed in promises are
@@ -1055,8 +1279,9 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
}
results[i] = value;
unresolved--;
- if (unresolved === 0)
+ if (unresolved === 0) {
resolveAll(results);
+ }
};
})(i);
if (Promise.isPromise(promise)) {
@@ -1070,18 +1295,28 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
/**
* Checks if the value is likely a promise (has a 'then' function).
- * @return {boolean} true if x is thenable
+ * @return {boolean} true if value is thenable
*/
Promise.isPromise = function Promise_isPromise(value) {
return value && typeof value.then === 'function';
};
+
/**
* Creates resolved promise
- * @param x resolve value
+ * @param value resolve value
* @returns {Promise}
*/
- Promise.resolve = function Promise_resolve(x) {
- return new Promise(function (resolve) { resolve(x); });
+ Promise.resolve = function Promise_resolve(value) {
+ return new Promise(function (resolve) { resolve(value); });
+ };
+
+ /**
+ * Creates rejected promise
+ * @param reason rejection value
+ * @returns {Promise}
+ */
+ Promise.reject = function Promise_reject(reason) {
+ return new Promise(function (resolve, reject) { reject(reason); });
};
Promise.prototype = {
@@ -1096,7 +1331,7 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
return;
}
- if (status == STATUS_RESOLVED &&
+ if (status === STATUS_RESOLVED &&
Promise.isPromise(value)) {
value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
this._updateStatus.bind(this, STATUS_REJECTED));
@@ -1124,7 +1359,7 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
then: function Promise_then(onResolve, onReject) {
var nextPromise = new Promise(function (resolve, reject) {
- this.resolve = reject;
+ this.resolve = resolve;
this.reject = reject;
});
this._handlers.push({
@@ -1135,6 +1370,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
});
HandlerManager.scheduleHandlers(this);
return nextPromise;
+ },
+
+ catch: function Promise_catch(onReject) {
+ return this.then(undefined, onReject);
}
};
@@ -1143,8 +1382,9 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
var StatTimer = (function StatTimerClosure() {
function rpad(str, pad, length) {
- while (str.length < length)
+ while (str.length < length) {
str += pad;
+ }
return str;
}
function StatTimer() {
@@ -1154,17 +1394,21 @@ var StatTimer = (function StatTimerClosure() {
}
StatTimer.prototype = {
time: function StatTimer_time(name) {
- if (!this.enabled)
+ if (!this.enabled) {
return;
- if (name in this.started)
+ }
+ if (name in this.started) {
warn('Timer is already running for ' + name);
+ }
this.started[name] = Date.now();
},
timeEnd: function StatTimer_timeEnd(name) {
- if (!this.enabled)
+ if (!this.enabled) {
return;
- if (!(name in this.started))
+ }
+ if (!(name in this.started)) {
warn('Timer has not been started for ' + name);
+ }
this.times.push({
'name': name,
'start': this.started[name],
@@ -1174,16 +1418,18 @@ var StatTimer = (function StatTimerClosure() {
delete this.started[name];
},
toString: function StatTimer_toString() {
+ var i, ii;
var times = this.times;
var out = '';
// Find the longest name for padding purposes.
var longest = 0;
- for (var i = 0, ii = times.length; i < ii; ++i) {
+ for (i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
- if (name.length > longest)
+ if (name.length > longest) {
longest = name.length;
+ }
}
- for (var i = 0, ii = times.length; i < ii; ++i) {
+ for (i = 0, ii = times.length; i < ii; ++i) {
var span = times[i];
var duration = span.end - span.start;
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
@@ -1195,8 +1441,9 @@ var StatTimer = (function StatTimerClosure() {
})();
PDFJS.createBlob = function createBlob(data, contentType) {
- if (typeof Blob !== 'undefined')
+ if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType });
+ }
// Blob builder is deprecated in FF14 and removed in FF18.
var bb = new MozBlobBuilder();
bb.append(data);
@@ -1204,18 +1451,17 @@ PDFJS.createBlob = function createBlob(data, contentType) {
};
PDFJS.createObjectURL = (function createObjectURLClosure() {
- if (typeof URL !== 'undefined' && URL.createObjectURL) {
- return function createObjectURL(data, contentType) {
- var blob = PDFJS.createBlob(data, contentType);
- return URL.createObjectURL(blob);
- };
- }
-
// Blob/createObjectURL is not available, falling back to data schema.
var digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
return function createObjectURL(data, contentType) {
+ if (!PDFJS.disableCreateObjectURL &&
+ typeof URL !== 'undefined' && URL.createObjectURL) {
+ var blob = PDFJS.createBlob(data, contentType);
+ return URL.createObjectURL(blob);
+ }
+
var buffer = 'data:' + contentType + ';base64,';
for (var i = 0, ii = data.length; i < ii; i += 3) {
var b1 = data[i] & 0xFF;
@@ -1235,23 +1481,15 @@ function MessageHandler(name, comObj) {
this.comObj = comObj;
this.callbackIndex = 1;
this.postMessageTransfers = true;
- var callbacks = this.callbacks = {};
+ var callbacksCapabilities = this.callbacksCapabilities = {};
var ah = this.actionHandler = {};
ah['console_log'] = [function ahConsoleLog(data) {
- log.apply(null, data);
+ console.log.apply(console, data);
+ }];
+ ah['console_error'] = [function ahConsoleError(data) {
+ console.error.apply(console, data);
}];
- // If there's no console available, console_error in the
- // action handler will do nothing.
- if ('console' in globalScope) {
- ah['console_error'] = [function ahConsoleError(data) {
- globalScope['console'].error.apply(null, data);
- }];
- } else {
- ah['console_error'] = [function ahConsoleError(data) {
- log.apply(null, data);
- }];
- }
ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
UnsupportedManager.notify(data);
}];
@@ -1260,35 +1498,40 @@ function MessageHandler(name, comObj) {
var data = event.data;
if (data.isReply) {
var callbackId = data.callbackId;
- if (data.callbackId in callbacks) {
- var callback = callbacks[callbackId];
- delete callbacks[callbackId];
- callback(data.data);
+ if (data.callbackId in callbacksCapabilities) {
+ var callback = callbacksCapabilities[callbackId];
+ delete callbacksCapabilities[callbackId];
+ if ('error' in data) {
+ callback.reject(data.error);
+ } else {
+ callback.resolve(data.data);
+ }
} else {
error('Cannot resolve callback ' + callbackId);
}
} else if (data.action in ah) {
var action = ah[data.action];
if (data.callbackId) {
- var deferred = {};
- var promise = new Promise(function (resolve, reject) {
- deferred.resolve = resolve;
- deferred.reject = reject;
- });
- deferred.promise = promise;
- promise.then(function(resolvedData) {
+ Promise.resolve().then(function () {
+ return action[0].call(action[1], data.data);
+ }).then(function (result) {
comObj.postMessage({
isReply: true,
callbackId: data.callbackId,
- data: resolvedData
+ data: result
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ isReply: true,
+ callbackId: data.callbackId,
+ error: reason
});
});
- action[0].call(action[1], data.data, deferred);
} else {
action[0].call(action[1], data.data);
}
} else {
- error('Unkown action from worker: ' + data.action);
+ error('Unknown action from worker: ' + data.action);
}
};
}
@@ -1305,19 +1548,47 @@ MessageHandler.prototype = {
* Sends a message to the comObj to invoke the action with the supplied data.
* @param {String} actionName Action to call.
* @param {JSON} data JSON data to send.
- * @param {function} [callback] Optional callback that will handle a reply.
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
*/
- send: function messageHandlerSend(actionName, data, callback, transfers) {
+ send: function messageHandlerSend(actionName, data, transfers) {
var message = {
action: actionName,
data: data
};
- if (callback) {
- var callbackId = this.callbackIndex++;
- this.callbacks[callbackId] = callback;
- message.callbackId = callbackId;
+ this.postMessage(message, transfers);
+ },
+ /**
+ * Sends a message to the comObj to invoke the action with the supplied data.
+ * Expects that other side will callback with the response.
+ * @param {String} actionName Action to call.
+ * @param {JSON} data JSON data to send.
+ * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
+ * @returns {Promise} Promise to be resolved with response data.
+ */
+ sendWithPromise:
+ function messageHandlerSendWithPromise(actionName, data, transfers) {
+ var callbackId = this.callbackIndex++;
+ var message = {
+ action: actionName,
+ data: data,
+ callbackId: callbackId
+ };
+ var capability = createPromiseCapability();
+ this.callbacksCapabilities[callbackId] = capability;
+ try {
+ this.postMessage(message, transfers);
+ } catch (e) {
+ capability.reject(e);
}
+ return capability.promise;
+ },
+ /**
+ * Sends raw message to the comObj.
+ * @private
+ * @param message {Object} Raw message.
+ * @param transfers List of transfers/ArrayBuffers, or undefined.
+ */
+ postMessage: function (message, transfers) {
if (transfers && this.postMessageTransfers) {
this.comObj.postMessage(message, transfers);
} else {
@@ -1331,2833 +1602,14 @@ function loadJpegStream(id, imageUrl, objs) {
img.onload = (function loadJpegStream_onloadClosure() {
objs.resolve(id, img);
});
+ img.onerror = (function loadJpegStream_onerrorClosure() {
+ objs.resolve(id, null);
+ warn('Error during JPEG image loading');
+ });
img.src = imageUrl;
}
-var ColorSpace = (function ColorSpaceClosure() {
- // Constructor should define this.numComps, this.defaultColor, this.name
- function ColorSpace() {
- error('should not call ColorSpace constructor');
- }
-
- ColorSpace.prototype = {
- /**
- * Converts the color value to the RGB color. The color components are
- * located in the src array starting from the srcOffset. Returns the array
- * of the rgb components, each value ranging from [0,255].
- */
- getRgb: function ColorSpace_getRgb(src, srcOffset) {
- error('Should not call ColorSpace.getRgb');
- },
- /**
- * Converts the color value to the RGB color, similar to the getRgb method.
- * The result placed into the dest array starting from the destOffset.
- */
- getRgbItem: function ColorSpace_getRgb(src, srcOffset, dest, destOffset) {
- error('Should not call ColorSpace.getRgbItem');
- },
- /**
- * Converts the specified number of the color values to the RGB colors.
- * The colors are located in the src array starting from the srcOffset.
- * The result is placed into the dest array starting from the destOffset.
- * The src array items shall be in [0,2^bits) range, the dest array items
- * will be in [0,255] range.
- */
- getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- error('Should not call ColorSpace.getRgbBuffer');
- },
- /**
- * Determines amount of the bytes is required to store the reslut of the
- * conversion that done by the getRgbBuffer method.
- */
- getOutputLength: function ColorSpace_getOutputLength(inputLength) {
- error('Should not call ColorSpace.getOutputLength');
- },
- /**
- * Returns true if source data will be equal the result/output data.
- */
- isPassthrough: function ColorSpace_isPassthrough(bits) {
- return false;
- },
- /**
- * Creates the output buffer and converts the specified number of the color
- * values to the RGB colors, similar to the getRgbBuffer.
- */
- createRgbBuffer: function ColorSpace_createRgbBuffer(src, srcOffset,
- count, bits) {
- if (this.isPassthrough(bits)) {
- return src.subarray(srcOffset);
- }
- var dest = new Uint8Array(count * 3);
- var numComponentColors = 1 << bits;
- // Optimization: create a color map when there is just one component and
- // we are converting more colors than the size of the color map. We
- // don't build the map if the colorspace is gray or rgb since those
- // methods are faster than building a map. This mainly offers big speed
- // ups for indexed and alternate colorspaces.
- if (this.numComps === 1 && count > numComponentColors &&
- this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
- // TODO it may be worth while to cache the color map. While running
- // testing I never hit a cache so I will leave that out for now (perhaps
- // we are reparsing colorspaces too much?).
- var allColors = bits <= 8 ? new Uint8Array(numComponentColors) :
- new Uint16Array(numComponentColors);
- for (var i = 0; i < numComponentColors; i++) {
- allColors[i] = i;
- }
- var colorMap = new Uint8Array(numComponentColors * 3);
- this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bits);
-
- var destOffset = 0;
- for (var i = 0; i < count; ++i) {
- var key = src[srcOffset++] * 3;
- dest[destOffset++] = colorMap[key];
- dest[destOffset++] = colorMap[key + 1];
- dest[destOffset++] = colorMap[key + 2];
- }
- return dest;
- }
- this.getRgbBuffer(src, srcOffset, count, dest, 0, bits);
- return dest;
- },
- /**
- * True if the colorspace has components in the default range of [0, 1].
- * This should be true for all colorspaces except for lab color spaces
- * which are [0,100], [-128, 127], [-128, 127].
- */
- usesZeroToOneRange: true
- };
-
- ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
- var IR = ColorSpace.parseToIR(cs, xref, res);
- if (IR instanceof AlternateCS)
- return IR;
-
- return ColorSpace.fromIR(IR);
- };
-
- ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
- var name = isArray(IR) ? IR[0] : IR;
-
- switch (name) {
- case 'DeviceGrayCS':
- return this.singletons.gray;
- case 'DeviceRgbCS':
- return this.singletons.rgb;
- case 'DeviceCmykCS':
- return this.singletons.cmyk;
- case 'CalGrayCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var gamma = IR[1].Gamma;
- return new CalGrayCS(whitePoint, blackPoint, gamma);
- case 'PatternCS':
- var basePatternCS = IR[1];
- if (basePatternCS)
- basePatternCS = ColorSpace.fromIR(basePatternCS);
- return new PatternCS(basePatternCS);
- case 'IndexedCS':
- var baseIndexedCS = IR[1];
- var hiVal = IR[2];
- var lookup = IR[3];
- return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
- case 'AlternateCS':
- var numComps = IR[1];
- var alt = IR[2];
- var tintFnIR = IR[3];
-
- return new AlternateCS(numComps, ColorSpace.fromIR(alt),
- PDFFunction.fromIR(tintFnIR));
- case 'LabCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var range = IR[1].Range;
- return new LabCS(whitePoint, blackPoint, range);
- default:
- error('Unkown name ' + name);
- }
- return null;
- };
-
- ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
- if (isName(cs)) {
- var colorSpaces = res.get('ColorSpace');
- if (isDict(colorSpaces)) {
- var refcs = colorSpaces.get(cs.name);
- if (refcs)
- cs = refcs;
- }
- }
-
- cs = xref.fetchIfRef(cs);
- var mode;
-
- if (isName(cs)) {
- mode = cs.name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'Pattern':
- return ['PatternCS', null];
- default:
- error('unrecognized colorspace ' + mode);
- }
- } else if (isArray(cs)) {
- mode = cs[0].name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'CalGray':
- var params = cs[1].getAll();
- return ['CalGrayCS', params];
- case 'CalRGB':
- return 'DeviceRgbCS';
- case 'ICCBased':
- var stream = xref.fetchIfRef(cs[1]);
- var dict = stream.dict;
- var numComps = dict.get('N');
- if (numComps == 1)
- return 'DeviceGrayCS';
- if (numComps == 3)
- return 'DeviceRgbCS';
- if (numComps == 4)
- return 'DeviceCmykCS';
- break;
- case 'Pattern':
- var basePatternCS = cs[1];
- if (basePatternCS)
- basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
- return ['PatternCS', basePatternCS];
- case 'Indexed':
- case 'I':
- var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
- var hiVal = cs[2] + 1;
- var lookup = xref.fetchIfRef(cs[3]);
- if (isStream(lookup)) {
- lookup = lookup.getBytes();
- }
- return ['IndexedCS', baseIndexedCS, hiVal, lookup];
- case 'Separation':
- case 'DeviceN':
- var name = cs[1];
- var numComps = 1;
- if (isName(name))
- numComps = 1;
- else if (isArray(name))
- numComps = name.length;
- var alt = ColorSpace.parseToIR(cs[2], xref, res);
- var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
- return ['AlternateCS', numComps, alt, tintFnIR];
- case 'Lab':
- var params = cs[1].getAll();
- return ['LabCS', params];
- default:
- error('unimplemented color space object "' + mode + '"');
- }
- } else {
- error('unrecognized color space object: "' + cs + '"');
- }
- return null;
- };
- /**
- * Checks if a decode map matches the default decode map for a color space.
- * This handles the general decode maps where there are two values per
- * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
- * This does not handle Lab, Indexed, or Pattern decode maps since they are
- * slightly different.
- * @param {Array} decode Decode map (usually from an image).
- * @param {Number} n Number of components the color space has.
- */
- ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
- if (!decode)
- return true;
-
- if (n * 2 !== decode.length) {
- warn('The decode map is not the correct length');
- return true;
- }
- for (var i = 0, ii = decode.length; i < ii; i += 2) {
- if (decode[i] !== 0 || decode[i + 1] != 1)
- return false;
- }
- return true;
- };
-
- ColorSpace.singletons = {
- get gray() {
- return shadow(this, 'gray', new DeviceGrayCS());
- },
- get rgb() {
- return shadow(this, 'rgb', new DeviceRgbCS());
- },
- get cmyk() {
- return shadow(this, 'cmyk', new DeviceCmykCS());
- }
- };
-
- return ColorSpace;
-})();
-
-/**
- * Alternate color space handles both Separation and DeviceN color spaces. A
- * Separation color space is actually just a DeviceN with one color component.
- * Both color spaces use a tinting function to convert colors to a base color
- * space.
- */
-var AlternateCS = (function AlternateCSClosure() {
- function AlternateCS(numComps, base, tintFn) {
- this.name = 'Alternate';
- this.numComps = numComps;
- this.defaultColor = new Float32Array(numComps);
- for (var i = 0; i < numComps; ++i) {
- this.defaultColor[i] = 1;
- }
- this.base = base;
- this.tintFn = tintFn;
- }
-
- AlternateCS.prototype = {
- getRgb: function AlternateCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var baseNumComps = this.base.numComps;
- var input = 'subarray' in src ?
- src.subarray(srcOffset, srcOffset + this.numComps) :
- Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
- var tinted = this.tintFn(input);
- this.base.getRgbItem(tinted, 0, dest, destOffset);
- },
- getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var tintFn = this.tintFn;
- var base = this.base;
- var scale = 1 / ((1 << bits) - 1);
- var baseNumComps = base.numComps;
- var usesZeroToOneRange = base.usesZeroToOneRange;
- var isPassthrough = base.isPassthrough(8) || !usesZeroToOneRange;
- var pos = isPassthrough ? destOffset : 0;
- var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
- var numComps = this.numComps;
-
- var scaled = new Float32Array(numComps);
- for (var i = 0; i < count; i++) {
- for (var j = 0; j < numComps; j++) {
- scaled[j] = src[srcOffset++] * scale;
- }
- var tinted = tintFn(scaled);
- if (usesZeroToOneRange) {
- for (var j = 0; j < baseNumComps; j++) {
- baseBuf[pos++] = tinted[j] * 255;
- }
- } else {
- base.getRgbItem(tinted, 0, baseBuf, pos);
- pos += baseNumComps;
- }
- }
- if (!isPassthrough) {
- base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8);
- }
- },
- getOutputLength: function AlternateCS_getOutputLength(inputLength) {
- return this.base.getOutputLength(inputLength *
- this.base.numComps / this.numComps);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return AlternateCS;
-})();
-
-var PatternCS = (function PatternCSClosure() {
- function PatternCS(baseCS) {
- this.name = 'Pattern';
- this.base = baseCS;
- }
- PatternCS.prototype = {};
-
- return PatternCS;
-})();
-
-var IndexedCS = (function IndexedCSClosure() {
- function IndexedCS(base, highVal, lookup) {
- this.name = 'Indexed';
- this.numComps = 1;
- this.defaultColor = new Uint8Array([0]);
- this.base = base;
- this.highVal = highVal;
-
- var baseNumComps = base.numComps;
- var length = baseNumComps * highVal;
- var lookupArray;
-
- if (isStream(lookup)) {
- lookupArray = new Uint8Array(length);
- var bytes = lookup.getBytes(length);
- lookupArray.set(bytes);
- } else if (isString(lookup)) {
- lookupArray = new Uint8Array(length);
- for (var i = 0; i < length; ++i)
- lookupArray[i] = lookup.charCodeAt(i);
- } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
- lookupArray = lookup;
- } else {
- error('Unrecognized lookup table: ' + lookup);
- }
- this.lookup = lookupArray;
- }
-
- IndexedCS.prototype = {
- getRgb: function IndexedCS_getRgb(src, srcOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- return this.base.getRgb(this.lookup, start);
- },
- getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- this.base.getRgbItem(this.lookup, start, dest, destOffset);
- },
- getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset) {
- var base = this.base;
- var numComps = base.numComps;
- var outputDelta = base.getOutputLength(numComps);
- var lookup = this.lookup;
-
- for (var i = 0; i < count; ++i) {
- var lookupPos = src[srcOffset++] * numComps;
- base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8);
- destOffset += outputDelta;
- }
- },
- getOutputLength: function IndexedCS_getOutputLength(inputLength) {
- return this.base.getOutputLength(inputLength * this.base.numComps);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
- // indexed color maps shouldn't be changed
- return true;
- },
- usesZeroToOneRange: true
- };
- return IndexedCS;
-})();
-
-var DeviceGrayCS = (function DeviceGrayCSClosure() {
- function DeviceGrayCS() {
- this.name = 'DeviceGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
- }
-
- DeviceGrayCS.prototype = {
- getRgb: function DeviceGrayCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var c = (src[srcOffset] * 255) | 0;
- c = c < 0 ? 0 : c > 255 ? 255 : c;
- dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
- },
- getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- var c = (scale * src[j++]) | 0;
- dest[q++] = c;
- dest[q++] = c;
- dest[q++] = c;
- }
- },
- getOutputLength: function DeviceGrayCS_getOutputLength(inputLength) {
- return inputLength * 3;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceGrayCS;
-})();
-
-var DeviceRgbCS = (function DeviceRgbCSClosure() {
- function DeviceRgbCS() {
- this.name = 'DeviceRGB';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
- }
- DeviceRgbCS.prototype = {
- getRgb: function DeviceRgbCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var r = (src[srcOffset] * 255) | 0;
- var g = (src[srcOffset + 1] * 255) | 0;
- var b = (src[srcOffset + 2] * 255) | 0;
- dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
- dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
- dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
- },
- getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var length = count * 3;
- if (bits == 8) {
- dest.set(src.subarray(srcOffset, srcOffset + length), destOffset);
- return;
- }
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < length; ++i) {
- dest[q++] = (scale * src[j++]) | 0;
- }
- },
- getOutputLength: function DeviceRgbCS_getOutputLength(inputLength) {
- return inputLength;
- },
- isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
- return bits == 8;
- },
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceRgbCS;
-})();
-
-var DeviceCmykCS = (function DeviceCmykCSClosure() {
- // The coefficients below was found using numerical analysis: the method of
- // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
- // where color_value is the tabular value from the table of sampled RGB colors
- // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
- // CMYK color conversion using the estimation below:
- // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
- function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
- var c = src[srcOffset + 0] * srcScale;
- var m = src[srcOffset + 1] * srcScale;
- var y = src[srcOffset + 2] * srcScale;
- var k = src[srcOffset + 3] * srcScale;
-
- var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
- var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
- var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
-
- dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
- dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
- dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
- }
-
- function DeviceCmykCS() {
- this.name = 'DeviceCMYK';
- this.numComps = 4;
- this.defaultColor = new Float32Array([0, 0, 0, 1]);
- }
- DeviceCmykCS.prototype = {
- getRgb: function DeviceCmykCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- convertToRgb(src, srcOffset, 1, rgb, 0);
- return rgb;
- },
- getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(src, srcOffset, 1, dest, destOffset);
- },
- getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var scale = 1 / ((1 << bits) - 1);
- for (var i = 0; i < count; i++) {
- convertToRgb(src, srcOffset, scale, dest, destOffset);
- srcOffset += 4;
- destOffset += 3;
- }
- },
- getOutputLength: function DeviceCmykCS_getOutputLength(inputLength) {
- return (inputLength >> 2) * 3;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return DeviceCmykCS;
-})();
-
-//
-// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
-//
-var CalGrayCS = (function CalGrayCSClosure() {
- function CalGrayCS(whitePoint, blackPoint, gamma) {
- this.name = 'CalGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
-
- if (!whitePoint) {
- error('WhitePoint missing - required for color space CalGray');
- }
- blackPoint = blackPoint || [0, 0, 0];
- gamma = gamma || 1;
-
- // Translate arguments to spec variables.
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
-
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- this.G = gamma;
-
- // Validate variables as per spec.
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
- error('Invalid WhitePoint components for ' + this.name +
- ', no fallback available');
- }
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint for ' + this.name + ', falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
- warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
- ', ZB: ' + this.ZB + ', only default values are supported.');
- }
-
- if (this.G < 1) {
- info('Invalid Gamma: ' + this.G + ' for ' + this.name +
- ', falling back to default');
- this.G = 1;
- }
- }
-
- function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
- // A represents a gray component of a calibrated gray space.
- // A <---> AG in the spec
- var A = src[srcOffset] * scale;
- var AG = Math.pow(A, cs.G);
-
- // Computes intermediate variables M, L, N as per spec.
- // Except if other than default BlackPoint values are used.
- var M = cs.XW * AG;
- var L = cs.YW * AG;
- var N = cs.ZW * AG;
-
- // Decode XYZ, as per spec.
- var X = M;
- var Y = L;
- var Z = N;
-
- // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
- // This yields values in range [0, 100].
- var Lstar = Math.max(116 * Math.pow(Y, 1 / 3) - 16, 0);
-
- // Convert values to rgb range [0, 255].
- dest[destOffset] = Lstar * 255 / 100;
- dest[destOffset + 1] = Lstar * 255 / 100;
- dest[destOffset + 2] = Lstar * 255 / 100;
- }
-
- CalGrayCS.prototype = {
- getRgb: function CalGrayCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(this, src, srcOffset, dest, destOffset, 1);
- },
- getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var scale = 1 / ((1 << bits) - 1);
-
- for (var i = 0; i < count; ++i) {
- convertToRgb(this, src, srcOffset, dest, destOffset, scale);
- srcOffset += 1;
- destOffset += 3;
- }
- },
- getOutputLength: function CalGrayCS_getOutputLength(inputLength) {
- return inputLength * 3;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return CalGrayCS;
-})();
-
-//
-// LabCS: Based on "PDF Reference, Sixth Ed", p.250
-//
-var LabCS = (function LabCSClosure() {
- function LabCS(whitePoint, blackPoint, range) {
- this.name = 'Lab';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
-
- if (!whitePoint)
- error('WhitePoint missing - required for color space Lab');
- blackPoint = blackPoint || [0, 0, 0];
- range = range || [-100, 100, -100, 100];
-
- // Translate args to spec variables
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
- this.amin = range[0];
- this.amax = range[1];
- this.bmin = range[2];
- this.bmax = range[3];
-
- // These are here just for completeness - the spec doesn't offer any
- // formulas that use BlackPoint in Lab
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- // Validate vars as per spec
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1)
- error('Invalid WhitePoint components, no fallback available');
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint, falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.amin > this.amax || this.bmin > this.bmax) {
- info('Invalid Range, falling back to defaults');
- this.amin = -100;
- this.amax = 100;
- this.bmin = -100;
- this.bmax = 100;
- }
- }
-
- // Function g(x) from spec
- function fn_g(x) {
- if (x >= 6 / 29)
- return x * x * x;
- else
- return (108 / 841) * (x - 4 / 29);
- }
-
- function decode(value, high1, low2, high2) {
- return low2 + (value) * (high2 - low2) / (high1);
- }
-
- // If decoding is needed maxVal should be 2^bits per component - 1.
- function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
- // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
- // not the usual [0, 1]. If a command like setFillColor is used the src
- // values will already be within the correct range. However, if we are
- // converting an image we have to map the values to the correct range given
- // above.
- // Ls,as,bs <---> L*,a*,b* in the spec
- var Ls = src[srcOffset];
- var as = src[srcOffset + 1];
- var bs = src[srcOffset + 2];
- if (maxVal !== false) {
- Ls = decode(Ls, maxVal, 0, 100);
- as = decode(as, maxVal, cs.amin, cs.amax);
- bs = decode(bs, maxVal, cs.bmin, cs.bmax);
- }
-
- // Adjust limits of 'as' and 'bs'
- as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
- bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
-
- // Computes intermediate variables X,Y,Z as per spec
- var M = (Ls + 16) / 116;
- var L = M + (as / 500);
- var N = M - (bs / 200);
-
- var X = cs.XW * fn_g(L);
- var Y = cs.YW * fn_g(M);
- var Z = cs.ZW * fn_g(N);
-
- var r, g, b;
- // Using different conversions for D50 and D65 white points,
- // per http://www.color.org/srgb.pdf
- if (cs.ZW < 1) {
- // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
- r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
- g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
- b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
- } else {
- // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
- r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
- g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
- b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
- }
- // clamp color values to [0,1] range then convert to [0,255] range.
- dest[destOffset] = Math.sqrt(r < 0 ? 0 : r > 1 ? 1 : r) * 255;
- dest[destOffset + 1] = Math.sqrt(g < 0 ? 0 : g > 1 ? 1 : g) * 255;
- dest[destOffset + 2] = Math.sqrt(b < 0 ? 0 : b > 1 ? 1 : b) * 255;
- }
-
- LabCS.prototype = {
- getRgb: function LabCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- convertToRgb(this, src, srcOffset, false, rgb, 0);
- return rgb;
- },
- getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
- convertToRgb(this, src, srcOffset, false, dest, destOffset);
- },
- getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var maxVal = (1 << bits) - 1;
- for (var i = 0; i < count; i++) {
- convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
- srcOffset += 3;
- destOffset += 3;
- }
- },
- getOutputLength: function LabCS_getOutputLength(inputLength) {
- return inputLength;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
- // XXX: Decoding is handled with the lab conversion because of the strange
- // ranges that are used.
- return true;
- },
- usesZeroToOneRange: false
- };
- return LabCS;
-})();
-
-
-
-var PatternType = {
- AXIAL: 2,
- RADIAL: 3
-};
-
-var Pattern = (function PatternClosure() {
- // Constructor should define this.getPattern
- function Pattern() {
- error('should not call Pattern constructor');
- }
-
- Pattern.prototype = {
- // Input: current Canvas context
- // Output: the appropriate fillStyle or strokeStyle
- getPattern: function Pattern_getPattern(ctx) {
- error('Should not call Pattern.getStyle: ' + ctx);
- }
- };
-
- Pattern.shadingFromIR = function Pattern_shadingFromIR(raw) {
- return Shadings[raw[0]].fromIR(raw);
- };
-
- Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
- res) {
-
- var dict = isStream(shading) ? shading.dict : shading;
- var type = dict.get('ShadingType');
-
- switch (type) {
- case PatternType.AXIAL:
- case PatternType.RADIAL:
- // Both radial and axial shadings are handled by RadialAxial shading.
- return new Shadings.RadialAxial(dict, matrix, xref, res);
- default:
- UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
- return new Shadings.Dummy();
- }
- };
- return Pattern;
-})();
-
-var Shadings = {};
-
-// A small number to offset the first/last color stops so we can insert ones to
-// support extend. Number.MIN_VALUE appears to be too small and breaks the
-// extend. 1e-7 works in FF but chrome seems to use an even smaller sized number
-// internally so we have to go bigger.
-Shadings.SMALL_NUMBER = 1e-2;
-
-// Radial and axial shading have very similar implementations
-// If needed, the implementations can be broken into two classes
-Shadings.RadialAxial = (function RadialAxialClosure() {
- function RadialAxial(dict, matrix, xref, res, ctx) {
- this.matrix = matrix;
- this.coordsArr = dict.get('Coords');
- this.shadingType = dict.get('ShadingType');
- this.type = 'Pattern';
- this.ctx = ctx;
- var cs = dict.get('ColorSpace', 'CS');
- cs = ColorSpace.parse(cs, xref, res);
- this.cs = cs;
-
- var t0 = 0.0, t1 = 1.0;
- if (dict.has('Domain')) {
- var domainArr = dict.get('Domain');
- t0 = domainArr[0];
- t1 = domainArr[1];
- }
-
- var extendStart = false, extendEnd = false;
- if (dict.has('Extend')) {
- var extendArr = dict.get('Extend');
- extendStart = extendArr[0];
- extendEnd = extendArr[1];
- }
-
- if (this.shadingType === PatternType.RADIAL &&
- (!extendStart || !extendEnd)) {
- // Radial gradient only currently works if either circle is fully within
- // the other circle.
- var x1 = this.coordsArr[0];
- var y1 = this.coordsArr[1];
- var r1 = this.coordsArr[2];
- var x2 = this.coordsArr[3];
- var y2 = this.coordsArr[4];
- var r2 = this.coordsArr[5];
- var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
- if (r1 <= r2 + distance &&
- r2 <= r1 + distance) {
- warn('Unsupported radial gradient.');
- }
- }
-
- this.extendStart = extendStart;
- this.extendEnd = extendEnd;
-
- var fnObj = dict.get('Function');
- var fn;
- if (isArray(fnObj)) {
- var fnArray = [];
- for (var j = 0, jj = fnObj.length; j < jj; j++) {
- var obj = xref.fetchIfRef(fnObj[j]);
- if (!isPDFFunction(obj)) {
- error('Invalid function');
- }
- fnArray.push(PDFFunction.parse(xref, obj));
- }
- fn = function radialAxialColorFunction(arg) {
- var out = [];
- for (var i = 0, ii = fnArray.length; i < ii; i++) {
- out.push(fnArray[i](arg)[0]);
- }
- return out;
- };
- } else {
- if (!isPDFFunction(fnObj)) {
- error('Invalid function');
- }
- fn = PDFFunction.parse(xref, fnObj);
- }
-
- // 10 samples seems good enough for now, but probably won't work
- // if there are sharp color changes. Ideally, we would implement
- // the spec faithfully and add lossless optimizations.
- var diff = t1 - t0;
- var step = diff / 10;
-
- var colorStops = this.colorStops = [];
-
- // Protect against bad domains so we don't end up in an infinte loop below.
- if (t0 >= t1 || step <= 0) {
- // Acrobat doesn't seem to handle these cases so we'll ignore for
- // now.
- info('Bad shading domain.');
- return;
- }
-
- for (var i = t0; i <= t1; i += step) {
- var rgbColor = cs.getRgb(fn([i]), 0);
- var cssColor = Util.makeCssRgb(rgbColor);
- colorStops.push([(i - t0) / diff, cssColor]);
- }
-
- var background = 'transparent';
- if (dict.has('Background')) {
- var rgbColor = cs.getRgb(dict.get('Background'), 0);
- background = Util.makeCssRgb(rgbColor);
- }
-
- if (!extendStart) {
- // Insert a color stop at the front and offset the first real color stop
- // so it doesn't conflict with the one we insert.
- colorStops.unshift([0, background]);
- colorStops[1][0] += Shadings.SMALL_NUMBER;
- }
- if (!extendEnd) {
- // Same idea as above in extendStart but for the end.
- colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
- colorStops.push([1, background]);
- }
-
- this.colorStops = colorStops;
- }
-
- RadialAxial.fromIR = function RadialAxial_fromIR(raw) {
- var type = raw[1];
- var colorStops = raw[2];
- var p0 = raw[3];
- var p1 = raw[4];
- var r0 = raw[5];
- var r1 = raw[6];
- return {
- type: 'Pattern',
- getPattern: function RadialAxial_getPattern(ctx) {
- var grad;
- if (type == PatternType.AXIAL)
- grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
- else if (type == PatternType.RADIAL)
- grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
-
- for (var i = 0, ii = colorStops.length; i < ii; ++i) {
- var c = colorStops[i];
- grad.addColorStop(c[0], c[1]);
- }
- return grad;
- }
- };
- };
-
- RadialAxial.prototype = {
- getIR: function RadialAxial_getIR() {
- var coordsArr = this.coordsArr;
- var type = this.shadingType;
- if (type == PatternType.AXIAL) {
- var p0 = [coordsArr[0], coordsArr[1]];
- var p1 = [coordsArr[2], coordsArr[3]];
- var r0 = null;
- var r1 = null;
- } else if (type == PatternType.RADIAL) {
- var p0 = [coordsArr[0], coordsArr[1]];
- var p1 = [coordsArr[3], coordsArr[4]];
- var r0 = coordsArr[2];
- var r1 = coordsArr[5];
- } else {
- error('getPattern type unknown: ' + type);
- }
-
- var matrix = this.matrix;
- if (matrix) {
- p0 = Util.applyTransform(p0, matrix);
- p1 = Util.applyTransform(p1, matrix);
- }
-
- return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
- }
- };
-
- return RadialAxial;
-})();
-
-Shadings.Dummy = (function DummyClosure() {
- function Dummy() {
- this.type = 'Pattern';
- }
-
- Dummy.fromIR = function Dummy_fromIR() {
- return {
- type: 'Pattern',
- getPattern: function Dummy_fromIR_getPattern() {
- return 'hotpink';
- }
- };
- };
-
- Dummy.prototype = {
- getIR: function Dummy_getIR() {
- return ['Dummy'];
- }
- };
- return Dummy;
-})();
-
-var TilingPattern = (function TilingPatternClosure() {
- var PaintType = {
- COLORED: 1,
- UNCOLORED: 2
- };
-
- var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
-
- function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
- this.name = IR[1][0].name;
- this.operatorList = IR[2];
- this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
- this.bbox = IR[4];
- this.xstep = IR[5];
- this.ystep = IR[6];
- this.paintType = IR[7];
- this.tilingType = IR[8];
- this.color = color;
- this.objs = objs;
- this.commonObjs = commonObjs;
- this.baseTransform = baseTransform;
- this.type = 'Pattern';
- this.ctx = ctx;
- }
-
- TilingPattern.getIR = function TilingPattern_getIR(operatorList, dict, args) {
- var matrix = dict.get('Matrix');
- var bbox = dict.get('BBox');
- var xstep = dict.get('XStep');
- var ystep = dict.get('YStep');
- var paintType = dict.get('PaintType');
- var tilingType = dict.get('TilingType');
-
- return [
- 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
- paintType, tilingType
- ];
- };
-
- TilingPattern.prototype = {
- createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {
- var operatorList = this.operatorList;
- var bbox = this.bbox;
- var xstep = this.xstep;
- var ystep = this.ystep;
- var paintType = this.paintType;
- var tilingType = this.tilingType;
- var color = this.color;
- var objs = this.objs;
- var commonObjs = this.commonObjs;
- var ctx = this.ctx;
-
- info('TilingType: ' + tilingType);
-
- var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
-
- var topLeft = [x0, y0];
- // we want the canvas to be as large as the step size
- var botRight = [x0 + xstep, y0 + ystep];
-
- var width = botRight[0] - topLeft[0];
- var height = botRight[1] - topLeft[1];
-
- // Obtain scale from matrix and current transformation matrix.
- var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
- var curMatrixScale = Util.singularValueDecompose2dScale(
- this.baseTransform);
- var combinedScale = [matrixScale[0] * curMatrixScale[0],
- matrixScale[1] * curMatrixScale[1]];
-
- // MAX_PATTERN_SIZE is used to avoid OOM situation.
- // Use width and height values that are as close as possible to the end
- // result when the pattern is used. Too low value makes the pattern look
- // blurry. Too large value makes it look too crispy.
- width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),
- MAX_PATTERN_SIZE);
-
- height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
- MAX_PATTERN_SIZE);
-
- var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
- var tmpCtx = tmpCanvas.context;
- var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
- graphics.groupLevel = owner.groupLevel;
-
- this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
-
- this.setScale(width, height, xstep, ystep);
- this.transformToScale(graphics);
-
- // transform coordinates to pattern space
- var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
- graphics.transform.apply(graphics, tmpTranslate);
-
- this.clipBbox(graphics, bbox, x0, y0, x1, y1);
-
- graphics.executeOperatorList(operatorList);
- return tmpCanvas.canvas;
- },
-
- setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
- this.scale = [width / xstep, height / ystep];
- },
-
- transformToScale: function TilingPattern_transformToScale(graphics) {
- var scale = this.scale;
- var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
- graphics.transform.apply(graphics, tmpScale);
- },
-
- scaleToContext: function TilingPattern_scaleToContext() {
- var scale = this.scale;
- this.ctx.scale(1 / scale[0], 1 / scale[1]);
- },
-
- clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
- if (bbox && isArray(bbox) && 4 == bbox.length) {
- var bboxWidth = x1 - x0;
- var bboxHeight = y1 - y0;
- graphics.rectangle(x0, y0, bboxWidth, bboxHeight);
- graphics.clip();
- graphics.endPath();
- }
- },
-
- setFillAndStrokeStyleToContext:
- function setFillAndStrokeStyleToContext(context, paintType, color) {
- switch (paintType) {
- case PaintType.COLORED:
- var ctx = this.ctx;
- context.fillStyle = ctx.fillStyle;
- context.strokeStyle = ctx.strokeStyle;
- break;
- case PaintType.UNCOLORED:
- var rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
- var cssColor = Util.makeCssRgb(rgbColor);
- context.fillStyle = cssColor;
- context.strokeStyle = cssColor;
- break;
- default:
- error('Unsupported paint type: ' + paintType);
- }
- },
-
- getPattern: function TilingPattern_getPattern(ctx, owner) {
- var temporaryPatternCanvas = this.createPatternCanvas(owner);
-
- var ctx = this.ctx;
- ctx.setTransform.apply(ctx, this.baseTransform);
- ctx.transform.apply(ctx, this.matrix);
- this.scaleToContext();
-
- return ctx.createPattern(temporaryPatternCanvas, 'repeat');
- }
- };
-
- return TilingPattern;
-})();
-
-
-
-var PDFFunction = (function PDFFunctionClosure() {
- var CONSTRUCT_SAMPLED = 0;
- var CONSTRUCT_INTERPOLATED = 2;
- var CONSTRUCT_STICHED = 3;
- var CONSTRUCT_POSTSCRIPT = 4;
-
- return {
- getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
- str) {
- var length = 1;
- for (var i = 0, ii = size.length; i < ii; i++)
- length *= size[i];
- length *= outputSize;
-
- var array = [];
- var codeSize = 0;
- var codeBuf = 0;
- // 32 is a valid bps so shifting won't work
- var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
-
- var strBytes = str.getBytes((length * bps + 7) / 8);
- var strIdx = 0;
- for (var i = 0; i < length; i++) {
- while (codeSize < bps) {
- codeBuf <<= 8;
- codeBuf |= strBytes[strIdx++];
- codeSize += 8;
- }
- codeSize -= bps;
- array.push((codeBuf >> codeSize) * sampleMul);
- codeBuf &= (1 << codeSize) - 1;
- }
- return array;
- },
-
- getIR: function PDFFunction_getIR(xref, fn) {
- var dict = fn.dict;
- if (!dict)
- dict = fn;
-
- var types = [this.constructSampled,
- null,
- this.constructInterpolated,
- this.constructStiched,
- this.constructPostScript];
-
- var typeNum = dict.get('FunctionType');
- var typeFn = types[typeNum];
- if (!typeFn)
- error('Unknown type of function');
-
- return typeFn.call(this, fn, dict, xref);
- },
-
- fromIR: function PDFFunction_fromIR(IR) {
- var type = IR[0];
- switch (type) {
- case CONSTRUCT_SAMPLED:
- return this.constructSampledFromIR(IR);
- case CONSTRUCT_INTERPOLATED:
- return this.constructInterpolatedFromIR(IR);
- case CONSTRUCT_STICHED:
- return this.constructStichedFromIR(IR);
- //case CONSTRUCT_POSTSCRIPT:
- default:
- return this.constructPostScriptFromIR(IR);
- }
- },
-
- parse: function PDFFunction_parse(xref, fn) {
- var IR = this.getIR(xref, fn);
- return this.fromIR(IR);
- },
-
- constructSampled: function PDFFunction_constructSampled(str, dict) {
- function toMultiArray(arr) {
- var inputLength = arr.length;
- var outputLength = arr.length / 2;
- var out = [];
- var index = 0;
- for (var i = 0; i < inputLength; i += 2) {
- out[index] = [arr[i], arr[i + 1]];
- ++index;
- }
- return out;
- }
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain || !range)
- error('No domain or range');
-
- var inputSize = domain.length / 2;
- var outputSize = range.length / 2;
-
- domain = toMultiArray(domain);
- range = toMultiArray(range);
-
- var size = dict.get('Size');
- var bps = dict.get('BitsPerSample');
- var order = dict.get('Order') || 1;
- if (order !== 1) {
- // No description how cubic spline interpolation works in PDF32000:2008
- // As in poppler, ignoring order, linear interpolation may work as good
- info('No support for cubic spline interpolation: ' + order);
- }
-
- var encode = dict.get('Encode');
- if (!encode) {
- encode = [];
- for (var i = 0; i < inputSize; ++i) {
- encode.push(0);
- encode.push(size[i] - 1);
- }
- }
- encode = toMultiArray(encode);
-
- var decode = dict.get('Decode');
- if (!decode)
- decode = range;
- else
- decode = toMultiArray(decode);
-
- var samples = this.getSampleArray(size, outputSize, bps, str);
-
- return [
- CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
- outputSize, Math.pow(2, bps) - 1, range
- ];
- },
-
- constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
- // See chapter 3, page 109 of the PDF reference
- function interpolate(x, xmin, xmax, ymin, ymax) {
- return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
- }
-
- return function constructSampledFromIRResult(args) {
- // See chapter 3, page 110 of the PDF reference.
- var m = IR[1];
- var domain = IR[2];
- var encode = IR[3];
- var decode = IR[4];
- var samples = IR[5];
- var size = IR[6];
- var n = IR[7];
- var mask = IR[8];
- var range = IR[9];
-
- if (m != args.length)
- error('Incorrect number of arguments: ' + m + ' != ' +
- args.length);
-
- var x = args;
-
- // Building the cube vertices: its part and sample index
- // http://rjwagner49.com/Mathematics/Interpolation.pdf
- var cubeVertices = 1 << m;
- var cubeN = new Float64Array(cubeVertices);
- var cubeVertex = new Uint32Array(cubeVertices);
- for (var j = 0; j < cubeVertices; j++)
- cubeN[j] = 1;
-
- var k = n, pos = 1;
- // Map x_i to y_j for 0 <= i < m using the sampled function.
- for (var i = 0; i < m; ++i) {
- // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
- var domain_2i = domain[i][0];
- var domain_2i_1 = domain[i][1];
- var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1);
-
- // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
- // Encode_2i, Encode_2i+1)
- var e = interpolate(xi, domain_2i, domain_2i_1,
- encode[i][0], encode[i][1]);
-
- // e_i' = min(max(e_i, 0), Size_i - 1)
- var size_i = size[i];
- e = Math.min(Math.max(e, 0), size_i - 1);
-
- // Adjusting the cube: N and vertex sample index
- var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
- var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
- var n1 = e - e0; // (e - e0) / (e1 - e0);
- var offset0 = e0 * k;
- var offset1 = offset0 + k; // e1 * k
- for (var j = 0; j < cubeVertices; j++) {
- if (j & pos) {
- cubeN[j] *= n1;
- cubeVertex[j] += offset1;
- } else {
- cubeN[j] *= n0;
- cubeVertex[j] += offset0;
- }
- }
-
- k *= size_i;
- pos <<= 1;
- }
-
- var y = new Float64Array(n);
- for (var j = 0; j < n; ++j) {
- // Sum all cube vertices' samples portions
- var rj = 0;
- for (var i = 0; i < cubeVertices; i++)
- rj += samples[cubeVertex[i] + j] * cubeN[i];
-
- // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
- // Decode_2j, Decode_2j+1)
- rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
-
- // y_j = min(max(r_j, range_2j), range_2j+1)
- y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
- }
-
- return y;
- };
- },
-
- constructInterpolated: function PDFFunction_constructInterpolated(str,
- dict) {
- var c0 = dict.get('C0') || [0];
- var c1 = dict.get('C1') || [1];
- var n = dict.get('N');
-
- if (!isArray(c0) || !isArray(c1))
- error('Illegal dictionary for interpolated function');
-
- var length = c0.length;
- var diff = [];
- for (var i = 0; i < length; ++i)
- diff.push(c1[i] - c0[i]);
-
- return [CONSTRUCT_INTERPOLATED, c0, diff, n];
- },
-
- constructInterpolatedFromIR:
- function PDFFunction_constructInterpolatedFromIR(IR) {
- var c0 = IR[1];
- var diff = IR[2];
- var n = IR[3];
-
- var length = diff.length;
-
- return function constructInterpolatedFromIRResult(args) {
- var x = n == 1 ? args[0] : Math.pow(args[0], n);
-
- var out = [];
- for (var j = 0; j < length; ++j)
- out.push(c0[j] + (x * diff[j]));
-
- return out;
-
- };
- },
-
- constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
- var domain = dict.get('Domain');
-
- if (!domain)
- error('No domain');
-
- var inputSize = domain.length / 2;
- if (inputSize != 1)
- error('Bad domain for stiched function');
-
- var fnRefs = dict.get('Functions');
- var fns = [];
- for (var i = 0, ii = fnRefs.length; i < ii; ++i)
- fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
-
- var bounds = dict.get('Bounds');
- var encode = dict.get('Encode');
-
- return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
- },
-
- constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
- var domain = IR[1];
- var bounds = IR[2];
- var encode = IR[3];
- var fnsIR = IR[4];
- var fns = [];
-
- for (var i = 0, ii = fnsIR.length; i < ii; i++) {
- fns.push(PDFFunction.fromIR(fnsIR[i]));
- }
-
- return function constructStichedFromIRResult(args) {
- var clip = function constructStichedFromIRClip(v, min, max) {
- if (v > max)
- v = max;
- else if (v < min)
- v = min;
- return v;
- };
-
- // clip to domain
- var v = clip(args[0], domain[0], domain[1]);
- // calulate which bound the value is in
- for (var i = 0, ii = bounds.length; i < ii; ++i) {
- if (v < bounds[i])
- break;
- }
-
- // encode value into domain of function
- var dmin = domain[0];
- if (i > 0)
- dmin = bounds[i - 1];
- var dmax = domain[1];
- if (i < bounds.length)
- dmax = bounds[i];
-
- var rmin = encode[2 * i];
- var rmax = encode[2 * i + 1];
-
- var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
-
- // call the appropropriate function
- return fns[i]([v2]);
- };
- },
-
- constructPostScript: function PDFFunction_constructPostScript(fn, dict,
- xref) {
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain)
- error('No domain.');
-
- if (!range)
- error('No range.');
-
- var lexer = new PostScriptLexer(fn);
- var parser = new PostScriptParser(lexer);
- var code = parser.parse();
-
- return [CONSTRUCT_POSTSCRIPT, domain, range, code];
- },
-
- constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
- IR) {
- var domain = IR[1];
- var range = IR[2];
- var code = IR[3];
- var numOutputs = range.length / 2;
- var evaluator = new PostScriptEvaluator(code);
- // Cache the values for a big speed up, the cache size is limited though
- // since the number of possible values can be huge from a PS function.
- var cache = new FunctionCache();
- return function constructPostScriptFromIRResult(args) {
- var initialStack = [];
- for (var i = 0, ii = (domain.length / 2); i < ii; ++i) {
- initialStack.push(args[i]);
- }
-
- var key = initialStack.join('_');
- if (cache.has(key))
- return cache.get(key);
-
- var stack = evaluator.execute(initialStack);
- var transformed = [];
- for (i = numOutputs - 1; i >= 0; --i) {
- var out = stack.pop();
- var rangeIndex = 2 * i;
- if (out < range[rangeIndex])
- out = range[rangeIndex];
- else if (out > range[rangeIndex + 1])
- out = range[rangeIndex + 1];
- transformed[i] = out;
- }
- cache.set(key, transformed);
- return transformed;
- };
- }
- };
-})();
-
-var FunctionCache = (function FunctionCacheClosure() {
- // Of 10 PDF's with type4 functions the maxium number of distinct values seen
- // was 256. This still may need some tweaking in the future though.
- var MAX_CACHE_SIZE = 1024;
- function FunctionCache() {
- this.cache = {};
- this.total = 0;
- }
- FunctionCache.prototype = {
- has: function FunctionCache_has(key) {
- return key in this.cache;
- },
- get: function FunctionCache_get(key) {
- return this.cache[key];
- },
- set: function FunctionCache_set(key, value) {
- if (this.total < MAX_CACHE_SIZE) {
- this.cache[key] = value;
- this.total++;
- }
- }
- };
- return FunctionCache;
-})();
-
-var PostScriptStack = (function PostScriptStackClosure() {
- var MAX_STACK_SIZE = 100;
- function PostScriptStack(initialStack) {
- this.stack = initialStack || [];
- }
-
- PostScriptStack.prototype = {
- push: function PostScriptStack_push(value) {
- if (this.stack.length >= MAX_STACK_SIZE)
- error('PostScript function stack overflow.');
- this.stack.push(value);
- },
- pop: function PostScriptStack_pop() {
- if (this.stack.length <= 0)
- error('PostScript function stack underflow.');
- return this.stack.pop();
- },
- copy: function PostScriptStack_copy(n) {
- if (this.stack.length + n >= MAX_STACK_SIZE)
- error('PostScript function stack overflow.');
- var stack = this.stack;
- for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++)
- stack.push(stack[i]);
- },
- index: function PostScriptStack_index(n) {
- this.push(this.stack[this.stack.length - n - 1]);
- },
- // rotate the last n stack elements p times
- roll: function PostScriptStack_roll(n, p) {
- var stack = this.stack;
- var l = stack.length - n;
- var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
- for (i = l, j = r; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- for (i = l, j = c - 1; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- for (i = c, j = r; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- }
- };
- return PostScriptStack;
-})();
-var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
- function PostScriptEvaluator(operators, operands) {
- this.operators = operators;
- this.operands = operands;
- }
- PostScriptEvaluator.prototype = {
- execute: function PostScriptEvaluator_execute(initialStack) {
- var stack = new PostScriptStack(initialStack);
- var counter = 0;
- var operators = this.operators;
- var length = operators.length;
- var operator, a, b;
- while (counter < length) {
- operator = operators[counter++];
- if (typeof operator == 'number') {
- // Operator is really an operand and should be pushed to the stack.
- stack.push(operator);
- continue;
- }
- switch (operator) {
- // non standard ps operators
- case 'jz': // jump if false
- b = stack.pop();
- a = stack.pop();
- if (!a)
- counter = b;
- break;
- case 'j': // jump
- a = stack.pop();
- counter = a;
- break;
-
- // all ps operators in alphabetical order (excluding if/ifelse)
- case 'abs':
- a = stack.pop();
- stack.push(Math.abs(a));
- break;
- case 'add':
- b = stack.pop();
- a = stack.pop();
- stack.push(a + b);
- break;
- case 'and':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a && b);
- else
- stack.push(a & b);
- break;
- case 'atan':
- a = stack.pop();
- stack.push(Math.atan(a));
- break;
- case 'bitshift':
- b = stack.pop();
- a = stack.pop();
- if (a > 0)
- stack.push(a << b);
- else
- stack.push(a >> b);
- break;
- case 'ceiling':
- a = stack.pop();
- stack.push(Math.ceil(a));
- break;
- case 'copy':
- a = stack.pop();
- stack.copy(a);
- break;
- case 'cos':
- a = stack.pop();
- stack.push(Math.cos(a));
- break;
- case 'cvi':
- a = stack.pop() | 0;
- stack.push(a);
- break;
- case 'cvr':
- // noop
- break;
- case 'div':
- b = stack.pop();
- a = stack.pop();
- stack.push(a / b);
- break;
- case 'dup':
- stack.copy(1);
- break;
- case 'eq':
- b = stack.pop();
- a = stack.pop();
- stack.push(a == b);
- break;
- case 'exch':
- stack.roll(2, 1);
- break;
- case 'exp':
- b = stack.pop();
- a = stack.pop();
- stack.push(Math.pow(a, b));
- break;
- case 'false':
- stack.push(false);
- break;
- case 'floor':
- a = stack.pop();
- stack.push(Math.floor(a));
- break;
- case 'ge':
- b = stack.pop();
- a = stack.pop();
- stack.push(a >= b);
- break;
- case 'gt':
- b = stack.pop();
- a = stack.pop();
- stack.push(a > b);
- break;
- case 'idiv':
- b = stack.pop();
- a = stack.pop();
- stack.push((a / b) | 0);
- break;
- case 'index':
- a = stack.pop();
- stack.index(a);
- break;
- case 'le':
- b = stack.pop();
- a = stack.pop();
- stack.push(a <= b);
- break;
- case 'ln':
- a = stack.pop();
- stack.push(Math.log(a));
- break;
- case 'log':
- a = stack.pop();
- stack.push(Math.log(a) / Math.LN10);
- break;
- case 'lt':
- b = stack.pop();
- a = stack.pop();
- stack.push(a < b);
- break;
- case 'mod':
- b = stack.pop();
- a = stack.pop();
- stack.push(a % b);
- break;
- case 'mul':
- b = stack.pop();
- a = stack.pop();
- stack.push(a * b);
- break;
- case 'ne':
- b = stack.pop();
- a = stack.pop();
- stack.push(a != b);
- break;
- case 'neg':
- a = stack.pop();
- stack.push(-b);
- break;
- case 'not':
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a && b);
- else
- stack.push(a & b);
- break;
- case 'or':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a || b);
- else
- stack.push(a | b);
- break;
- case 'pop':
- stack.pop();
- break;
- case 'roll':
- b = stack.pop();
- a = stack.pop();
- stack.roll(a, b);
- break;
- case 'round':
- a = stack.pop();
- stack.push(Math.round(a));
- break;
- case 'sin':
- a = stack.pop();
- stack.push(Math.sin(a));
- break;
- case 'sqrt':
- a = stack.pop();
- stack.push(Math.sqrt(a));
- break;
- case 'sub':
- b = stack.pop();
- a = stack.pop();
- stack.push(a - b);
- break;
- case 'true':
- stack.push(true);
- break;
- case 'truncate':
- a = stack.pop();
- a = a < 0 ? Math.ceil(a) : Math.floor(a);
- stack.push(a);
- break;
- case 'xor':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a != b);
- else
- stack.push(a ^ b);
- break;
- default:
- error('Unknown operator ' + operator);
- break;
- }
- }
- return stack.stack;
- }
- };
- return PostScriptEvaluator;
-})();
-
-var PostScriptParser = (function PostScriptParserClosure() {
- function PostScriptParser(lexer) {
- this.lexer = lexer;
- this.operators = [];
- this.token = null;
- this.prev = null;
- }
- PostScriptParser.prototype = {
- nextToken: function PostScriptParser_nextToken() {
- this.prev = this.token;
- this.token = this.lexer.getToken();
- },
- accept: function PostScriptParser_accept(type) {
- if (this.token.type == type) {
- this.nextToken();
- return true;
- }
- return false;
- },
- expect: function PostScriptParser_expect(type) {
- if (this.accept(type))
- return true;
- error('Unexpected symbol: found ' + this.token.type + ' expected ' +
- type + '.');
- },
- parse: function PostScriptParser_parse() {
- this.nextToken();
- this.expect(PostScriptTokenTypes.LBRACE);
- this.parseBlock();
- this.expect(PostScriptTokenTypes.RBRACE);
- return this.operators;
- },
- parseBlock: function PostScriptParser_parseBlock() {
- while (true) {
- if (this.accept(PostScriptTokenTypes.NUMBER)) {
- this.operators.push(this.prev.value);
- } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
- this.operators.push(this.prev.value);
- } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
- this.parseCondition();
- } else {
- return;
- }
- }
- },
- parseCondition: function PostScriptParser_parseCondition() {
- // Add two place holders that will be updated later
- var conditionLocation = this.operators.length;
- this.operators.push(null, null);
-
- this.parseBlock();
- this.expect(PostScriptTokenTypes.RBRACE);
- if (this.accept(PostScriptTokenTypes.IF)) {
- // The true block is right after the 'if' so it just falls through on
- // true else it jumps and skips the true block.
- this.operators[conditionLocation] = this.operators.length;
- this.operators[conditionLocation + 1] = 'jz';
- } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
- var jumpLocation = this.operators.length;
- this.operators.push(null, null);
- var endOfTrue = this.operators.length;
- this.parseBlock();
- this.expect(PostScriptTokenTypes.RBRACE);
- this.expect(PostScriptTokenTypes.IFELSE);
- // The jump is added at the end of the true block to skip the false
- // block.
- this.operators[jumpLocation] = this.operators.length;
- this.operators[jumpLocation + 1] = 'j';
-
- this.operators[conditionLocation] = endOfTrue;
- this.operators[conditionLocation + 1] = 'jz';
- } else {
- error('PS Function: error parsing conditional.');
- }
- }
- };
- return PostScriptParser;
-})();
-
-var PostScriptTokenTypes = {
- LBRACE: 0,
- RBRACE: 1,
- NUMBER: 2,
- OPERATOR: 3,
- IF: 4,
- IFELSE: 5
-};
-
-var PostScriptToken = (function PostScriptTokenClosure() {
- function PostScriptToken(type, value) {
- this.type = type;
- this.value = value;
- }
-
- var opCache = {};
-
- PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
- var opValue = opCache[op];
- if (opValue)
- return opValue;
-
- return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
- };
-
- PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
- '{');
- PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
- '}');
- PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
- PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
- 'IFELSE');
- return PostScriptToken;
-})();
-
-var PostScriptLexer = (function PostScriptLexerClosure() {
- function PostScriptLexer(stream) {
- this.stream = stream;
- this.nextChar();
- }
- PostScriptLexer.prototype = {
- nextChar: function PostScriptLexer_nextChar() {
- return (this.currentChar = this.stream.getByte());
- },
- getToken: function PostScriptLexer_getToken() {
- var s = '';
- var comment = false;
- var ch = this.currentChar;
-
- // skip comments
- while (true) {
- if (ch < 0) {
- return EOF;
- }
-
- if (comment) {
- if (ch === 0x0A || ch === 0x0D) {
- comment = false;
- }
- } else if (ch == 0x25) { // '%'
- comment = true;
- } else if (!Lexer.isSpace(ch)) {
- break;
- }
- ch = this.nextChar();
- }
- switch (ch | 0) {
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
- case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
- case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
- return new PostScriptToken(PostScriptTokenTypes.NUMBER,
- this.getNumber());
- case 0x7B: // '{'
- this.nextChar();
- return PostScriptToken.LBRACE;
- case 0x7D: // '}'
- this.nextChar();
- return PostScriptToken.RBRACE;
- }
- // operator
- var str = String.fromCharCode(ch);
- while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
- ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
- str += String.fromCharCode(ch);
- }
- switch (str.toLowerCase()) {
- case 'if':
- return PostScriptToken.IF;
- case 'ifelse':
- return PostScriptToken.IFELSE;
- default:
- return PostScriptToken.getOperator(str);
- }
- },
- getNumber: function PostScriptLexer_getNumber() {
- var ch = this.currentChar;
- var str = String.fromCharCode(ch);
- while ((ch = this.nextChar()) >= 0) {
- if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
- ch === 0x2D || ch === 0x2E) { // '-', '.'
- str += String.fromCharCode(ch);
- } else {
- break;
- }
- }
- var value = parseFloat(str);
- if (isNaN(value))
- error('Invalid floating point number: ' + value);
- return value;
- }
- };
- return PostScriptLexer;
-})();
-
-
-
-var Annotation = (function AnnotationClosure() {
- // 12.5.5: Algorithm: Appearance streams
- function getTransformMatrix(rect, bbox, matrix) {
- var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
- var minX = bounds[0];
- var minY = bounds[1];
- var maxX = bounds[2];
- var maxY = bounds[3];
-
- if (minX === maxX || minY === maxY) {
- // From real-life file, bbox was [0, 0, 0, 0]. In this case,
- // just apply the transform for rect
- return [1, 0, 0, 1, rect[0], rect[1]];
- }
-
- var xRatio = (rect[2] - rect[0]) / (maxX - minX);
- var yRatio = (rect[3] - rect[1]) / (maxY - minY);
- return [
- xRatio,
- 0,
- 0,
- yRatio,
- rect[0] - minX * xRatio,
- rect[1] - minY * yRatio
- ];
- }
-
- function getDefaultAppearance(dict) {
- var appearanceState = dict.get('AP');
- if (!isDict(appearanceState)) {
- return;
- }
-
- var appearance;
- var appearances = appearanceState.get('N');
- if (isDict(appearances)) {
- var as = dict.get('AS');
- if (as && appearances.has(as.name)) {
- appearance = appearances.get(as.name);
- }
- } else {
- appearance = appearances;
- }
- return appearance;
- }
-
- function Annotation(params) {
- if (params.data) {
- this.data = params.data;
- return;
- }
-
- var dict = params.dict;
- var data = this.data = {};
-
- data.subtype = dict.get('Subtype').name;
- var rect = dict.get('Rect');
- data.rect = Util.normalizeRect(rect);
- data.annotationFlags = dict.get('F');
-
- var color = dict.get('C');
- if (isArray(color) && color.length === 3) {
- // TODO(mack): currently only supporting rgb; need support different
- // colorspaces
- data.color = color;
- } else {
- data.color = [0, 0, 0];
- }
-
- // Some types of annotations have border style dict which has more
- // info than the border array
- if (dict.has('BS')) {
- var borderStyle = dict.get('BS');
- data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
- } else {
- var borderArray = dict.get('Border') || [0, 0, 1];
- data.borderWidth = borderArray[2] || 0;
- }
-
- this.appearance = getDefaultAppearance(dict);
- data.hasAppearance = !!this.appearance;
- }
-
- Annotation.prototype = {
-
- getData: function Annotation_getData() {
- return this.data;
- },
-
- hasHtml: function Annotation_hasHtml() {
- return false;
- },
-
- getHtmlElement: function Annotation_getHtmlElement(commonObjs) {
- throw new NotImplementedException(
- 'getHtmlElement() should be implemented in subclass');
- },
-
- // TODO(mack): Remove this, it's not really that helpful.
- getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) {
- assert(!isWorker,
- 'getEmptyContainer() should be called from main thread');
-
- rect = rect || this.data.rect;
- var element = document.createElement(tagName);
- element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
- element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
- return element;
- },
-
- isViewable: function Annotation_isViewable() {
- var data = this.data;
- return !!(
- data &&
- (!data.annotationFlags ||
- !(data.annotationFlags & 0x22)) && // Hidden or NoView
- data.rect // rectangle is nessessary
- );
- },
-
- loadResources: function(keys) {
- var promise = new LegacyPromise();
- this.appearance.dict.getAsync('Resources').then(function(resources) {
- if (!resources) {
- promise.resolve();
- return;
- }
- var objectLoader = new ObjectLoader(resources.map,
- keys,
- resources.xref);
- objectLoader.load().then(function() {
- promise.resolve(resources);
- });
- }.bind(this));
-
- return promise;
- },
-
- getOperatorList: function Annotation_getToOperatorList(evaluator) {
-
- var promise = new LegacyPromise();
-
- if (!this.appearance) {
- promise.resolve(new OperatorList());
- return promise;
- }
-
- var data = this.data;
-
- var appearanceDict = this.appearance.dict;
- var resourcesPromise = this.loadResources([
- 'ExtGState',
- 'ColorSpace',
- 'Pattern',
- 'Shading',
- 'XObject',
- 'Font'
- // ProcSet
- // Properties
- ]);
- var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
- var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
- var transform = getTransformMatrix(data.rect, bbox, matrix);
-
- var border = data.border;
-
- resourcesPromise.then(function(resources) {
- var opList = new OperatorList();
- opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
- evaluator.getOperatorList(this.appearance, resources, opList);
- opList.addOp(OPS.endAnnotation, []);
- promise.resolve(opList);
- }.bind(this));
-
- return promise;
- }
- };
-
- Annotation.getConstructor =
- function Annotation_getConstructor(subtype, fieldType) {
-
- if (!subtype) {
- return;
- }
-
- // TODO(mack): Implement FreeText annotations
- if (subtype === 'Link') {
- return LinkAnnotation;
- } else if (subtype === 'Text') {
- return TextAnnotation;
- } else if (subtype === 'Widget') {
- if (!fieldType) {
- return;
- }
-
- if (fieldType === 'Tx') {
- return TextWidgetAnnotation;
- } else {
- return WidgetAnnotation;
- }
- } else {
- return Annotation;
- }
- };
-
- // TODO(mack): Support loading annotation from data
- Annotation.fromData = function Annotation_fromData(data) {
- var subtype = data.subtype;
- var fieldType = data.fieldType;
- var Constructor = Annotation.getConstructor(subtype, fieldType);
- if (Constructor) {
- return new Constructor({ data: data });
- }
- };
-
- Annotation.fromRef = function Annotation_fromRef(xref, ref) {
-
- var dict = xref.fetchIfRef(ref);
- if (!isDict(dict)) {
- return;
- }
-
- var subtype = dict.get('Subtype');
- subtype = isName(subtype) ? subtype.name : '';
- if (!subtype) {
- return;
- }
-
- var fieldType = Util.getInheritableProperty(dict, 'FT');
- fieldType = isName(fieldType) ? fieldType.name : '';
-
- var Constructor = Annotation.getConstructor(subtype, fieldType);
- if (!Constructor) {
- return;
- }
-
- var params = {
- dict: dict,
- ref: ref,
- };
-
- var annotation = new Constructor(params);
-
- if (annotation.isViewable()) {
- return annotation;
- } else {
- warn('unimplemented annotation type: ' + subtype);
- }
- };
-
- Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
- annotations, opList, pdfManager, partialEvaluator) {
-
- function reject(e) {
- annotationsReadyPromise.reject(e);
- }
-
- var annotationsReadyPromise = new LegacyPromise();
-
- var annotationPromises = [];
- for (var i = 0, n = annotations.length; i < n; ++i) {
- annotationPromises.push(annotations[i].getOperatorList(partialEvaluator));
- }
- Promise.all(annotationPromises).then(function(datas) {
- opList.addOp(OPS.beginAnnotations, []);
- for (var i = 0, n = datas.length; i < n; ++i) {
- var annotOpList = datas[i];
- opList.addOpList(annotOpList);
- }
- opList.addOp(OPS.endAnnotations, []);
- annotationsReadyPromise.resolve();
- }, reject);
-
- return annotationsReadyPromise;
- };
-
- return Annotation;
-})();
-PDFJS.Annotation = Annotation;
-
-
-var WidgetAnnotation = (function WidgetAnnotationClosure() {
-
- function WidgetAnnotation(params) {
- Annotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- var dict = params.dict;
- var data = this.data;
-
- data.fieldValue = stringToPDFString(
- Util.getInheritableProperty(dict, 'V') || '');
- data.alternativeText = stringToPDFString(dict.get('TU') || '');
- data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
- var fieldType = Util.getInheritableProperty(dict, 'FT');
- data.fieldType = isName(fieldType) ? fieldType.name : '';
- data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
- this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
-
- // Building the full field name by collecting the field and
- // its ancestors 'T' data and joining them using '.'.
- var fieldName = [];
- var namedItem = dict;
- var ref = params.ref;
- while (namedItem) {
- var parent = namedItem.get('Parent');
- var parentRef = namedItem.getRaw('Parent');
- var name = namedItem.get('T');
- if (name) {
- fieldName.unshift(stringToPDFString(name));
- } else {
- // The field name is absent, that means more than one field
- // with the same name may exist. Replacing the empty name
- // with the '`' plus index in the parent's 'Kids' array.
- // This is not in the PDF spec but necessary to id the
- // the input controls.
- var kids = parent.get('Kids');
- var j, jj;
- for (j = 0, jj = kids.length; j < jj; j++) {
- var kidRef = kids[j];
- if (kidRef.num == ref.num && kidRef.gen == ref.gen)
- break;
- }
- fieldName.unshift('`' + j);
- }
- namedItem = parent;
- ref = parentRef;
- }
- data.fullName = fieldName.join('.');
- }
-
- var parent = Annotation.prototype;
- Util.inherit(WidgetAnnotation, Annotation, {
- isViewable: function WidgetAnnotation_isViewable() {
- if (this.data.fieldType === 'Sig') {
- warn('unimplemented annotation type: Widget signature');
- return false;
- }
-
- return parent.isViewable.call(this);
- }
- });
-
- return WidgetAnnotation;
-})();
-
-var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
- function TextWidgetAnnotation(params) {
- WidgetAnnotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
- }
-
- // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
- function setTextStyles(element, item, fontObj) {
-
- var style = element.style;
- style.fontSize = item.fontSize + 'px';
- style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
-
- if (!fontObj) {
- return;
- }
-
- style.fontWeight = fontObj.black ?
- (fontObj.bold ? 'bolder' : 'bold') :
- (fontObj.bold ? 'bold' : 'normal');
- style.fontStyle = fontObj.italic ? 'italic' : 'normal';
-
- var fontName = fontObj.loadedName;
- var fontFamily = fontName ? '"' + fontName + '", ' : '';
- // Use a reasonable default font if the font doesn't specify a fallback
- var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
- style.fontFamily = fontFamily + fallbackName;
- }
-
-
- var parent = WidgetAnnotation.prototype;
- Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
- hasHtml: function TextWidgetAnnotation_hasHtml() {
- return !this.data.hasAppearance && !!this.data.fieldValue;
- },
-
- getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
- assert(!isWorker, 'getHtmlElement() shall be called from main thread');
-
- var item = this.data;
-
- var element = this.getEmptyContainer('div');
- element.style.display = 'table';
-
- var content = document.createElement('div');
- content.textContent = item.fieldValue;
- var textAlignment = item.textAlignment;
- content.style.textAlign = ['left', 'center', 'right'][textAlignment];
- content.style.verticalAlign = 'middle';
- content.style.display = 'table-cell';
-
- var fontObj = item.fontRefName ?
- commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
-
- element.appendChild(content);
-
- return element;
- },
-
- getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
- if (this.appearance) {
- return Annotation.prototype.getOperatorList.call(this, evaluator);
- }
-
- var promise = new LegacyPromise();
- var opList = new OperatorList();
- var data = this.data;
-
- // Even if there is an appearance stream, ignore it. This is the
- // behaviour used by Adobe Reader.
-
- var defaultAppearance = data.defaultAppearance;
- if (!defaultAppearance) {
- promise.resolve(opList);
- return promise;
- }
-
- // Include any font resources found in the default appearance
-
- var stream = new Stream(stringToBytes(defaultAppearance));
- evaluator.getOperatorList(stream, this.fieldResources, opList);
- var appearanceFnArray = opList.fnArray;
- var appearanceArgsArray = opList.argsArray;
- var fnArray = [];
- var argsArray = [];
-
- // TODO(mack): Add support for stroke color
- data.rgb = [0, 0, 0];
- // TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
- for (var i = 0, n = fnArray.length; i < n; ++i) {
- var fnId = appearanceFnArray[i];
- var args = appearanceArgsArray[i];
-
- if (fnId === OPS.setFont) {
- data.fontRefName = args[0];
- var size = args[1];
- if (size < 0) {
- data.fontDirection = -1;
- data.fontSize = -size;
- } else {
- data.fontDirection = 1;
- data.fontSize = size;
- }
- } else if (fnId === OPS.setFillRGBColor) {
- data.rgb = args;
- } else if (fnId === OPS.setFillGray) {
- var rgbValue = args[0] * 255;
- data.rgb = [rgbValue, rgbValue, rgbValue];
- }
- }
- promise.resolve(opList);
- return promise;
- }
- });
-
- return TextWidgetAnnotation;
-})();
-
-var TextAnnotation = (function TextAnnotationClosure() {
- function TextAnnotation(params) {
- Annotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- var dict = params.dict;
- var data = this.data;
-
- var content = dict.get('Contents');
- var title = dict.get('T');
- data.content = stringToPDFString(content || '');
- data.title = stringToPDFString(title || '');
- data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name;
- }
-
- var ANNOT_MIN_SIZE = 10;
-
- Util.inherit(TextAnnotation, Annotation, {
-
- getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
- var promise = new LegacyPromise();
- promise.resolve(new OperatorList());
- return promise;
- },
-
- hasHtml: function TextAnnotation_hasHtml() {
- return true;
- },
-
- getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
- assert(!isWorker, 'getHtmlElement() shall be called from main thread');
-
- var item = this.data;
- var rect = item.rect;
-
- // sanity check because of OOo-generated PDFs
- if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
- rect[3] = rect[1] + ANNOT_MIN_SIZE;
- }
- if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
- rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
- }
-
- var container = this.getEmptyContainer('section', rect);
- container.className = 'annotText';
-
- var image = document.createElement('img');
- image.style.height = container.style.height;
- var iconName = item.name;
- image.src = PDFJS.imageResourcesPath + 'annotation-' +
- iconName.toLowerCase() + '.svg';
- image.alt = '[{{type}} Annotation]';
- image.dataset.l10nId = 'text_annotation_type';
- image.dataset.l10nArgs = JSON.stringify({type: iconName});
- var content = document.createElement('div');
- content.setAttribute('hidden', true);
- var title = document.createElement('h1');
- var text = document.createElement('p');
- content.style.left = Math.floor(rect[2] - rect[0]) + 'px';
- content.style.top = '0px';
- title.textContent = item.title;
-
- if (!item.content && !item.title) {
- content.setAttribute('hidden', true);
- } else {
- var e = document.createElement('span');
- var lines = item.content.split(/(?:\r\n?|\n)/);
- for (var i = 0, ii = lines.length; i < ii; ++i) {
- var line = lines[i];
- e.appendChild(document.createTextNode(line));
- if (i < (ii - 1))
- e.appendChild(document.createElement('br'));
- }
- text.appendChild(e);
-
- var showAnnotation = function showAnnotation() {
- container.style.zIndex += 1;
- content.removeAttribute('hidden');
- };
-
- var hideAnnotation = function hideAnnotation(e) {
- if (e.toElement || e.relatedTarget) { // No context menu is used
- container.style.zIndex -= 1;
- content.setAttribute('hidden', true);
- }
- };
-
- content.addEventListener('mouseover', showAnnotation, false);
- content.addEventListener('mouseout', hideAnnotation, false);
- image.addEventListener('mouseover', showAnnotation, false);
- image.addEventListener('mouseout', hideAnnotation, false);
- }
-
- content.appendChild(title);
- content.appendChild(text);
- container.appendChild(image);
- container.appendChild(content);
-
- return container;
- }
- });
-
- return TextAnnotation;
-})();
-
-var LinkAnnotation = (function LinkAnnotationClosure() {
- function LinkAnnotation(params) {
- Annotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- var dict = params.dict;
- var data = this.data;
-
- var action = dict.get('A');
- if (action) {
- var linkType = action.get('S').name;
- if (linkType === 'URI') {
- var url = addDefaultProtocolToUrl(action.get('URI'));
- // TODO: pdf spec mentions urls can be relative to a Base
- // entry in the dictionary.
- if (!isValidUrl(url, false)) {
- url = '';
- }
- data.url = url;
- } else if (linkType === 'GoTo') {
- data.dest = action.get('D');
- } else if (linkType === 'GoToR') {
- var urlDict = action.get('F');
- if (isDict(urlDict)) {
- // We assume that the 'url' is a Filspec dictionary
- // and fetch the url without checking any further
- url = urlDict.get('F') || '';
- }
-
- // TODO: pdf reference says that GoToR
- // can also have 'NewWindow' attribute
- if (!isValidUrl(url, false)) {
- url = '';
- }
- data.url = url;
- data.dest = action.get('D');
- } else if (linkType === 'Named') {
- data.action = action.get('N').name;
- } else {
- warn('unrecognized link type: ' + linkType);
- }
- } else if (dict.has('Dest')) {
- // simple destination link
- var dest = dict.get('Dest');
- data.dest = isName(dest) ? dest.name : dest;
- }
- }
-
- // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
- function addDefaultProtocolToUrl(url) {
- if (url.indexOf('www.') === 0) {
- return ('http://' + url);
- }
- return url;
- }
-
- Util.inherit(LinkAnnotation, Annotation, {
- hasOperatorList: function LinkAnnotation_hasOperatorList() {
- return false;
- },
-
- hasHtml: function LinkAnnotation_hasHtml() {
- return true;
- },
-
- getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
- var rect = this.data.rect;
- var element = document.createElement('a');
- var borderWidth = this.data.borderWidth;
-
- element.style.borderWidth = borderWidth + 'px';
- var color = this.data.color;
- var rgb = [];
- for (var i = 0; i < 3; ++i) {
- rgb[i] = Math.round(color[i] * 255);
- }
- element.style.borderColor = Util.makeCssRgb(rgb);
- element.style.borderStyle = 'solid';
-
- var width = rect[2] - rect[0] - 2 * borderWidth;
- var height = rect[3] - rect[1] - 2 * borderWidth;
- element.style.width = width + 'px';
- element.style.height = height + 'px';
-
- element.href = this.data.url || '';
- return element;
- }
- });
-
- return LinkAnnotation;
-})();
-
-
var NetworkManager = (function NetworkManagerClosure() {
@@ -4168,7 +1620,9 @@ var NetworkManager = (function NetworkManagerClosure() {
function NetworkManager(url, args) {
this.url = url;
args = args || {};
- this.httpHeaders = args.httpHeaders || {};
+ this.isHttp = /^https?:/i.test(url);
+ this.httpHeaders = (this.isHttp && args.httpHeaders) || {};
+ this.withCredentials = args.withCredentials || false;
this.getXhr = args.getXhr ||
function NetworkManager_getXhr() {
return new XMLHttpRequest();
@@ -4180,17 +1634,16 @@ var NetworkManager = (function NetworkManagerClosure() {
}
function getArrayBuffer(xhr) {
- var data = (xhr.mozResponseArrayBuffer || xhr.mozResponse ||
- xhr.responseArrayBuffer || xhr.response);
+ var data = xhr.response;
if (typeof data !== 'string') {
return data;
}
var length = data.length;
- var buffer = new Uint8Array(length);
+ var array = new Uint8Array(length);
for (var i = 0; i < length; i++) {
- buffer[i] = data.charCodeAt(i) & 0xFF;
+ array[i] = data.charCodeAt(i) & 0xFF;
}
- return buffer;
+ return array.buffer;
}
NetworkManager.prototype = {
@@ -4205,11 +1658,11 @@ var NetworkManager = (function NetworkManagerClosure() {
return this.request(args);
},
- requestFull: function NetworkManager_requestRange(listeners) {
+ requestFull: function NetworkManager_requestFull(listeners) {
return this.request(listeners);
},
- request: function NetworkManager_requestRange(args) {
+ request: function NetworkManager_request(args) {
var xhr = this.getXhr();
var xhrId = this.currXhrId++;
var pendingRequest = this.pendingRequests[xhrId] = {
@@ -4217,6 +1670,7 @@ var NetworkManager = (function NetworkManagerClosure() {
};
xhr.open('GET', this.url);
+ xhr.withCredentials = this.withCredentials;
for (var property in this.httpHeaders) {
var value = this.httpHeaders[property];
if (typeof value === 'undefined') {
@@ -4224,7 +1678,7 @@ var NetworkManager = (function NetworkManagerClosure() {
}
xhr.setRequestHeader(property, value);
}
- if ('begin' in args && 'end' in args) {
+ if (this.isHttp && 'begin' in args && 'end' in args) {
var rangeStr = args.begin + '-' + (args.end - 1);
xhr.setRequestHeader('Range', 'bytes=' + rangeStr);
pendingRequest.expectedStatus = 206;
@@ -4232,27 +1686,54 @@ var NetworkManager = (function NetworkManagerClosure() {
pendingRequest.expectedStatus = 200;
}
- xhr.mozResponseType = xhr.responseType = 'arraybuffer';
-
- if (args.onProgress) {
- xhr.onprogress = args.onProgress;
+ if (args.onProgressiveData) {
+ xhr.responseType = 'moz-chunked-arraybuffer';
+ if (xhr.responseType === 'moz-chunked-arraybuffer') {
+ pendingRequest.onProgressiveData = args.onProgressiveData;
+ pendingRequest.mozChunked = true;
+ } else {
+ xhr.responseType = 'arraybuffer';
+ }
+ } else {
+ xhr.responseType = 'arraybuffer';
}
+
if (args.onError) {
xhr.onerror = function(evt) {
args.onError(xhr.status);
};
}
xhr.onreadystatechange = this.onStateChange.bind(this, xhrId);
+ xhr.onprogress = this.onProgress.bind(this, xhrId);
pendingRequest.onHeadersReceived = args.onHeadersReceived;
pendingRequest.onDone = args.onDone;
pendingRequest.onError = args.onError;
+ pendingRequest.onProgress = args.onProgress;
xhr.send(null);
return xhrId;
},
+ onProgress: function NetworkManager_onProgress(xhrId, evt) {
+ var pendingRequest = this.pendingRequests[xhrId];
+ if (!pendingRequest) {
+ // Maybe abortRequest was called...
+ return;
+ }
+
+ if (pendingRequest.mozChunked) {
+ var chunk = getArrayBuffer(pendingRequest.xhr);
+ pendingRequest.onProgressiveData(chunk);
+ }
+
+ var onProgress = pendingRequest.onProgress;
+ if (onProgress) {
+ onProgress(evt);
+ }
+ },
+
onStateChange: function NetworkManager_onStateChange(xhrId, evt) {
var pendingRequest = this.pendingRequests[xhrId];
if (!pendingRequest) {
@@ -4279,7 +1760,7 @@ var NetworkManager = (function NetworkManagerClosure() {
delete this.pendingRequests[xhrId];
// success status == 0 can be on ftp, file and other protocols
- if (xhr.status === 0 && /^https?:/i.test(this.url)) {
+ if (xhr.status === 0 && this.isHttp) {
if (pendingRequest.onError) {
pendingRequest.onError(xhr.status);
}
@@ -4313,6 +1794,8 @@ var NetworkManager = (function NetworkManagerClosure() {
begin: begin,
chunk: chunk
});
+ } else if (pendingRequest.onProgressiveData) {
+ pendingRequest.onDone(null);
} else {
pendingRequest.onDone({
begin: 0,
@@ -4332,6 +1815,10 @@ var NetworkManager = (function NetworkManagerClosure() {
return this.pendingRequests[xhrId].xhr;
},
+ isStreamingRequest: function NetworkManager_isStreamingRequest(xhrId) {
+ return !!(this.pendingRequests[xhrId].onProgressiveData);
+ },
+
isPendingRequest: function NetworkManager_isPendingRequest(xhrId) {
return xhrId in this.pendingRequests;
},
@@ -4369,7 +1856,8 @@ var ChunkedStream = (function ChunkedStreamClosure() {
this.numChunksLoaded = 0;
this.numChunks = Math.ceil(length / chunkSize);
this.manager = manager;
- this.initialDataLength = 0;
+ this.progressiveDataLength = 0;
+ this.lastSuccessfulEnsureByteChunk = -1; // a single-entry cache
}
// required methods for a stream. if a particular stream does not
@@ -4379,7 +1867,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
getMissingChunks: function ChunkedStream_getMissingChunks() {
var chunks = [];
for (var chunk = 0, n = this.numChunks; chunk < n; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
+ if (!this.loadedChunks[chunk]) {
chunks.push(chunk);
}
}
@@ -4394,7 +1882,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
return this.numChunksLoaded === this.numChunks;
},
- onReceiveData: function(begin, chunk) {
+ onReceiveData: function ChunkedStream_onReceiveData(begin, chunk) {
var end = begin + chunk.byteLength;
assert(begin % this.chunkSize === 0, 'Bad begin offset: ' + begin);
@@ -4402,38 +1890,59 @@ var ChunkedStream = (function ChunkedStreamClosure() {
// See ChunkedStream.moveStart()
var length = this.bytes.length;
assert(end % this.chunkSize === 0 || end === length,
- 'Bad end offset: ' + end);
+ 'Bad end offset: ' + end);
this.bytes.set(new Uint8Array(chunk), begin);
var chunkSize = this.chunkSize;
var beginChunk = Math.floor(begin / chunkSize);
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
+ var curChunk;
- for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
- this.loadedChunks[chunk] = true;
+ for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
+ if (!this.loadedChunks[curChunk]) {
+ this.loadedChunks[curChunk] = true;
++this.numChunksLoaded;
}
}
},
- onReceiveInitialData: function (data) {
- this.bytes.set(data);
- this.initialDataLength = data.length;
- var endChunk = this.end === data.length ?
- this.numChunks : Math.floor(data.length / this.chunkSize);
- for (var i = 0; i < endChunk; i++) {
- this.loadedChunks[i] = true;
- ++this.numChunksLoaded;
+ onReceiveProgressiveData:
+ function ChunkedStream_onReceiveProgressiveData(data) {
+ var position = this.progressiveDataLength;
+ var beginChunk = Math.floor(position / this.chunkSize);
+
+ this.bytes.set(new Uint8Array(data), position);
+ position += data.byteLength;
+ this.progressiveDataLength = position;
+ var endChunk = position >= this.end ? this.numChunks :
+ Math.floor(position / this.chunkSize);
+ var curChunk;
+ for (curChunk = beginChunk; curChunk < endChunk; ++curChunk) {
+ if (!this.loadedChunks[curChunk]) {
+ this.loadedChunks[curChunk] = true;
+ ++this.numChunksLoaded;
+ }
}
},
+ ensureByte: function ChunkedStream_ensureByte(pos) {
+ var chunk = Math.floor(pos / this.chunkSize);
+ if (chunk === this.lastSuccessfulEnsureByteChunk) {
+ return;
+ }
+
+ if (!this.loadedChunks[chunk]) {
+ throw new MissingDataException(pos, pos + 1);
+ }
+ this.lastSuccessfulEnsureByteChunk = chunk;
+ },
+
ensureRange: function ChunkedStream_ensureRange(begin, end) {
if (begin >= end) {
return;
}
- if (end <= this.initialDataLength) {
+ if (end <= this.progressiveDataLength) {
return;
}
@@ -4441,21 +1950,22 @@ var ChunkedStream = (function ChunkedStreamClosure() {
var beginChunk = Math.floor(begin / chunkSize);
var endChunk = Math.floor((end - 1) / chunkSize) + 1;
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
+ if (!this.loadedChunks[chunk]) {
throw new MissingDataException(begin, end);
}
}
},
nextEmptyChunk: function ChunkedStream_nextEmptyChunk(beginChunk) {
- for (var chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
+ var chunk, n;
+ for (chunk = beginChunk, n = this.numChunks; chunk < n; ++chunk) {
+ if (!this.loadedChunks[chunk]) {
return chunk;
}
}
// Wrap around to beginning
- for (var chunk = 0; chunk < beginChunk; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
+ for (chunk = 0; chunk < beginChunk; ++chunk) {
+ if (!this.loadedChunks[chunk]) {
return chunk;
}
}
@@ -4463,22 +1973,40 @@ var ChunkedStream = (function ChunkedStreamClosure() {
},
hasChunk: function ChunkedStream_hasChunk(chunk) {
- return chunk in this.loadedChunks;
+ return !!this.loadedChunks[chunk];
},
get length() {
return this.end - this.start;
},
+ get isEmpty() {
+ return this.length === 0;
+ },
+
getByte: function ChunkedStream_getByte() {
var pos = this.pos;
if (pos >= this.end) {
return -1;
}
- this.ensureRange(pos, pos + 1);
+ this.ensureByte(pos);
return this.bytes[this.pos++];
},
+ getUint16: function ChunkedStream_getUint16() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ return (b0 << 8) + b1;
+ },
+
+ getInt32: function ChunkedStream_getInt32() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ var b2 = this.getByte();
+ var b3 = this.getByte();
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
+ },
+
// returns subarray of original buffer
// should only be read
getBytes: function ChunkedStream_getBytes(length) {
@@ -4492,14 +2020,21 @@ var ChunkedStream = (function ChunkedStreamClosure() {
}
var end = pos + length;
- if (end > strEnd)
+ if (end > strEnd) {
end = strEnd;
+ }
this.ensureRange(pos, end);
this.pos = end;
return bytes.subarray(pos, end);
},
+ peekByte: function ChunkedStream_peekByte() {
+ var peekedByte = this.getByte();
+ this.pos--;
+ return peekedByte;
+ },
+
peekBytes: function ChunkedStream_peekBytes(length) {
var bytes = this.getBytes(length);
this.pos -= bytes.length;
@@ -4512,8 +2047,9 @@ var ChunkedStream = (function ChunkedStreamClosure() {
},
skip: function ChunkedStream_skip(n) {
- if (!n)
+ if (!n) {
n = 1;
+ }
this.pos += n;
},
@@ -4526,6 +2062,8 @@ var ChunkedStream = (function ChunkedStreamClosure() {
},
makeSubStream: function ChunkedStream_makeSubStream(start, length, dict) {
+ this.ensureRange(start, start + length);
+
function ChunkedStreamSubstream() {}
ChunkedStreamSubstream.prototype = Object.create(this);
ChunkedStreamSubstream.prototype.getMissingChunks = function() {
@@ -4534,7 +2072,7 @@ var ChunkedStream = (function ChunkedStreamClosure() {
var endChunk = Math.floor((this.end - 1) / chunkSize) + 1;
var missingChunks = [];
for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
- if (!(chunk in this.loadedChunks)) {
+ if (!this.loadedChunks[chunk]) {
missingChunks.push(chunk);
}
}
@@ -4556,7 +2094,6 @@ var ChunkedStream = (function ChunkedStreamClosure() {
var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
function ChunkedStreamManager(length, chunkSize, url, args) {
- var self = this;
this.stream = new ChunkedStream(length, chunkSize, this);
this.length = length;
this.chunkSize = chunkSize;
@@ -4577,7 +2114,8 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
};
this.networkManager = new NetworkManager(this.url, {
getXhr: getXhr,
- httpHeaders: args.httpHeaders
+ httpHeaders: args.httpHeaders,
+ withCredentials: args.withCredentials
});
this.sendRequest = function ChunkedStreamManager_sendRequest(begin, end) {
this.networkManager.requestRange(begin, end, {
@@ -4592,29 +2130,18 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
this.chunksNeededByRequest = {};
this.requestsByChunk = {};
this.callbacksByRequest = {};
+ this.progressiveDataLength = 0;
+
+ this._loadedStreamCapability = createPromiseCapability();
- this.loadedStream = new LegacyPromise();
if (args.initialData) {
- this.setInitialData(args.initialData);
+ this.onReceiveData({chunk: args.initialData});
}
}
ChunkedStreamManager.prototype = {
-
- setInitialData: function ChunkedStreamManager_setInitialData(data) {
- this.stream.onReceiveInitialData(data);
- if (this.stream.allChunksLoaded()) {
- this.loadedStream.resolve(this.stream);
- } else if (this.msgHandler) {
- this.msgHandler.send('DocProgress', {
- loaded: data.length,
- total: this.length
- });
- }
- },
-
onLoadedStream: function ChunkedStreamManager_getLoadedStream() {
- return this.loadedStream;
+ return this._loadedStreamCapability.promise;
},
// Get all the chunks that are not yet loaded and groups them into
@@ -4622,7 +2149,7 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
requestAllChunks: function ChunkedStreamManager_requestAllChunks() {
var missingChunks = this.stream.getMissingChunks();
this.requestChunks(missingChunks);
- return this.loadedStream;
+ return this._loadedStreamCapability.promise;
},
requestChunks: function ChunkedStreamManager_requestChunks(chunks,
@@ -4630,8 +2157,9 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
var requestId = this.currRequestId++;
var chunksNeeded;
+ var i, ii;
this.chunksNeededByRequest[requestId] = chunksNeeded = {};
- for (var i = 0, ii = chunks.length; i < ii; i++) {
+ for (i = 0, ii = chunks.length; i < ii; i++) {
if (!this.stream.hasChunk(chunks[i])) {
chunksNeeded[chunks[i]] = true;
}
@@ -4662,7 +2190,7 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
var groupedChunksToRequest = this.groupChunks(chunksToRequest);
- for (var i = 0; i < groupedChunksToRequest.length; ++i) {
+ for (i = 0; i < groupedChunksToRequest.length; ++i) {
var groupedChunk = groupedChunksToRequest[i];
var begin = groupedChunk.beginChunk * this.chunkSize;
var end = Math.min(groupedChunk.endChunk * this.chunkSize, this.length);
@@ -4724,13 +2252,13 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
}
if (prevChunk >= 0 && prevChunk + 1 !== chunk) {
- groupedChunks.push({
- beginChunk: beginChunk, endChunk: prevChunk + 1});
+ groupedChunks.push({ beginChunk: beginChunk,
+ endChunk: prevChunk + 1 });
beginChunk = chunk;
}
if (i + 1 === chunks.length) {
- groupedChunks.push({
- beginChunk: beginChunk, endChunk: chunk + 1});
+ groupedChunks.push({ beginChunk: beginChunk,
+ endChunk: chunk + 1 });
}
prevChunk = chunk;
@@ -4739,8 +2267,8 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
},
onProgress: function ChunkedStreamManager_onProgress(args) {
- var bytesLoaded = this.stream.numChunksLoaded * this.chunkSize +
- args.loaded;
+ var bytesLoaded = (this.stream.numChunksLoaded * this.chunkSize +
+ args.loaded);
this.msgHandler.send('DocProgress', {
loaded: bytesLoaded,
total: this.length
@@ -4749,26 +2277,34 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
onReceiveData: function ChunkedStreamManager_onReceiveData(args) {
var chunk = args.chunk;
- var begin = args.begin;
+ var isProgressive = args.begin === undefined;
+ var begin = isProgressive ? this.progressiveDataLength : args.begin;
var end = begin + chunk.byteLength;
- var beginChunk = this.getBeginChunk(begin);
- var endChunk = this.getEndChunk(end);
+ var beginChunk = Math.floor(begin / this.chunkSize);
+ var endChunk = end < this.length ? Math.floor(end / this.chunkSize) :
+ Math.ceil(end / this.chunkSize);
+
+ if (isProgressive) {
+ this.stream.onReceiveProgressiveData(chunk);
+ this.progressiveDataLength = end;
+ } else {
+ this.stream.onReceiveData(begin, chunk);
+ }
- this.stream.onReceiveData(begin, chunk);
if (this.stream.allChunksLoaded()) {
- this.loadedStream.resolve(this.stream);
+ this._loadedStreamCapability.resolve(this.stream);
}
var loadedRequests = [];
- for (var chunk = beginChunk; chunk < endChunk; ++chunk) {
-
+ var i, requestId;
+ for (chunk = beginChunk; chunk < endChunk; ++chunk) {
// The server might return more chunks than requested
var requestIds = this.requestsByChunk[chunk] || [];
delete this.requestsByChunk[chunk];
- for (var i = 0; i < requestIds.length; ++i) {
- var requestId = requestIds[i];
+ for (i = 0; i < requestIds.length; ++i) {
+ requestId = requestIds[i];
var chunksNeeded = this.chunksNeededByRequest[requestId];
if (chunk in chunksNeeded) {
delete chunksNeeded[chunk];
@@ -4802,8 +2338,8 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
}
}
- for (var i = 0; i < loadedRequests.length; ++i) {
- var requestId = loadedRequests[i];
+ for (i = 0; i < loadedRequests.length; ++i) {
+ requestId = loadedRequests[i];
var callback = this.callbacksByRequest[requestId];
delete this.callbacksByRequest[requestId];
if (callback) {
@@ -4817,6 +2353,10 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
});
},
+ onError: function ChunkedStreamManager_onError(err) {
+ this._loadedStreamCapability.reject(err);
+ },
+
getBeginChunk: function ChunkedStreamManager_getBeginChunk(begin) {
var chunk = Math.floor(begin / this.chunkSize);
return chunk;
@@ -4842,6 +2382,9 @@ var ChunkedStreamManager = (function ChunkedStreamManagerClosure() {
+// The maximum number of bytes fetched per range request
+var RANGE_CHUNK_SIZE = 65536;
+
// TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
var BasePdfManager = (function BasePdfManagerClosure() {
function BasePdfManager() {
@@ -4853,24 +2396,24 @@ var BasePdfManager = (function BasePdfManagerClosure() {
throw new NotImplementedException();
},
- ensureModel: function BasePdfManager_ensureModel(prop, args) {
- return this.ensure(this.pdfModel, prop, args);
+ ensureDoc: function BasePdfManager_ensureDoc(prop, args) {
+ return this.ensure(this.pdfDocument, prop, args);
},
ensureXRef: function BasePdfManager_ensureXRef(prop, args) {
- return this.ensure(this.pdfModel.xref, prop, args);
+ return this.ensure(this.pdfDocument.xref, prop, args);
},
ensureCatalog: function BasePdfManager_ensureCatalog(prop, args) {
- return this.ensure(this.pdfModel.catalog, prop, args);
+ return this.ensure(this.pdfDocument.catalog, prop, args);
},
getPage: function BasePdfManager_pagePage(pageIndex) {
- return this.pdfModel.getPage(pageIndex);
+ return this.pdfDocument.getPage(pageIndex);
},
cleanup: function BasePdfManager_cleanup() {
- return this.pdfModel.cleanup();
+ return this.pdfDocument.cleanup();
},
ensure: function BasePdfManager_ensure(obj, prop, args) {
@@ -4885,13 +2428,22 @@ var BasePdfManager = (function BasePdfManagerClosure() {
return new NotImplementedException();
},
+ sendProgressiveData: function BasePdfManager_sendProgressiveData(chunk) {
+ return new NotImplementedException();
+ },
+
updatePassword: function BasePdfManager_updatePassword(password) {
- this.pdfModel.xref.password = this.password = password;
- if (this.passwordChangedPromise) {
- this.passwordChangedPromise.resolve();
+ this.pdfDocument.xref.password = this.password = password;
+ if (this._passwordChangedCapability) {
+ this._passwordChangedCapability.resolve();
}
},
+ passwordChanged: function BasePdfManager_passwordChanged() {
+ this._passwordChangedCapability = createPromiseCapability();
+ return this._passwordChangedCapability.promise;
+ },
+
terminate: function BasePdfManager_terminate() {
return new NotImplementedException();
}
@@ -4903,9 +2455,9 @@ var BasePdfManager = (function BasePdfManagerClosure() {
var LocalPdfManager = (function LocalPdfManagerClosure() {
function LocalPdfManager(data, password) {
var stream = new Stream(data);
- this.pdfModel = new PDFDocument(this, stream, password);
- this.loadedStream = new LegacyPromise();
- this.loadedStream.resolve(stream);
+ this.pdfDocument = new PDFDocument(this, stream, password);
+ this._loadedStreamCapability = createPromiseCapability();
+ this._loadedStreamCapability.resolve(stream);
}
LocalPdfManager.prototype = Object.create(BasePdfManager.prototype);
@@ -4913,28 +2465,25 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
LocalPdfManager.prototype.ensure =
function LocalPdfManager_ensure(obj, prop, args) {
- var promise = new LegacyPromise();
- try {
- var value = obj[prop];
- var result;
- if (typeof(value) === 'function') {
- result = value.apply(obj, args);
- } else {
- result = value;
+ return new Promise(function (resolve, reject) {
+ try {
+ var value = obj[prop];
+ var result;
+ if (typeof value === 'function') {
+ result = value.apply(obj, args);
+ } else {
+ result = value;
+ }
+ resolve(result);
+ } catch (e) {
+ reject(e);
}
- promise.resolve(result);
- } catch (e) {
- console.log(e.stack);
- promise.reject(e);
- }
- return promise;
+ });
};
LocalPdfManager.prototype.requestRange =
function LocalPdfManager_requestRange(begin, end) {
- var promise = new LegacyPromise();
- promise.resolve();
- return promise;
+ return Promise.resolve();
};
LocalPdfManager.prototype.requestLoadedStream =
@@ -4943,7 +2492,7 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
LocalPdfManager.prototype.onLoadedStream =
function LocalPdfManager_getLoadedStream() {
- return this.loadedStream;
+ return this._loadedStreamCapability.promise;
};
LocalPdfManager.prototype.terminate =
@@ -4955,9 +2504,6 @@ var LocalPdfManager = (function LocalPdfManagerClosure() {
})();
var NetworkPdfManager = (function NetworkPdfManagerClosure() {
-
- var CHUNK_SIZE = 65536;
-
function NetworkPdfManager(args, msgHandler) {
this.msgHandler = msgHandler;
@@ -4965,14 +2511,15 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
var params = {
msgHandler: msgHandler,
httpHeaders: args.httpHeaders,
+ withCredentials: args.withCredentials,
chunkedViewerLoading: args.chunkedViewerLoading,
disableAutoFetch: args.disableAutoFetch,
initialData: args.initialData
};
- this.streamManager = new ChunkedStreamManager(args.length, CHUNK_SIZE,
+ this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
args.url, params);
- this.pdfModel = new PDFDocument(this, this.streamManager.getStream(),
+ this.pdfDocument = new PDFDocument(this, this.streamManager.getStream(),
args.password);
}
@@ -4981,42 +2528,39 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
NetworkPdfManager.prototype.ensure =
function NetworkPdfManager_ensure(obj, prop, args) {
- var promise = new LegacyPromise();
- this.ensureHelper(promise, obj, prop, args);
- return promise;
- };
+ var pdfManager = this;
- NetworkPdfManager.prototype.ensureHelper =
- function NetworkPdfManager_ensureHelper(promise, obj, prop, args) {
- try {
- var result;
- var value = obj[prop];
- if (typeof(value) === 'function') {
- result = value.apply(obj, args);
- } else {
- result = value;
- }
- promise.resolve(result);
- } catch(e) {
- if (!(e instanceof MissingDataException)) {
- console.log(e.stack);
- promise.reject(e);
- return;
+ return new Promise(function (resolve, reject) {
+ function ensureHelper() {
+ try {
+ var result;
+ var value = obj[prop];
+ if (typeof value === 'function') {
+ result = value.apply(obj, args);
+ } else {
+ result = value;
+ }
+ resolve(result);
+ } catch(e) {
+ if (!(e instanceof MissingDataException)) {
+ reject(e);
+ return;
+ }
+ pdfManager.streamManager.requestRange(e.begin, e.end, ensureHelper);
+ }
}
- this.streamManager.requestRange(e.begin, e.end, function() {
- this.ensureHelper(promise, obj, prop, args);
- }.bind(this));
- }
+ ensureHelper();
+ });
};
NetworkPdfManager.prototype.requestRange =
function NetworkPdfManager_requestRange(begin, end) {
- var promise = new LegacyPromise();
- this.streamManager.requestRange(begin, end, function() {
- promise.resolve();
- });
- return promise;
+ return new Promise(function (resolve) {
+ this.streamManager.requestRange(begin, end, function() {
+ resolve();
+ });
+ }.bind(this));
};
NetworkPdfManager.prototype.requestLoadedStream =
@@ -5024,6 +2568,11 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
this.streamManager.requestAllChunks();
};
+ NetworkPdfManager.prototype.sendProgressiveData =
+ function NetworkPdfManager_sendProgressiveData(chunk) {
+ this.streamManager.onReceiveData({ chunk: chunk });
+ };
+
NetworkPdfManager.prototype.onLoadedStream =
function NetworkPdfManager_getLoadedStream() {
return this.streamManager.onLoadedStream();
@@ -5041,6 +2590,8 @@ var NetworkPdfManager = (function NetworkPdfManagerClosure() {
var Page = (function PageClosure() {
+ var LETTER_SIZE_MEDIABOX = [0, 0, 612, 792];
+
function Page(pdfManager, xref, pageIndex, pageDict, ref, fontCache) {
this.pdfManager = pdfManager;
this.pageIndex = pageIndex;
@@ -5058,51 +2609,69 @@ var Page = (function PageClosure() {
getPageProp: function Page_getPageProp(key) {
return this.pageDict.get(key);
},
- inheritPageProp: function Page_inheritPageProp(key) {
+
+ getInheritedPageProp: function Page_inheritPageProp(key) {
var dict = this.pageDict;
- var obj = dict.get(key);
- while (obj === undefined) {
+ var value = dict.get(key);
+ while (value === undefined) {
dict = dict.get('Parent');
- if (!dict)
+ if (!dict) {
break;
- obj = dict.get(key);
+ }
+ value = dict.get(key);
}
- return obj;
+ return value;
},
+
get content() {
return this.getPageProp('Contents');
},
+
get resources() {
- return shadow(this, 'resources', this.inheritPageProp('Resources'));
+ var value = this.getInheritedPageProp('Resources');
+ // For robustness: The spec states that a \Resources entry has to be
+ // present, but can be empty. Some document omit it still. In this case
+ // return an empty dictionary:
+ if (value === undefined) {
+ value = Dict.empty;
+ }
+ return shadow(this, 'resources', value);
},
+
get mediaBox() {
- var obj = this.inheritPageProp('MediaBox');
+ var obj = this.getInheritedPageProp('MediaBox');
// Reset invalid media box to letter size.
- if (!isArray(obj) || obj.length !== 4)
- obj = [0, 0, 612, 792];
+ if (!isArray(obj) || obj.length !== 4) {
+ obj = LETTER_SIZE_MEDIABOX;
+ }
return shadow(this, 'mediaBox', obj);
},
+
get view() {
var mediaBox = this.mediaBox;
- var cropBox = this.inheritPageProp('CropBox');
- if (!isArray(cropBox) || cropBox.length !== 4)
+ var cropBox = this.getInheritedPageProp('CropBox');
+ if (!isArray(cropBox) || cropBox.length !== 4) {
return shadow(this, 'view', mediaBox);
+ }
// From the spec, 6th ed., p.963:
// "The crop, bleed, trim, and art boxes should not ordinarily
// extend beyond the boundaries of the media box. If they do, they are
// effectively reduced to their intersection with the media box."
cropBox = Util.intersect(cropBox, mediaBox);
- if (!cropBox)
+ if (!cropBox) {
return shadow(this, 'view', mediaBox);
-
+ }
return shadow(this, 'view', cropBox);
},
+
get annotationRefs() {
- return shadow(this, 'annotationRefs', this.inheritPageProp('Annots'));
+ return shadow(this, 'annotationRefs',
+ this.getInheritedPageProp('Annots'));
},
+
get rotate() {
- var rotate = this.inheritPageProp('Rotate') || 0;
+ var rotate = this.getInheritedPageProp('Rotate') || 0;
// Normalize rotation so it's a multiple of 90 and between 0 and 270
if (rotate % 90 !== 0) {
rotate = 0;
@@ -5115,6 +2684,7 @@ var Page = (function PageClosure() {
}
return shadow(this, 'rotate', rotate);
},
+
getContentStream: function Page_getContentStream() {
var content = this.content;
var stream;
@@ -5123,8 +2693,9 @@ var Page = (function PageClosure() {
var xref = this.xref;
var i, n = content.length;
var streams = [];
- for (i = 0; i < n; ++i)
+ for (i = 0; i < n; ++i) {
streams.push(xref.fetchIfRef(content[i]));
+ }
stream = new StreamsSequenceStream(streams);
} else if (isStream(content)) {
stream = content;
@@ -5134,31 +2705,22 @@ var Page = (function PageClosure() {
}
return stream;
},
- loadResources: function(keys) {
+
+ loadResources: function Page_loadResources(keys) {
if (!this.resourcesPromise) {
- // TODO: add async inheritPageProp and remove this.
+ // TODO: add async getInheritedPageProp and remove this.
this.resourcesPromise = this.pdfManager.ensure(this, 'resources');
}
- var promise = new LegacyPromise();
- this.resourcesPromise.then(function resourceSuccess() {
+ return this.resourcesPromise.then(function resourceSuccess() {
var objectLoader = new ObjectLoader(this.resources.map,
keys,
this.xref);
- objectLoader.load().then(function objectLoaderSuccess() {
- promise.resolve();
- });
+ return objectLoader.load();
}.bind(this));
- return promise;
},
- getOperatorList: function Page_getOperatorList(handler) {
+
+ getOperatorList: function Page_getOperatorList(handler, intent) {
var self = this;
- var promise = new LegacyPromise();
-
- function reject(e) {
- promise.reject(e);
- }
-
- var pageListPromise = new LegacyPromise();
var pdfManager = this.pdfManager;
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
@@ -5169,53 +2731,53 @@ var Page = (function PageClosure() {
'Pattern',
'Shading',
'XObject',
- 'Font',
+ 'Font'
// ProcSet
// Properties
]);
- var partialEvaluator = new PartialEvaluator(
- pdfManager, this.xref, handler,
- this.pageIndex, 'p' + this.pageIndex + '_',
- this.idCounters, this.fontCache);
+ var partialEvaluator = new PartialEvaluator(pdfManager, this.xref,
+ handler, this.pageIndex,
+ 'p' + this.pageIndex + '_',
+ this.idCounters,
+ this.fontCache);
- var dataPromises = Promise.all(
- [contentStreamPromise, resourcesPromise], reject);
- dataPromises.then(function(data) {
+ var dataPromises = Promise.all([contentStreamPromise, resourcesPromise]);
+ var pageListPromise = dataPromises.then(function(data) {
var contentStream = data[0];
-
-
- var opList = new OperatorList(handler, self.pageIndex);
+ var opList = new OperatorList(intent, handler, self.pageIndex);
handler.send('StartRenderPage', {
transparency: partialEvaluator.hasBlendModes(self.resources),
- pageIndex: self.pageIndex
+ pageIndex: self.pageIndex,
+ intent: intent
});
- partialEvaluator.getOperatorList(contentStream, self.resources, opList);
- pageListPromise.resolve(opList);
+ return partialEvaluator.getOperatorList(contentStream, self.resources,
+ opList).then(function () {
+ return opList;
+ });
});
var annotationsPromise = pdfManager.ensure(this, 'annotations');
- Promise.all([pageListPromise, annotationsPromise]).then(function(datas) {
+ return Promise.all([pageListPromise, annotationsPromise]).then(
+ function(datas) {
var pageOpList = datas[0];
var annotations = datas[1];
if (annotations.length === 0) {
pageOpList.flush(true);
- promise.resolve(pageOpList);
- return;
+ return pageOpList;
}
var annotationsReadyPromise = Annotation.appendToOperatorList(
- annotations, pageOpList, pdfManager, partialEvaluator);
- annotationsReadyPromise.then(function () {
+ annotations, pageOpList, pdfManager, partialEvaluator, intent);
+ return annotationsReadyPromise.then(function () {
pageOpList.flush(true);
- promise.resolve(pageOpList);
- }, reject);
- }, reject);
-
- return promise;
+ return pageOpList;
+ });
+ });
},
+
extractTextContent: function Page_extractTextContent() {
var handler = {
on: function nullHandlerOn() {},
@@ -5224,8 +2786,6 @@ var Page = (function PageClosure() {
var self = this;
- var textContentPromise = new LegacyPromise();
-
var pdfManager = this.pdfManager;
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
[]);
@@ -5238,19 +2798,17 @@ var Page = (function PageClosure() {
var dataPromises = Promise.all([contentStreamPromise,
resourcesPromise]);
- dataPromises.then(function(data) {
+ return dataPromises.then(function(data) {
var contentStream = data[0];
- var partialEvaluator = new PartialEvaluator(
- pdfManager, self.xref, handler,
- self.pageIndex, 'p' + self.pageIndex + '_',
- self.idCounters, self.fontCache);
+ var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
+ handler, self.pageIndex,
+ 'p' + self.pageIndex + '_',
+ self.idCounters,
+ self.fontCache);
- var bidiTexts = partialEvaluator.getTextContent(contentStream,
- self.resources);
- textContentPromise.resolve(bidiTexts);
+ return partialEvaluator.getTextContent(contentStream,
+ self.resources);
});
-
- return textContentPromise;
},
getAnnotationsData: function Page_getAnnotationsData() {
@@ -5264,7 +2822,7 @@ var Page = (function PageClosure() {
get annotations() {
var annotations = [];
- var annotationRefs = this.annotationRefs || [];
+ var annotationRefs = (this.annotationRefs || []);
for (var i = 0, n = annotationRefs.length; i < n; ++i) {
var annotationRef = annotationRefs[i];
var annotation = Annotation.fromRef(this.xref, annotationRef);
@@ -5288,16 +2846,17 @@ var Page = (function PageClosure() {
*/
var PDFDocument = (function PDFDocumentClosure() {
function PDFDocument(pdfManager, arg, password) {
- if (isStream(arg))
+ if (isStream(arg)) {
init.call(this, pdfManager, arg, password);
- else if (isArrayBuffer(arg))
+ } else if (isArrayBuffer(arg)) {
init.call(this, pdfManager, new Stream(arg), password);
- else
+ } else {
error('PDFDocument: Unknown argument type');
+ }
}
function init(pdfManager, stream, password) {
- assertWellFormed(stream.length > 0, 'stream must have data');
+ assert(stream.length > 0, 'stream must have data');
this.pdfManager = pdfManager;
this.stream = stream;
var xref = new XRef(this.stream, password, pdfManager);
@@ -5307,15 +2866,19 @@ var PDFDocument = (function PDFDocumentClosure() {
function find(stream, needle, limit, backwards) {
var pos = stream.pos;
var end = stream.end;
- var str = '';
- if (pos + limit > end)
+ var strBuf = [];
+ if (pos + limit > end) {
limit = end - pos;
- for (var n = 0; n < limit; ++n)
- str += String.fromCharCode(stream.getByte());
+ }
+ for (var n = 0; n < limit; ++n) {
+ strBuf.push(String.fromCharCode(stream.getByte()));
+ }
+ var str = strBuf.join('');
stream.pos = pos;
var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle);
- if (index == -1)
+ if (index === -1) {
return false; /* not found */
+ }
stream.pos += index;
return true; /* found */
}
@@ -5360,22 +2923,15 @@ var PDFDocument = (function PDFDocumentClosure() {
},
get linearization() {
- var length = this.stream.length;
- var linearization = false;
- if (length) {
+ var linearization = null;
+ if (this.stream.length) {
try {
- linearization = new Linearization(this.stream);
- if (linearization.length != length) {
- linearization = false;
- }
+ linearization = Linearization.create(this.stream);
} catch (err) {
if (err instanceof MissingDataException) {
throw err;
}
-
- info('The linearization data is not available ' +
- 'or unreadable PDF data is found');
- linearization = false;
+ info(err);
}
}
// shadow the prototype getter with a data property
@@ -5388,16 +2944,18 @@ var PDFDocument = (function PDFDocumentClosure() {
if (linearization) {
// Find end of first obj.
stream.reset();
- if (find(stream, 'endobj', 1024))
+ if (find(stream, 'endobj', 1024)) {
startXRef = stream.pos + 6;
+ }
} else {
// Find startxref by jumping backward from the end of the file.
var step = 1024;
var found = false, pos = stream.end;
while (!found && pos > 0) {
pos -= step - 'startxref'.length;
- if (pos < 0)
+ if (pos < 0) {
pos = 0;
+ }
stream.pos = pos;
found = find(stream, 'startxref', step, true);
}
@@ -5413,8 +2971,9 @@ var PDFDocument = (function PDFDocumentClosure() {
ch = stream.getByte();
}
startXRef = parseInt(str, 10);
- if (isNaN(startXRef))
+ if (isNaN(startXRef)) {
startXRef = 0;
+ }
}
}
// shadow the prototype getter with a data property
@@ -5423,8 +2982,9 @@ var PDFDocument = (function PDFDocumentClosure() {
get mainXRefEntriesOffset() {
var mainXRefEntriesOffset = 0;
var linearization = this.linearization;
- if (linearization)
+ if (linearization) {
mainXRefEntriesOffset = linearization.mainXRefEntriesOffset;
+ }
// shadow the prototype getter with a data property
return shadow(this, 'mainXRefEntriesOffset', mainXRefEntriesOffset);
},
@@ -5485,8 +3045,8 @@ var PDFDocument = (function PDFDocumentClosure() {
var value = infoDict.get(key);
// Make sure the value conforms to the spec.
if (validEntries[key](value)) {
- docInfo[key] = typeof value !== 'string' ? value :
- stringToPDFString(value);
+ docInfo[key] = (typeof value !== 'string' ?
+ value : stringToPDFString(value));
} else {
info('Bad value in document info for "' + key + '"');
}
@@ -5532,6 +3092,13 @@ var Name = (function NameClosure() {
Name.prototype = {};
+ var nameCache = {};
+
+ Name.get = function Name_get(name) {
+ var nameValue = nameCache[name];
+ return (nameValue ? nameValue : (nameCache[name] = new Name(name)));
+ };
+
return Name;
})();
@@ -5546,10 +3113,7 @@ var Cmd = (function CmdClosure() {
Cmd.get = function Cmd_get(cmd) {
var cmdValue = cmdCache[cmd];
- if (cmdValue)
- return cmdValue;
-
- return cmdCache[cmd] = new Cmd(cmd);
+ return (cmdValue ? cmdValue : (cmdCache[cmd] = new Cmd(cmd)));
};
return Cmd;
@@ -5560,11 +3124,30 @@ var Dict = (function DictClosure() {
return nonSerializable; // creating closure on some variable
};
+ var GETALL_DICTIONARY_TYPES_WHITELIST = {
+ 'Background': true,
+ 'ExtGState': true,
+ 'Halftone': true,
+ 'Layout': true,
+ 'Mask': true,
+ 'Pagination': true,
+ 'Printing': true
+ };
+
+ function isRecursionAllowedFor(dict) {
+ if (!isName(dict.Type)) {
+ return true;
+ }
+ var dictType = dict.Type.name;
+ return GETALL_DICTIONARY_TYPES_WHITELIST[dictType] === true;
+ }
+
// xref is optional
function Dict(xref) {
// Map should only be used internally, use functions below to access.
this.map = Object.create(null);
this.xref = xref;
+ this.objId = null;
this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
}
@@ -5577,12 +3160,12 @@ var Dict = (function DictClosure() {
get: function Dict_get(key1, key2, key3) {
var value;
var xref = this.xref;
- if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
- typeof key2 == 'undefined') {
+ if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
+ typeof key2 === 'undefined') {
return xref ? xref.fetchIfRef(value) : value;
}
- if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
- typeof key3 == 'undefined') {
+ if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
+ typeof key3 === 'undefined') {
return xref ? xref.fetchIfRef(value) : value;
}
value = this.map[key3] || null;
@@ -5592,33 +3175,26 @@ var Dict = (function DictClosure() {
// Same as get(), but returns a promise and uses fetchIfRefAsync().
getAsync: function Dict_getAsync(key1, key2, key3) {
var value;
- var promise;
var xref = this.xref;
- if (typeof (value = this.map[key1]) !== undefined || key1 in this.map ||
- typeof key2 === undefined) {
+ if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
+ typeof key2 === 'undefined') {
if (xref) {
return xref.fetchIfRefAsync(value);
}
- promise = new LegacyPromise();
- promise.resolve(value);
- return promise;
+ return Promise.resolve(value);
}
- if (typeof (value = this.map[key2]) !== undefined || key2 in this.map ||
- typeof key3 === undefined) {
+ if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
+ typeof key3 === 'undefined') {
if (xref) {
return xref.fetchIfRefAsync(value);
}
- promise = new LegacyPromise();
- promise.resolve(value);
- return promise;
+ return Promise.resolve(value);
}
value = this.map[key3] || null;
if (xref) {
return xref.fetchIfRefAsync(value);
}
- promise = new LegacyPromise();
- promise.resolve(value);
- return promise;
+ return Promise.resolve(value);
},
// no dereferencing
@@ -5628,10 +3204,52 @@ var Dict = (function DictClosure() {
// creates new map and dereferences all Refs
getAll: function Dict_getAll() {
- var all = {};
- for (var key in this.map) {
- var obj = this.get(key);
- all[key] = obj instanceof Dict ? obj.getAll() : obj;
+ var all = Object.create(null);
+ var queue = null;
+ var key, obj;
+ for (key in this.map) {
+ obj = this.get(key);
+ if (obj instanceof Dict) {
+ if (isRecursionAllowedFor(obj)) {
+ (queue || (queue = [])).push({target: all, key: key, obj: obj});
+ } else {
+ all[key] = this.getRaw(key);
+ }
+ } else {
+ all[key] = obj;
+ }
+ }
+ if (!queue) {
+ return all;
+ }
+
+ // trying to take cyclic references into the account
+ var processed = Object.create(null);
+ while (queue.length > 0) {
+ var item = queue.shift();
+ var itemObj = item.obj;
+ var objId = itemObj.objId;
+ if (objId && objId in processed) {
+ item.target[item.key] = processed[objId];
+ continue;
+ }
+ var dereferenced = Object.create(null);
+ for (key in itemObj.map) {
+ obj = itemObj.get(key);
+ if (obj instanceof Dict) {
+ if (isRecursionAllowedFor(obj)) {
+ queue.push({target: dereferenced, key: key, obj: obj});
+ } else {
+ dereferenced[key] = itemObj.getRaw(key);
+ }
+ } else {
+ dereferenced[key] = obj;
+ }
+ }
+ if (objId) {
+ processed[objId] = dereferenced;
+ }
+ item.target[item.key] = dereferenced;
}
return all;
},
@@ -5651,6 +3269,8 @@ var Dict = (function DictClosure() {
}
};
+ Dict.empty = new Dict(null);
+
return Dict;
})();
@@ -5660,13 +3280,23 @@ var Ref = (function RefClosure() {
this.gen = gen;
}
- Ref.prototype = {};
+ Ref.prototype = {
+ toString: function Ref_toString() {
+ // This function is hot, so we make the string as compact as possible.
+ // |this.gen| is almost always zero, so we treat that case specially.
+ var str = this.num + 'R';
+ if (this.gen !== 0) {
+ str += this.gen;
+ }
+ return str;
+ }
+ };
return Ref;
})();
-// The reference is identified by number and generation,
-// this structure stores only one instance of the reference.
+// The reference is identified by number and generation.
+// This structure stores only one instance of the reference.
var RefSet = (function RefSetClosure() {
function RefSet() {
this.dict = {};
@@ -5674,15 +3304,15 @@ var RefSet = (function RefSetClosure() {
RefSet.prototype = {
has: function RefSet_has(ref) {
- return ('R' + ref.num + '.' + ref.gen) in this.dict;
+ return ref.toString() in this.dict;
},
put: function RefSet_put(ref) {
- this.dict['R' + ref.num + '.' + ref.gen] = true;
+ this.dict[ref.toString()] = true;
},
remove: function RefSet_remove(ref) {
- delete this.dict['R' + ref.num + '.' + ref.gen];
+ delete this.dict[ref.toString()];
}
};
@@ -5696,15 +3326,19 @@ var RefSetCache = (function RefSetCacheClosure() {
RefSetCache.prototype = {
get: function RefSetCache_get(ref) {
- return this.dict['R' + ref.num + '.' + ref.gen];
+ return this.dict[ref.toString()];
},
has: function RefSetCache_has(ref) {
- return ('R' + ref.num + '.' + ref.gen) in this.dict;
+ return ref.toString() in this.dict;
},
put: function RefSetCache_put(ref, obj) {
- this.dict['R' + ref.num + '.' + ref.gen] = obj;
+ this.dict[ref.toString()] = obj;
+ },
+
+ putAlias: function RefSetCache_putAlias(ref, aliasRef) {
+ this.dict[ref.toString()] = this.get(aliasRef);
},
forEach: function RefSetCache_forEach(fn, thisArg) {
@@ -5727,7 +3361,7 @@ var Catalog = (function CatalogClosure() {
this.xref = xref;
this.catDict = xref.getCatalogObj();
this.fontCache = new RefSetCache();
- assertWellFormed(isDict(this.catDict),
+ assert(isDict(this.catDict),
'catalog object is not a dictionary');
this.pagePromises = [];
@@ -5736,11 +3370,12 @@ var Catalog = (function CatalogClosure() {
Catalog.prototype = {
get metadata() {
var streamRef = this.catDict.getRaw('Metadata');
- if (!isRef(streamRef))
+ if (!isRef(streamRef)) {
return shadow(this, 'metadata', null);
+ }
- var encryptMetadata = !this.xref.encrypt ? false :
- this.xref.encrypt.encryptMetadata;
+ var encryptMetadata = (!this.xref.encrypt ? false :
+ this.xref.encrypt.encryptMetadata);
var stream = this.xref.fetch(streamRef, !encryptMetadata);
var metadata;
@@ -5767,7 +3402,7 @@ var Catalog = (function CatalogClosure() {
},
get toplevelPagesDict() {
var pagesObj = this.catDict.get('Pages');
- assertWellFormed(isDict(pagesObj), 'invalid top-level pages dictionary');
+ assert(isDict(pagesObj), 'invalid top-level pages dictionary');
// shadow the prototype getter
return shadow(this, 'toplevelPagesDict', pagesObj);
},
@@ -5798,17 +3433,20 @@ var Catalog = (function CatalogClosure() {
while (queue.length > 0) {
var i = queue.shift();
var outlineDict = xref.fetchIfRef(i.obj);
- if (outlineDict === null)
+ if (outlineDict === null) {
continue;
- if (!outlineDict.has('Title'))
+ }
+ if (!outlineDict.has('Title')) {
error('Invalid outline item');
+ }
var dest = outlineDict.get('A');
- if (dest)
+ if (dest) {
dest = dest.get('D');
- else if (outlineDict.has('Dest')) {
+ } else if (outlineDict.has('Dest')) {
dest = outlineDict.getRaw('Dest');
- if (isName(dest))
+ if (isName(dest)) {
dest = dest.name;
+ }
}
var title = outlineDict.get('Title');
var outlineItem = {
@@ -5834,11 +3472,11 @@ var Catalog = (function CatalogClosure() {
}
}
}
- return root.items.length > 0 ? root.items : null;
+ return (root.items.length > 0 ? root.items : null);
},
get numPages() {
var obj = this.toplevelPagesDict.get('Count');
- assertWellFormed(
+ assert(
isInt(obj),
'page count in top level pages object is not an integer'
);
@@ -5853,16 +3491,19 @@ var Catalog = (function CatalogClosure() {
var xref = this.xref;
var dests = {}, nameTreeRef, nameDictionaryRef;
var obj = this.catDict.get('Names');
- if (obj)
+ if (obj && obj.has('Dests')) {
nameTreeRef = obj.getRaw('Dests');
- else if (this.catDict.has('Dests'))
+ } else if (this.catDict.has('Dests')) {
nameDictionaryRef = this.catDict.get('Dests');
+ }
if (nameDictionaryRef) {
// reading simple destination dictionary
obj = nameDictionaryRef;
obj.forEach(function catalogForEach(key, value) {
- if (!value) return;
+ if (!value) {
+ return;
+ }
dests[key] = fetchDestination(value);
});
}
@@ -5878,6 +3519,62 @@ var Catalog = (function CatalogClosure() {
}
return shadow(this, 'destinations', dests);
},
+ getDestination: function Catalog_getDestination(destinationId) {
+ function fetchDestination(dest) {
+ return isDict(dest) ? dest.get('D') : dest;
+ }
+
+ var xref = this.xref;
+ var dest, nameTreeRef, nameDictionaryRef;
+ var obj = this.catDict.get('Names');
+ if (obj && obj.has('Dests')) {
+ nameTreeRef = obj.getRaw('Dests');
+ } else if (this.catDict.has('Dests')) {
+ nameDictionaryRef = this.catDict.get('Dests');
+ }
+
+ if (nameDictionaryRef) {
+ // reading simple destination dictionary
+ obj = nameDictionaryRef;
+ obj.forEach(function catalogForEach(key, value) {
+ if (!value) {
+ return;
+ }
+ if (key === destinationId) {
+ dest = fetchDestination(value);
+ }
+ });
+ }
+ if (nameTreeRef) {
+ var nameTree = new NameTree(nameTreeRef, xref);
+ dest = fetchDestination(nameTree.get(destinationId));
+ }
+ return dest;
+ },
+ get attachments() {
+ var xref = this.xref;
+ var attachments = null, nameTreeRef;
+ var obj = this.catDict.get('Names');
+ if (obj) {
+ nameTreeRef = obj.getRaw('EmbeddedFiles');
+ }
+
+ if (nameTreeRef) {
+ var nameTree = new NameTree(nameTreeRef, xref);
+ var names = nameTree.getAll();
+ for (var name in names) {
+ if (!names.hasOwnProperty(name)) {
+ continue;
+ }
+ var fs = new FileSpec(names[name], xref);
+ if (!attachments) {
+ attachments = {};
+ }
+ attachments[stringToPDFString(name)] = fs.serializable;
+ }
+ }
+ return shadow(this, 'attachments', attachments);
+ },
get javaScript() {
var xref = this.xref;
var obj = this.catDict.get('Names');
@@ -5890,7 +3587,7 @@ var Catalog = (function CatalogClosure() {
if (!names.hasOwnProperty(name)) {
continue;
}
- // We don't really use the JavaScript right now so this code is
+ // We don't really use the JavaScript right now. This code is
// defensive so we don't cause errors on document load.
var jsDict = names[name];
if (!isDict(jsDict)) {
@@ -5910,15 +3607,37 @@ var Catalog = (function CatalogClosure() {
javaScript.push(stringToPDFString(js));
}
}
+
+ // Append OpenAction actions to javaScript array
+ var openactionDict = this.catDict.get('OpenAction');
+ if (isDict(openactionDict)) {
+ var objType = openactionDict.get('Type');
+ var actionType = openactionDict.get('S');
+ var action = openactionDict.get('N');
+ var isPrintAction = (isName(objType) && objType.name === 'Action' &&
+ isName(actionType) && actionType.name === 'Named' &&
+ isName(action) && action.name === 'Print');
+
+ if (isPrintAction) {
+ javaScript.push('print(true);');
+ }
+ }
+
return shadow(this, 'javaScript', javaScript);
},
cleanup: function Catalog_cleanup() {
- this.fontCache.forEach(function (font) {
- delete font.sent;
- delete font.translated;
+ var promises = [];
+ this.fontCache.forEach(function (promise) {
+ promises.push(promise);
});
- this.fontCache.clear();
+ return Promise.all(promises).then(function (translatedFonts) {
+ for (var i = 0, ii = translatedFonts.length; i < ii; i++) {
+ var font = translatedFonts[i].dict;
+ delete font.translated;
+ }
+ this.fontCache.clear();
+ }.bind(this));
},
getPage: function Catalog_getPage(pageIndex) {
@@ -5936,7 +3655,7 @@ var Catalog = (function CatalogClosure() {
},
getPageDict: function Catalog_getPageDict(pageIndex) {
- var promise = new LegacyPromise();
+ var capability = createPromiseCapability();
var nodesToVisit = [this.catDict.getRaw('Pages')];
var currentPageIndex = 0;
var xref = this.xref;
@@ -5949,7 +3668,7 @@ var Catalog = (function CatalogClosure() {
xref.fetchAsync(currentNode).then(function (obj) {
if ((isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids')))) {
if (pageIndex === currentPageIndex) {
- promise.resolve([obj, currentNode]);
+ capability.resolve([obj, currentNode]);
} else {
currentPageIndex++;
next();
@@ -5958,7 +3677,7 @@ var Catalog = (function CatalogClosure() {
}
nodesToVisit.push(obj);
next();
- }.bind(this), promise.reject.bind(promise));
+ }, capability.reject);
return;
}
@@ -5993,10 +3712,10 @@ var Catalog = (function CatalogClosure() {
}
}
}
- promise.reject('Page index ' + pageIndex + ' not found.');
+ capability.reject('Page index ' + pageIndex + ' not found.');
}
next();
- return promise;
+ return capability.promise;
},
getPageIndex: function Catalog_getPageIndex(ref) {
@@ -6026,8 +3745,8 @@ var Catalog = (function CatalogClosure() {
var found = false;
for (var i = 0; i < kids.length; i++) {
var kid = kids[i];
- assert(isRef(kid), 'kids must be an ref');
- if (kid.num == kidRef.num) {
+ assert(isRef(kid), 'kids must be a ref');
+ if (kid.num === kidRef.num) {
found = true;
break;
}
@@ -6071,13 +3790,16 @@ var Catalog = (function CatalogClosure() {
var XRef = (function XRefClosure() {
function XRef(stream, password) {
-
this.stream = stream;
this.entries = [];
this.xrefstms = {};
// prepare the XRef cache
this.cache = [];
this.password = password;
+ this.stats = {
+ streamTypes: [],
+ fontTypes: []
+ };
}
XRef.prototype = {
@@ -6101,8 +3823,8 @@ var XRef = (function XRefClosure() {
if (encrypt) {
var ids = trailerDict.get('ID');
var fileId = (ids && ids.length) ? ids[0] : '';
- this.encrypt = new CipherTransformFactory(
- encrypt, fileId, this.password);
+ this.encrypt = new CipherTransformFactory(encrypt, fileId,
+ this.password);
}
// get the root dictionary (catalog) object
@@ -6126,9 +3848,9 @@ var XRef = (function XRefClosure() {
var obj = this.readXRefTable(parser);
// Sanity check
- if (!isCmd(obj, 'trailer'))
+ if (!isCmd(obj, 'trailer')) {
error('Invalid XRef table: could not find trailer dictionary');
-
+ }
// Read trailer dictionary, e.g.
// trailer
// << /Size 22
@@ -6139,9 +3861,14 @@ var XRef = (function XRefClosure() {
// The parser goes through the entire stream << ... >> and provides
// a getter interface for the key-value table
var dict = parser.getObj();
- if (!isDict(dict))
- error('Invalid XRef table: could not parse trailer dictionary');
+ // The pdflib PDF generator can generate a nested trailer dictionary
+ if (!isDict(dict) && dict.dict) {
+ dict = dict.dict;
+ }
+ if (!isDict(dict)) {
+ error('Invalid XRef table: could not parse trailer dictionary');
+ }
delete this.tableState;
return dict;
@@ -6178,9 +3905,9 @@ var XRef = (function XRefClosure() {
var first = tableState.firstEntryNum;
var count = tableState.entryCount;
- if (!isInt(first) || !isInt(count))
+ if (!isInt(first) || !isInt(count)) {
error('Invalid XRef table: wrong types in subsection header');
-
+ }
// Inner loop is over objects themselves
for (var i = tableState.entryNum; i < count; i++) {
tableState.streamPos = stream.pos;
@@ -6193,21 +3920,21 @@ var XRef = (function XRefClosure() {
entry.gen = parser.getObj();
var type = parser.getObj();
- if (isCmd(type, 'f'))
+ if (isCmd(type, 'f')) {
entry.free = true;
- else if (isCmd(type, 'n'))
+ } else if (isCmd(type, 'n')) {
entry.uncompressed = true;
+ }
// Validate entry obj
if (!isInt(entry.offset) || !isInt(entry.gen) ||
!(entry.free || entry.uncompressed)) {
- console.log(entry.offset, entry.gen, entry.free,
- entry.uncompressed);
error('Invalid entry in XRef subsection: ' + first + ', ' + count);
}
- if (!this.entries[i + first])
+ if (!this.entries[i + first]) {
this.entries[i + first] = entry;
+ }
}
tableState.entryNum = 0;
@@ -6225,9 +3952,9 @@ var XRef = (function XRefClosure() {
}
// Sanity check: as per spec, first object must be free
- if (this.entries[0] && !this.entries[0].free)
+ if (this.entries[0] && !this.entries[0].free) {
error('Invalid XRef table: unexpected first object');
-
+ }
return obj;
},
@@ -6267,13 +3994,12 @@ var XRef = (function XRefClosure() {
var entryRanges = streamState.entryRanges;
while (entryRanges.length > 0) {
-
var first = entryRanges[0];
var n = entryRanges[1];
- if (!isInt(first) || !isInt(n))
+ if (!isInt(first) || !isInt(n)) {
error('Invalid XRef range fields: ' + first + ', ' + n);
-
+ }
if (!isInt(typeFieldWidth) || !isInt(offsetFieldWidth) ||
!isInt(generationFieldWidth)) {
error('Invalid XRef entry fields length: ' + first + ', ' + n);
@@ -6283,15 +4009,19 @@ var XRef = (function XRefClosure() {
streamState.streamPos = stream.pos;
var type = 0, offset = 0, generation = 0;
- for (j = 0; j < typeFieldWidth; ++j)
+ for (j = 0; j < typeFieldWidth; ++j) {
type = (type << 8) | stream.getByte();
- // if type field is absent, its default value = 1
- if (typeFieldWidth === 0)
+ }
+ // if type field is absent, its default value is 1
+ if (typeFieldWidth === 0) {
type = 1;
- for (j = 0; j < offsetFieldWidth; ++j)
+ }
+ for (j = 0; j < offsetFieldWidth; ++j) {
offset = (offset << 8) | stream.getByte();
- for (j = 0; j < generationFieldWidth; ++j)
+ }
+ for (j = 0; j < generationFieldWidth; ++j) {
generation = (generation << 8) | stream.getByte();
+ }
var entry = {};
entry.offset = offset;
entry.gen = generation;
@@ -6307,8 +4037,9 @@ var XRef = (function XRefClosure() {
default:
error('Invalid XRef entry type: ' + type);
}
- if (!this.entries[first + i])
+ if (!this.entries[first + i]) {
this.entries[first + i] = entry;
+ }
}
streamState.entryNum = 0;
@@ -6316,14 +4047,16 @@ var XRef = (function XRefClosure() {
entryRanges.splice(0, 2);
}
},
+
indexObjects: function XRef_indexObjects() {
// Simple scan through the PDF content to find objects,
// trailers and XRef streams.
function readToken(data, offset) {
var token = '', ch = data[offset];
while (ch !== 13 && ch !== 10) {
- if (++offset >= data.length)
+ if (++offset >= data.length) {
break;
+ }
token += String.fromCharCode(ch);
ch = data[offset];
}
@@ -6335,11 +4068,12 @@ var XRef = (function XRefClosure() {
// finding byte sequence
while (offset < dataLength) {
var i = 0;
- while (i < length && data[offset + i] == what[i])
+ while (i < length && data[offset + i] === what[i]) {
++i;
- if (i >= length)
+ }
+ if (i >= length) {
break; // sequence found
-
+ }
offset++;
skipped++;
}
@@ -6356,8 +4090,6 @@ var XRef = (function XRefClosure() {
var buffer = stream.getBytes();
var position = stream.start, length = buffer.length;
var trailers = [], xrefStms = [];
- var state = 0;
- var currentToken;
while (position < length) {
var ch = buffer[position];
if (ch === 32 || ch === 9 || ch === 13 || ch === 10) {
@@ -6400,32 +4132,38 @@ var XRef = (function XRefClosure() {
}
position += contentLength;
- } else
+ } else {
position += token.length + 1;
+ }
}
// reading XRef streams
- for (var i = 0, ii = xrefStms.length; i < ii; ++i) {
+ var i, ii;
+ for (i = 0, ii = xrefStms.length; i < ii; ++i) {
this.startXRefQueue.push(xrefStms[i]);
this.readXRef(/* recoveryMode */ true);
}
// finding main trailer
var dict;
- for (var i = 0, ii = trailers.length; i < ii; ++i) {
+ for (i = 0, ii = trailers.length; i < ii; ++i) {
stream.pos = trailers[i];
- var parser = new Parser(new Lexer(stream), true, null);
+ var parser = new Parser(new Lexer(stream), true, this);
var obj = parser.getObj();
- if (!isCmd(obj, 'trailer'))
+ if (!isCmd(obj, 'trailer')) {
continue;
+ }
// read the trailer dictionary
- if (!isDict(dict = parser.getObj()))
+ if (!isDict(dict = parser.getObj())) {
continue;
+ }
// taking the first one with 'ID'
- if (dict.has('ID'))
+ if (dict.has('ID')) {
return dict;
+ }
}
// no tailer with 'ID', taking last one (if exists)
- if (dict)
+ if (dict) {
return dict;
+ }
// nothing helps
// calling error() would reject worker with an UnknownErrorException.
throw new InvalidPDFException('Invalid PDF structure');
@@ -6438,15 +4176,14 @@ var XRef = (function XRefClosure() {
while (this.startXRefQueue.length) {
var startXRef = this.startXRefQueue[0];
- stream.pos = startXRef;
+ stream.pos = startXRef + stream.start;
- var parser = new Parser(new Lexer(stream), true, null);
+ var parser = new Parser(new Lexer(stream), true, this);
var obj = parser.getObj();
var dict;
// Get dictionary
if (isCmd(obj, 'xref')) {
-
// Parse end-of-file XRef
dict = this.processXRefTable(parser);
if (!this.topDict) {
@@ -6465,7 +4202,6 @@ var XRef = (function XRefClosure() {
}
}
} else if (isInt(obj)) {
-
// Parse in-stream XRef
if (!isInt(parser.getObj()) ||
!isCmd(parser.getObj(), 'obj') ||
@@ -6476,9 +4212,9 @@ var XRef = (function XRefClosure() {
if (!this.topDict) {
this.topDict = dict;
}
-
- if (!dict)
+ if (!dict) {
error('Failed to read XRef stream');
+ }
} else {
error('Invalid XRef stream header');
}
@@ -6501,98 +4237,112 @@ var XRef = (function XRefClosure() {
if (e instanceof MissingDataException) {
throw e;
}
- log('(while reading XRef): ' + e);
+ info('(while reading XRef): ' + e);
}
- if (recoveryMode)
+ if (recoveryMode) {
return;
+ }
throw new XRefParseException();
},
getEntry: function XRef_getEntry(i) {
- var e = this.entries[i];
- if (e === null)
- return null;
- return e.free || !e.offset ? null : e; // returns null if entry is free
+ var xrefEntry = this.entries[i];
+ if (xrefEntry && !xrefEntry.free && xrefEntry.offset) {
+ return xrefEntry;
+ }
+ return null;
},
+
fetchIfRef: function XRef_fetchIfRef(obj) {
- if (!isRef(obj))
+ if (!isRef(obj)) {
return obj;
+ }
return this.fetch(obj);
},
+
fetch: function XRef_fetch(ref, suppressEncryption) {
- assertWellFormed(isRef(ref), 'ref object is not a reference');
+ assert(isRef(ref), 'ref object is not a reference');
var num = ref.num;
- var e;
if (num in this.cache) {
- e = this.cache[num];
- if (e instanceof Stream) {
- return e.makeSubStream(e.start, e.length, e.dict);
- }
- return e;
+ var cacheEntry = this.cache[num];
+ return cacheEntry;
}
- e = this.getEntry(num);
+ var xrefEntry = this.getEntry(num);
// the referenced entry can be free
- if (e === null)
- return (this.cache[num] = e);
-
- var gen = ref.gen;
- var stream, parser;
- if (e.uncompressed) {
- if (e.gen != gen)
- error('inconsistent generation in XRef');
- stream = this.stream.makeSubStream(e.offset);
- parser = new Parser(new Lexer(stream), true, this);
- var obj1 = parser.getObj();
- var obj2 = parser.getObj();
- var obj3 = parser.getObj();
- if (!isInt(obj1) || obj1 != num ||
- !isInt(obj2) || obj2 != gen ||
- !isCmd(obj3)) {
- error('bad XRef entry');
- }
- if (!isCmd(obj3, 'obj')) {
- // some bad pdfs use "obj1234" and really mean 1234
- if (obj3.cmd.indexOf('obj') === 0) {
- num = parseInt(obj3.cmd.substring(3), 10);
- if (!isNaN(num))
- return num;
- }
- error('bad XRef entry');
- }
- if (this.encrypt && !suppressEncryption) {
- try {
- e = parser.getObj(this.encrypt.createCipherTransform(num, gen));
- } catch (ex) {
- // almost all streams must be encrypted, but sometimes
- // they are not probably due to some broken generators
- // re-trying without encryption
- return this.fetch(ref, true);
- }
- } else {
- e = parser.getObj();
- }
- if (!isStream(e)) {
- this.cache[num] = e;
- }
- return e;
+ if (xrefEntry === null) {
+ return (this.cache[num] = null);
}
- // compressed entry
- var tableOffset = e.offset;
- stream = this.fetch(new Ref(tableOffset, 0));
- if (!isStream(stream))
+ if (xrefEntry.uncompressed) {
+ xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
+ } else {
+ xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
+ }
+ if (isDict(xrefEntry)){
+ xrefEntry.objId = ref.toString();
+ } else if (isStream(xrefEntry)) {
+ xrefEntry.dict.objId = ref.toString();
+ }
+ return xrefEntry;
+ },
+
+ fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,
+ suppressEncryption) {
+ var gen = ref.gen;
+ var num = ref.num;
+ if (xrefEntry.gen !== gen) {
+ error('inconsistent generation in XRef');
+ }
+ var stream = this.stream.makeSubStream(xrefEntry.offset +
+ this.stream.start);
+ var parser = new Parser(new Lexer(stream), true, this);
+ var obj1 = parser.getObj();
+ var obj2 = parser.getObj();
+ var obj3 = parser.getObj();
+ if (!isInt(obj1) || parseInt(obj1, 10) !== num ||
+ !isInt(obj2) || parseInt(obj2, 10) !== gen ||
+ !isCmd(obj3)) {
+ error('bad XRef entry');
+ }
+ if (!isCmd(obj3, 'obj')) {
+ // some bad PDFs use "obj1234" and really mean 1234
+ if (obj3.cmd.indexOf('obj') === 0) {
+ num = parseInt(obj3.cmd.substring(3), 10);
+ if (!isNaN(num)) {
+ return num;
+ }
+ }
+ error('bad XRef entry');
+ }
+ if (this.encrypt && !suppressEncryption) {
+ xrefEntry = parser.getObj(this.encrypt.createCipherTransform(num, gen));
+ } else {
+ xrefEntry = parser.getObj();
+ }
+ if (!isStream(xrefEntry)) {
+ this.cache[num] = xrefEntry;
+ }
+ return xrefEntry;
+ },
+
+ fetchCompressed: function XRef_fetchCompressed(xrefEntry,
+ suppressEncryption) {
+ var tableOffset = xrefEntry.offset;
+ var stream = this.fetch(new Ref(tableOffset, 0));
+ if (!isStream(stream)) {
error('bad ObjStm stream');
+ }
var first = stream.dict.get('First');
var n = stream.dict.get('N');
if (!isInt(first) || !isInt(n)) {
error('invalid first and n parameters for ObjStm stream');
}
- parser = new Parser(new Lexer(stream), false, this);
+ var parser = new Parser(new Lexer(stream), false, this);
parser.allowStreams = true;
- var i, entries = [], nums = [];
+ var i, entries = [], num, nums = [];
// read the object numbers to populate cache
for (i = 0; i < n; ++i) {
num = parser.getObj();
@@ -6614,36 +4364,38 @@ var XRef = (function XRefClosure() {
this.cache[num] = entries[i];
}
}
- e = entries[e.gen];
- if (e === undefined) {
+ xrefEntry = entries[xrefEntry.gen];
+ if (xrefEntry === undefined) {
error('bad XRef entry for compressed object');
}
- return e;
+ return xrefEntry;
},
+
fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
if (!isRef(obj)) {
- var promise = new LegacyPromise();
- promise.resolve(obj);
- return promise;
+ return Promise.resolve(obj);
}
return this.fetchAsync(obj);
},
+
fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
- var promise = new LegacyPromise();
- var tryFetch = function (promise) {
+ var streamManager = this.stream.manager;
+ var xref = this;
+ return new Promise(function tryFetch(resolve, reject) {
try {
- promise.resolve(this.fetch(ref, suppressEncryption));
+ resolve(xref.fetch(ref, suppressEncryption));
} catch (e) {
if (e instanceof MissingDataException) {
- this.stream.manager.requestRange(e.begin, e.end, tryFetch);
+ streamManager.requestRange(e.begin, e.end, function () {
+ tryFetch(resolve, reject);
+ });
return;
}
- promise.reject(e);
+ reject(e);
}
- }.bind(this, promise);
- tryFetch();
- return promise;
+ });
},
+
getCatalogObj: function XRef_getCatalogObj() {
return this.root;
}
@@ -6653,8 +4405,8 @@ var XRef = (function XRefClosure() {
})();
/**
- * A NameTree is like a Dict but has some adventagous properties, see the spec
- * (7.9.6) for more details.
+ * A NameTree is like a Dict but has some advantageous properties, see the
+ * spec (7.9.6) for more details.
* TODO: implement all the Dict functions and make this more efficent.
*/
var NameTree = (function NameTreeClosure() {
@@ -6684,8 +4436,9 @@ var NameTree = (function NameTreeClosure() {
var kids = obj.get('Kids');
for (i = 0, n = kids.length; i < n; i++) {
var kid = kids[i];
- if (processed.has(kid))
+ if (processed.has(kid)) {
error('invalid destinations');
+ }
queue.push(kid);
processed.put(kid);
}
@@ -6699,11 +4452,172 @@ var NameTree = (function NameTreeClosure() {
}
}
return dict;
+ },
+
+ get: function NameTree_get(destinationId) {
+ if (!this.root) {
+ return null;
+ }
+
+ var xref = this.xref;
+ var kidsOrNames = xref.fetchIfRef(this.root);
+ var loopCount = 0;
+ var MAX_NAMES_LEVELS = 10;
+ var l, r, m;
+
+ // Perform a binary search to quickly find the entry that
+ // contains the named destination we are looking for.
+ while (kidsOrNames.has('Kids')) {
+ loopCount++;
+ if (loopCount > MAX_NAMES_LEVELS) {
+ warn('Search depth limit for named destionations has been reached.');
+ return null;
+ }
+
+ var kids = kidsOrNames.get('Kids');
+ if (!isArray(kids)) {
+ return null;
+ }
+
+ l = 0;
+ r = kids.length - 1;
+ while (l <= r) {
+ m = (l + r) >> 1;
+ var kid = xref.fetchIfRef(kids[m]);
+ var limits = kid.get('Limits');
+
+ if (destinationId < limits[0]) {
+ r = m - 1;
+ } else if (destinationId > limits[1]) {
+ l = m + 1;
+ } else {
+ kidsOrNames = xref.fetchIfRef(kids[m]);
+ break;
+ }
+ }
+ if (l > r) {
+ return null;
+ }
+ }
+
+ // If we get here, then we have found the right entry. Now
+ // go through the named destinations in the Named dictionary
+ // until we find the exact destination we're looking for.
+ var names = kidsOrNames.get('Names');
+ if (isArray(names)) {
+ // Perform a binary search to reduce the lookup time.
+ l = 0;
+ r = names.length - 2;
+ while (l <= r) {
+ // Check only even indices (0, 2, 4, ...) because the
+ // odd indices contain the actual D array.
+ m = (l + r) & ~1;
+ if (destinationId < names[m]) {
+ r = m - 2;
+ } else if (destinationId > names[m]) {
+ l = m + 2;
+ } else {
+ return xref.fetchIfRef(names[m + 1]);
+ }
+ }
+ }
+ return null;
}
};
return NameTree;
})();
+/**
+ * "A PDF file can refer to the contents of another file by using a File
+ * Specification (PDF 1.1)", see the spec (7.11) for more details.
+ * NOTE: Only embedded files are supported (as part of the attachments support)
+ * TODO: support the 'URL' file system (with caching if !/V), portable
+ * collections attributes and related files (/RF)
+ */
+var FileSpec = (function FileSpecClosure() {
+ function FileSpec(root, xref) {
+ if (!root || !isDict(root)) {
+ return;
+ }
+ this.xref = xref;
+ this.root = root;
+ if (root.has('FS')) {
+ this.fs = root.get('FS');
+ }
+ this.description = root.has('Desc') ?
+ stringToPDFString(root.get('Desc')) :
+ '';
+ if (root.has('RF')) {
+ warn('Related file specifications are not supported');
+ }
+ this.contentAvailable = true;
+ if (!root.has('EF')) {
+ this.contentAvailable = false;
+ warn('Non-embedded file specifications are not supported');
+ }
+ }
+
+ function pickPlatformItem(dict) {
+ // Look for the filename in this order:
+ // UF, F, Unix, Mac, DOS
+ if (dict.has('UF')) {
+ return dict.get('UF');
+ } else if (dict.has('F')) {
+ return dict.get('F');
+ } else if (dict.has('Unix')) {
+ return dict.get('Unix');
+ } else if (dict.has('Mac')) {
+ return dict.get('Mac');
+ } else if (dict.has('DOS')) {
+ return dict.get('DOS');
+ } else {
+ return null;
+ }
+ }
+
+ FileSpec.prototype = {
+ get filename() {
+ if (!this._filename && this.root) {
+ var filename = pickPlatformItem(this.root) || 'unnamed';
+ this._filename = stringToPDFString(filename).
+ replace(/\\\\/g, '\\').
+ replace(/\\\//g, '/').
+ replace(/\\/g, '/');
+ }
+ return this._filename;
+ },
+ get content() {
+ if (!this.contentAvailable) {
+ return null;
+ }
+ if (!this.contentRef && this.root) {
+ this.contentRef = pickPlatformItem(this.root.get('EF'));
+ }
+ var content = null;
+ if (this.contentRef) {
+ var xref = this.xref;
+ var fileObj = xref.fetchIfRef(this.contentRef);
+ if (fileObj && isStream(fileObj)) {
+ content = fileObj.getBytes();
+ } else {
+ warn('Embedded file specification points to non-existing/invalid ' +
+ 'content');
+ }
+ } else {
+ warn('Embedded file specification does not have a content');
+ }
+ return content;
+ },
+ get serializable() {
+ return {
+ filename: this.filename,
+ content: this.content
+ };
+ }
+ };
+ return FileSpec;
+})();
+
/**
* A helper for loading missing data in object graphs. It traverses the graph
* depth first and queues up any objects that have missing data. Once it has
@@ -6716,12 +4630,12 @@ var NameTree = (function NameTreeClosure() {
* entire PDF document object graph to be traversed.
*/
var ObjectLoader = (function() {
-
function mayHaveChildren(value) {
return isRef(value) || isDict(value) || isArray(value) || isStream(value);
}
function addChildren(node, nodesToVisit) {
+ var value;
if (isDict(node) || isStream(node)) {
var map;
if (isDict(node)) {
@@ -6730,14 +4644,14 @@ var ObjectLoader = (function() {
map = node.dict.map;
}
for (var key in map) {
- var value = map[key];
+ value = map[key];
if (mayHaveChildren(value)) {
nodesToVisit.push(value);
}
}
} else if (isArray(node)) {
for (var i = 0, ii = node.length; i < ii; i++) {
- var value = node[i];
+ value = node[i];
if (mayHaveChildren(value)) {
nodesToVisit.push(value);
}
@@ -6753,15 +4667,14 @@ var ObjectLoader = (function() {
}
ObjectLoader.prototype = {
-
load: function ObjectLoader_load() {
var keys = this.keys;
- this.promise = new LegacyPromise();
+ this.capability = createPromiseCapability();
// Don't walk the graph if all the data is already loaded.
if (!(this.xref.stream instanceof ChunkedStream) ||
this.xref.stream.getMissingChunks().length === 0) {
- this.promise.resolve();
- return this.promise;
+ this.capability.resolve();
+ return this.capability.promise;
}
this.refSet = new RefSet();
@@ -6772,7 +4685,7 @@ var ObjectLoader = (function() {
}
this.walk(nodesToVisit);
- return this.promise;
+ return this.capability.promise;
},
walk: function ObjectLoader_walk(nodesToVisit) {
@@ -6839,17 +4752,14 @@ var ObjectLoader = (function() {
}
// Everything is loaded.
this.refSet = null;
- this.promise.resolve();
+ this.capability.resolve();
}
-
};
return ObjectLoader;
})();
-
-
var ISOAdobeCharset = [
'.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
@@ -6952,6935 +4862,2858 @@ var ExpertSubsetCharset = [
-var CIDToUnicodeMaps = {
- 'Adobe-Japan1': [[32, 160], {f: 12, c: 33}, [45, 8209], {f: 46, c: 46}, 165,
- {f: 2, c: 93}, [95, 818], [96, 768], {f: 27, c: 97}, 166, 125, [732, 771],
- [700, 8217], 92, [699, 8216], 124, [126, 8764], {f: 3, c: 161}, 8260, 402,
- 0, 164, 8220, 171, {f: 2, c: 8249}, {f: 2, c: 64257}, [8210, 8211], 0, 0,
- [183, 8729], 0, 8226, 8218, 8222, 8221, 187, 0, 0, 191, {f: 2, c: 769},
- [175, 772], {f: 3, c: 774}, 778, [184, 807], 779, 808, 780, [822, 8212],
- 198, 170, 321, 216, 338, 186, 230, 305, 322, 248, 339, 223, 173, 169, 172,
- 174, 0, 0, {f: 2, c: 178}, 181, 185, {f: 3, c: 188}, {f: 6, c: 192},
- {f: 16, c: 199}, 0, {f: 6, c: 217}, {f: 6, c: 224}, {f: 16, c: 231}, 0,
- {f: 7, c: 249}, 352, 376, 381, [773, 8254], 353, 8482, 382, 0, 8194,
- {f: 59, c: 33}, 165, {f: 31, c: 93}, 65512, {f: 2, c: 125}, 0,
- {f: 63, c: 65377}, {s: 243}, [8195, 12288],
- {f: 2, c: 12289}, 65292, 65294, 12539, {f: 2, c: 65306}, 65311, 65281,
- {f: 2, c: 12443}, 180, 65344, 168, 65342, 65507, 65343, {f: 2, c: 12541},
- {f: 2, c: 12445}, 12291, 20189, {f: 3, c: 12293}, 12540, 8213, 8208, 65295,
- 65340, [12316, 65374], 8214, 65372, 8230, 8229, {s: 4}, {f: 2, c: 65288},
- {f: 2, c: 12308}, 65339, 65341, 65371, 65373, {f: 10, c: 12296}, 65291,
- [8722, 65293], 177, 215, 247, 65309, 8800, 65308, 65310, {f: 2, c: 8806},
- 8734, 8756, 9794, 9792, 176, {f: 2, c: 8242}, 8451, 65509, 65284,
- {f: 2, c: 65504}, 65285, 65283, 65286, 65290, 65312, 167, 9734, 9733, 9675,
- 9679, 9678, 9671, 9670, 9633, 9632, 9651, 9650, 9661, 9660, 8251, 12306,
- 8594, {f: 2, c: 8592}, 8595, 12307, 8712, 8715, {f: 2, c: 8838},
- {f: 2, c: 8834}, 8746, 8745, {f: 2, c: 8743}, 65506, 8658, 8660, 8704,
- 8707, 8736, 8869, 8978, 8706, 8711, 8801, 8786, {f: 2, c: 8810}, 8730,
- 8765, 8733, 8757, {f: 2, c: 8747}, 8491, 8240, 9839, 9837, 9834,
- {f: 2, c: 8224}, 182, 9711, {f: 10, c: 65296}, {f: 26, c: 65313},
- {f: 26, c: 65345}, {f: 83, c: 12353}, {f: 86, c: 12449}, {f: 17, c: 913},
- {f: 7, c: 931}, {f: 17, c: 945}, {f: 7, c: 963}, {f: 6, c: 1040}, 1025,
- {f: 32, c: 1046}, 1105, {f: 26, c: 1078}, 20124, 21782, 23043, 38463,
- 21696, 24859, 25384, 23030, 36898, 33909, 33564, 31312, 24746, 25569,
- 28197, 26093, 33894, 33446, 39925, 26771, 22311, 26017, 25201, 23451,
- 22992, 34427, 39156, 32098, 32190, 39822, 25110, 31903, 34999, 23433,
- 24245, 25353, 26263, 26696, 38343, 38797, 26447, 20197, 20234, 20301,
- 20381, 20553, 22258, 22839, 22996, 23041, 23561, 24799, 24847, 24944,
- 26131, 26885, 28858, 30031, 30064, 31227, 32173, 32239, 32963, 33806,
- [12176, 34915], 35586, 36949, 36986, 21307, 20117, 20133, 22495, 32946,
- 37057, 30959, [12032, 19968], 22769, 28322, 36920, 31282, 33576, 33419,
- 39983, 20801, 21360, 21693, 21729, 22240, 23035, 24341, 39154, 28139,
- 32996, 34093, 38498, 38512, 38560, 38907, 21515, 21491, 23431, 28879,
- [12155, 32701], 36802, [12204, 38632], 21359, 40284, 31418, 19985, 30867,
- [12165, 33276], 28198, 22040, 21764, 27421, 34074, 39995, 23013, 21417,
- 28006, [12128, 29916], 38287, 22082, 20113, 36939, 38642, 33615, 39180,
- 21473, 21942, 23344, 24433, 26144, 26355, 26628, 27704, 27891, 27945,
- 29787, 30408, 31310, 38964, 33521, 34907, 35424, 37613, 28082, 30123,
- 30410, 39365, 24742, 35585, 36234, 38322, 27022, 21421, 20870, 22290,
- 22576, 22852, 23476, 24310, 24616, 25513, 25588, 27839, 28436, 28814,
- 28948, 29017, 29141, 29503, 32257, 33398, 33489, 34199, 36960, 37467,
- 40219, 22633, 26044, 27738, 29989, 20985, 22830, 22885, 24448, 24540,
- 25276, 26106, 27178, 27431, 27572, 29579, 32705, 35158, 40236, 40206,
- [12009, 40644], 23713, 27798, 33659, 20740, 23627, 25014, 33222, 26742,
- 29281, [12036, 20057], 20474, 21368, 24681, 28201, 31311, [12211, 38899],
- 19979, 21270, 20206, 20309, 20285, 20385, 20339, 21152, 21487, 22025,
- 22799, 23233, 23478, 23521, 31185, 26247, 26524, 26550, 27468, 27827,
- [12117, 28779], 29634, 31117, [12146, 31166], 31292, 31623, 33457, 33499,
- 33540, 33655, 33775, 33747, 34662, 35506, 22057, 36008, 36838, 36942,
- 38686, 34442, 20420, 23784, 25105, [12123, 29273], 30011, 33253, 33469,
- 34558, 36032, 38597, 39187, 39381, 20171, 20250, 35299, 22238, 22602,
- 22730, 24315, 24555, 24618, 24724, 24674, 25040, 25106, 25296, 25913,
- 39745, 26214, 26800, 28023, 28784, 30028, 30342, 32117, 33445, 34809,
- 38283, 38542, [12185, 35997], 20977, 21182, 22806, 21683, 23475, 23830,
- 24936, 27010, 28079, 30861, 33995, 34903, 35442, 37799, 39608, 28012,
- 39336, 34521, 22435, 26623, 34510, 37390, 21123, 22151, 21508, 24275,
- 25313, 25785, 26684, 26680, 27579, 29554, 30906, 31339, 35226,
- [12179, 35282], 36203, 36611, 37101, 38307, 38548, [12208, 38761], 23398,
- 23731, 27005, {f: 2, c: 38989}, 25499, 31520, 27179, 27263, 26806, 39949,
- 28511, 21106, 21917, 24688, 25324, 27963, 28167, 28369, 33883, 35088,
- 36676, 19988, 39993, 21494, 26907, 27194, 38788, 26666, 20828, 31427,
- 33970, 37340, 37772, 22107, 40232, 26658, 33541, 33841, 31909, 21000,
- 33477, [12129, 29926], 20094, 20355, 20896, 23506, 21002, 21208, 21223,
- 24059, 21914, 22570, 23014, 23436, 23448, 23515, [12082, 24178], 24185,
- 24739, 24863, 24931, 25022, 25563, 25954, 26577, 26707, 26874, 27454,
- 27475, 27735, 28450, 28567, 28485, 29872, [12130, 29976], 30435, 30475,
- 31487, 31649, 31777, 32233, [12152, 32566], 32752, 32925, 33382, 33694,
- 35251, 35532, 36011, 36996, 37969, 38291, 38289, 38306, 38501, 38867,
- 39208, 33304, 20024, 21547, 23736, 24012, 29609, 30284, 30524, 23721,
- 32747, 36107, 38593, 38929, 38996, 39000, 20225, 20238, 21361, 21916,
- 22120, 22522, 22855, 23305, 23492, 23696, 24076, 24190, 24524, 25582,
- 26426, 26071, 26082, 26399, 26827, 26820, 27231, 24112, 27589, 27671,
- 27773, 30079, 31048, 23395, 31232, 32000, 24509, 35215, 35352, 36020,
- 36215, 36556, 36637, 39138, 39438, [12004, 12225, 39740], [12018, 20096],
- 20605, 20736, 22931, 23452, 25135, 25216, 25836, 27450, 29344, 30097,
- 31047, 32681, 34811, 35516, 35696, 25516, 33738, 38816, 21513, 21507,
- 21931, 26708, 27224, 35440, 30759, 26485, [12233, 40653], 21364, 23458,
- 33050, 34384, 36870, 19992, 20037, 20167, 20241, 21450, 21560, 23470,
- [12088, 24339], 24613, 25937, 26429, 27714, 27762, 27875, 28792, 29699,
- 31350, 31406, 31496, 32026, 31998, 32102, 26087, [12124, 29275], 21435,
- 23621, 24040, 25298, 25312, 25369, 28192, 34394, 35377, 36317, 37624,
- 28417, 31142, [12226, 39770], 20136, {f: 2, c: 20139}, 20379, 20384, 20689,
- 20807, 31478, 20849, 20982, 21332, 21281, 21375, 21483, 21932, 22659,
- 23777, 24375, 24394, 24623, 24656, 24685, 25375, 25945, 27211, 27841,
- 29378, 29421, 30703, 33016, 33029, 33288, 34126, 37111, 37857, 38911,
- 39255, 39514, 20208, 20957, 23597, 26241, 26989, 23616, 26354, 26997,
- [12127, 29577], 26704, 31873, 20677, 21220, 22343, [12081, 24062], 37670,
- [12100, 26020], 27427, 27453, 29748, 31105, 31165, 31563, 32202, 33465,
- 33740, 34943, 35167, 35641, 36817, [12198, 37329], 21535, 37504, 20061,
- 20534, 21477, 21306, 29399, 29590, 30697, 33510, 36527, 39366, 39368,
- 39378, 20855, 24858, 34398, 21936, 31354, 20598, 23507, 36935, 38533,
- 20018, 27355, 37351, 23633, 23624, 25496, 31391, 27795, 38772, 36705,
- 31402, 29066, 38536, 31874, 26647, 32368, 26705, 37740, 21234, 21531,
- 34219, 35347, 32676, 36557, 37089, 21350, 34952, 31041, 20418, 20670,
- 21009, 20804, 21843, 22317, 29674, 22411, 22865, 24418, 24452, 24693,
- 24950, 24935, 25001, 25522, 25658, 25964, 26223, 26690, 28179, 30054,
- 31293, 31995, 32076, 32153, 32331, 32619, 33550, 33610, 34509, 35336,
- 35427, 35686, 36605, 38938, 40335, 33464, 36814, 39912, 21127, 25119,
- 25731, 28608, 38553, 26689, 20625, [12107, 27424], 27770, 28500,
- [12147, 31348], 32080, [12174, 34880], 35363, [12105, 26376], 20214, 20537,
- 20518, 20581, 20860, 21048, 21091, 21927, 22287, 22533, 23244, 24314,
- 25010, 25080, 25331, 25458, 26908, 27177, 29309, [12125, 29356], 29486,
- 30740, 30831, 32121, 30476, 32937, [12178, 35211], 35609, 36066, 36562,
- 36963, 37749, 38522, 38997, 39443, 40568, 20803, 21407, 21427, 24187,
- 24358, 28187, 28304, [12126, 29572], 29694, 32067, 33335, [12180, 35328],
- 35578, 38480, 20046, 20491, 21476, 21628, 22266, 22993, 23396,
- [12080, 24049], 24235, 24359, [12094, 25144], 25925, 26543, 28246, 29392,
- 31946, 34996, 32929, 32993, 33776, [11969, 34382], 35463, 36328, 37431,
- 38599, 39015, [12238, 40723], 20116, 20114, 20237, 21320, 21577, 21566,
- 23087, 24460, 24481, 24735, 26791, 27278, 29786, 30849, 35486, 35492,
- 35703, 37264, 20062, 39881, 20132, 20348, 20399, 20505, 20502, 20809,
- 20844, 21151, 21177, 21246, 21402, [12061, 21475], 21521, 21518, 21897,
- 22353, 22434, 22909, 23380, 23389, 23439, [12079, 24037], 24039, 24055,
- 24184, 24195, 24218, 24247, 24344, 24658, 24908, 25239, 25304, 25511,
- 25915, 26114, 26179, 26356, 26477, 26657, 26775, 27083, 27743, 27946,
- 28009, 28207, 28317, 30002, 30343, 30828, 31295, 31968, 32005, 32024,
- 32094, 32177, 32789, 32771, 32943, 32945, 33108, 33167, 33322, 33618,
- [12175, 34892], 34913, 35611, 36002, 36092, 37066, 37237, 37489, 30783,
- 37628, 38308, 38477, 38917, [12217, 39321], [12220, 39640], 40251, 21083,
- 21163, 21495, 21512, 22741, 25335, 28640, 35946, 36703, 40633, 20811,
- 21051, 21578, 22269, 31296, 37239, 40288, [12234, 40658], 29508, 28425,
- 33136, 29969, 24573, 24794, [12219, 39592], 29403, 36796, 27492, 38915,
- 20170, 22256, 22372, 22718, 23130, 24680, 25031, 26127, 26118, 26681,
- 26801, 28151, 30165, 32058, [12169, 33390], 39746, 20123, 20304, 21449,
- 21766, 23919, 24038, 24046, 26619, 27801, 29811, 30722, 35408, 37782,
- 35039, 22352, 24231, 25387, 20661, 20652, 20877, 26368, 21705, 22622,
- 22971, 23472, 24425, 25165, 25505, 26685, 27507, 28168, 28797, 37319,
- 29312, 30741, 30758, 31085, 25998, 32048, 33756, 35009, 36617, 38555,
- 21092, 22312, 26448, 32618, 36001, 20916, 22338, 38442, 22586, 27018,
- 32948, 21682, 23822, 22524, 30869, 40442, 20316, 21066, 21643, 25662,
- 26152, 26388, 26613, 31364, 31574, 32034, 37679, 26716, 39853, 31545,
- 21273, 20874, 21047, 23519, 25334, 25774, 25830, 26413, 27578, 34217,
- 38609, 30352, 39894, 25420, 37638, 39851, [12139, 30399], 26194, 19977,
- 20632, 21442, [12077, 23665], 24808, 25746, 25955, 26719, 29158, 29642,
- 29987, 31639, 32386, 34453, 35715, 36059, 37240, 39184, 26028, 26283,
- 27531, 20181, 20180, 20282, 20351, 21050, 21496, 21490, 21987, 22235,
- [12064, 22763], 22987, 22985, 23039, [12070, 23376], 23629, 24066, 24107,
- 24535, 24605, 25351, [12096, 25903], 23388, 26031, 26045, 26088, 26525,
- [12108, 27490], 27515, [12114, 27663], 29509, 31049, 31169, [12151, 31992],
- 32025, 32043, 32930, 33026, [12164, 33267], 35222, 35422, 35433, 35430,
- 35468, 35566, 36039, 36060, 38604, 39164, [12013, 27503], 20107, 20284,
- 20365, 20816, 23383, 23546, 24904, 25345, 26178, 27425, 28363, 27835,
- 29246, 29885, 30164, 30913, [12144, 31034], [12157, 32780], [12159, 32819],
- [12163, 33258], 33940, 36766, 27728, [12229, 40575], 24335, 35672, 40235,
- 31482, 36600, 23437, 38635, 19971, 21489, 22519, 22833, 23241, 23460,
- 24713, 28287, 28422, 30142, 36074, 23455, 34048, 31712, 20594, 26612,
- 33437, 23649, 34122, 32286, 33294, 20889, 23556, 25448, 36198, 26012,
- 29038, 31038, 32023, 32773, 35613, [12190, 36554], 36974, 34503, 37034,
- 20511, 21242, 23610, 26451, 28796, 29237, 37196, 37320, 37675, 33509,
- 23490, 24369, 24825, 20027, 21462, 23432, [12095, 25163], 26417, 27530,
- 29417, 29664, 31278, 33131, 36259, 37202, [12216, 39318], 20754, 21463,
- 21610, 23551, 25480, 27193, 32172, 38656, 22234, 21454, 21608, 23447,
- 23601, 24030, 20462, 24833, 25342, 27954, 31168, 31179, 32066, 32333,
- 32722, 33261, [12168, 33311], 33936, 34886, 35186, 35728, 36468, 36655,
- 36913, 37195, 37228, 38598, 37276, 20160, 20303, 20805, [12055, 21313],
- 24467, 25102, 26580, 27713, 28171, 29539, 32294, 37325, 37507, 21460,
- 22809, 23487, 28113, 31069, 32302, 31899, 22654, 29087, 20986, 34899,
- 36848, 20426, 23803, 26149, 30636, 31459, 33308, 39423, 20934, 24490,
- 26092, 26991, 27529, 28147, 28310, 28516, 30462, 32020, 24033, 36981,
- 37255, 38918, 20966, 21021, 25152, 26257, 26329, 28186, 24246, 32210,
- 32626, 26360, 34223, 34295, 35576, 21161, 21465, [12069, 22899], 24207,
- 24464, 24661, 37604, 38500, 20663, 20767, 21213, 21280, 21319, 21484,
- 21736, 21830, 21809, 22039, 22888, 22974, 23100, 23477, 23558,
- [12073, 23567], 23569, 23578, 24196, 24202, 24288, 24432, 25215, 25220,
- 25307, 25484, 25463, 26119, 26124, 26157, 26230, 26494, 26786, 27167,
- 27189, 27836, 28040, 28169, 28248, 28988, 28966, 29031, 30151, 30465,
- 30813, 30977, 31077, 31216, 31456, 31505, 31911, 32057, 32918, 33750,
- 33931, 34121, 34909, 35059, 35359, 35388, 35412, 35443, 35937, 36062,
- 37284, 37478, 37758, 37912, 38556, 38808, 19978, 19976, 19998, 20055,
- 20887, 21104, 22478, 22580, 22732, 23330, 24120, 24773, 25854, 26465,
- 26454, 27972, 29366, 30067, 31331, 33976, 35698, 37304, 37664, 22065,
- 22516, 39166, 25325, 26893, 27542, 29165, 32340, 32887, [12170, 33394],
- 35302, [12215, 39135], 34645, 36785, 23611, 20280, 20449, 20405, 21767,
- 23072, 23517, 23529, [12092, 24515], 24910, 25391, 26032, 26187, 26862,
- 27035, 28024, 28145, 30003, 30137, 30495, 31070, 31206, 32051,
- [12162, 33251], 33455, 34218, 35242, 35386, [12189, 36523], [12191, 36763],
- 36914, 37341, 38663, [12040, 20154], 20161, 20995, 22645, 22764, 23563,
- 29978, 23613, 33102, 35338, 36805, 38499, 38765, 31525, 35535, 38920,
- 37218, 22259, 21416, 36887, 21561, 22402, 24101, 25512, [12116, 27700],
- 28810, 30561, 31883, 32736, 34928, 36930, 37204, 37648, 37656, 38543,
- 29790, 39620, 23815, 23913, 25968, 26530, 36264, 38619, 25454, 26441,
- 26905, 33733, 38935, 38592, 35070, 28548, 25722, [12072, 23544], 19990,
- 28716, 30045, 26159, 20932, 21046, 21218, 22995, 24449, 24615, 25104,
- 25919, 25972, 26143, 26228, 26866, 26646, 27491, 28165, 29298,
- [12131, 29983], 30427, 31934, 32854, 22768, 35069, [11972, 35199], 35488,
- 35475, 35531, 36893, 37266, [11992, 38738], 38745, [12011, 25993], 31246,
- 33030, 38587, 24109, 24796, 25114, 26021, 26132, 26512, [12143, 30707],
- 31309, 31821, 32318, 33034, 36012, [12186, 36196], 36321, 36447, 30889,
- 20999, 25305, 25509, 25666, 25240, 35373, 31363, 31680, 35500, 38634,
- 32118, [12166, 33292], 34633, 20185, 20808, 21315, 21344, 23459, 23554,
- 23574, 24029, 25126, 25159, 25776, 26643, 26676, 27849, 27973, 27927,
- 26579, 28508, 29006, 29053, 26059, 31359, 31661, 32218, 32330, 32680,
- 33146, [12167, 33307], 33337, 34214, 35438, 36046, 36341, 36984, 36983,
- 37549, 37521, 38275, 39854, 21069, 21892, 28472, 28982, 20840, 31109,
- 32341, 33203, 31950, 22092, 22609, 23720, 25514, 26366, 26365, 26970,
- 29401, 30095, 30094, 30990, 31062, 31199, 31895, 32032, 32068, 34311,
- 35380, 38459, 36961, [12239, 40736], 20711, 21109, 21452, 21474, 20489,
- 21930, 22766, 22863, 29245, 23435, 23652, 21277, 24803, 24819, 25436,
- 25475, 25407, 25531, 25805, 26089, 26361, 24035, 27085, 27133, 28437,
- 29157, 20105, 30185, 30456, 31379, 31967, 32207, 32156, 32865, 33609,
- 33624, 33900, 33980, 34299, 35013, [12187, 36208], 36865, 36973, 37783,
- 38684, 39442, 20687, 22679, 24974, 33235, 34101, 36104, 36896, 20419,
- 20596, 21063, 21363, 24687, 25417, 26463, 28204, [12188, 36275], 36895,
- 20439, 23646, 36042, 26063, 32154, 21330, 34966, 20854, 25539, 23384,
- 23403, 23562, 25613, 26449, 36956, 20182, 22810, 22826, 27760, 35409,
- 21822, 22549, 22949, 24816, 25171, 26561, 33333, 26965, 38464, 39364,
- 39464, 20307, 22534, 23550, 32784, 23729, 24111, 24453, 24608, 24907,
- 25140, 26367, 27888, 28382, 32974, 33151, 33492, 34955, 36024, 36864,
- 36910, 38538, 40667, 39899, 20195, 21488, [12068, 22823], 31532, 37261,
- 38988, 40441, 28381, 28711, 21331, 21828, 23429, 25176, 25246, 25299,
- 27810, 28655, 29730, 35351, 37944, 28609, 35582, 33592, 20967, 34552,
- 21482, 21481, 20294, 36948, [12192, 36784], 22890, 33073, 24061, 31466,
- 36799, 26842, [12181, 35895], 29432, 40008, 27197, 35504, 20025, 21336,
- 22022, 22374, 25285, 25506, 26086, 27470, 28129, 28251, 28845, 30701,
- 31471, 31658, 32187, 32829, 32966, 34507, 35477, 37723, 22243, 22727,
- 24382, 26029, 26262, 27264, 27573, 30007, 35527, 20516, 30693, 22320,
- 24347, 24677, 26234, 27744, 30196, 31258, 32622, 33268, 34584, 36933,
- 39347, 31689, 30044, [12149, 31481], 31569, 33988, 36880, 31209, 31378,
- 33590, 23265, 30528, 20013, 20210, 23449, 24544, 25277, 26172, 26609,
- 27880, [12173, 34411], 34935, 35387, 37198, 37619, 39376, 27159, 28710,
- 29482, 33511, 33879, 36015, 19969, 20806, 20939, 21899, 23541, 24086,
- 24115, 24193, 24340, 24373, 24427, 24500, 25074, 25361, 26274, 26397,
- 28526, 29266, 30010, 30522, 32884, 33081, 33144, 34678, 35519, 35548,
- 36229, 36339, 37530, [11985, 12199, 38263], 38914, [12227, 40165], 21189,
- 25431, 30452, 26389, 27784, 29645, 36035, 37806, 38515, 27941, 22684,
- 26894, 27084, 36861, 37786, 30171, 36890, 22618, 26626, 25524, 27131,
- 20291, 28460, 26584, 36795, 34086, 32180, 37716, 26943, 28528, 22378,
- 22775, 23340, 32044, [12118, 29226], 21514, 37347, 40372, 20141, 20302,
- 20572, 20597, 21059, 35998, 21576, 22564, 23450, 24093, 24213, 24237,
- 24311, 24351, 24716, 25269, 25402, 25552, 26799, 27712, 30855, 31118,
- 31243, 32224, 33351, 35330, 35558, 36420, 36883, 37048, 37165, 37336,
- [12237, 40718], 27877, 25688, 25826, 25973, 28404, 30340, 31515, 36969,
- 37841, 28346, 21746, 24505, 25764, 36685, 36845, 37444, 20856, 22635,
- 22825, 23637, 24215, 28155, 32399, 29980, 36028, 36578, 39003, 28857,
- 20253, 27583, 28593, [12133, 30000], 38651, 20814, 21520, 22581, 22615,
- 22956, 23648, 24466, [12099, 26007], 26460, 28193, 30331, 33759, 36077,
- 36884, 37117, 37709, 30757, 30778, 21162, 24230, [12063, 22303], 22900,
- 24594, 20498, 20826, 20908, 20941, [12049, 20992], 21776, 22612, 22616,
- 22871, 23445, 23798, 23947, 24764, 25237, 25645, 26481, 26691, 26812,
- 26847, 30423, 28120, 28271, 28059, 28783, 29128, 24403, 30168, 31095,
- 31561, 31572, 31570, 31958, 32113, 21040, 33891, 34153, 34276, 35342,
- 35588, [12182, 35910], 36367, 36867, 36879, 37913, 38518, 38957, 39472,
- 38360, 20685, 21205, 21516, 22530, 23566, 24999, 25758, 27934, 30643,
- 31461, 33012, 33796, 36947, 37509, 23776, 40199, 21311, 24471, 24499,
- 28060, 29305, 30563, 31167, 31716, 27602, 29420, 35501, 26627, 27233,
- 20984, 31361, 26932, 23626, 40182, 33515, 23493, [12195, 37193], 28702,
- 22136, 23663, 24775, 25958, 27788, 35930, 36929, 38931, 21585, 26311,
- 37389, 22856, 37027, 20869, 20045, 20970, 34201, 35598, 28760, 25466,
- 37707, 26978, 39348, 32260, 30071, 21335, 26976, 36575, 38627, 27741,
- [12038, 20108], 23612, 24336, 36841, 21250, 36049, [12161, 32905], 34425,
- 24319, [12103, 26085], 20083, [12042, 20837], 22914, 23615, 38894, 20219,
- 22922, 24525, 35469, 28641, 31152, 31074, 23527, 33905, 29483, 29105,
- 24180, 24565, 25467, 25754, 29123, 31896, 20035, 24316, 20043, 22492,
- 22178, 24745, 28611, 32013, 33021, 33075, 33215, 36786, 35223, 34468,
- 24052, 25226, 25773, 35207, 26487, 27874, 27966, 29750, 30772, 23110,
- 32629, 33453, [12218, 39340], 20467, 24259, 25309, 25490, 25943, 26479,
- 30403, 29260, 32972, 32954, 36649, 37197, 20493, 22521, 23186, 26757,
- 26995, 29028, 29437, 36023, 22770, 36064, 38506, 36889, 34687, 31204,
- 30695, 33833, 20271, 21093, 21338, 25293, 26575, 27850, [12137, 30333],
- 31636, 31893, 33334, 34180, 36843, 26333, 28448, 29190, 32283, 33707,
- 39361, [12008, 40614], 20989, 31665, 30834, 31672, 32903, 31560, 27368,
- 24161, 32908, 30033, 30048, [12043, 20843], 37474, 28300, 30330, 37271,
- 39658, 20240, 32624, 25244, 31567, 38309, 40169, 22138, 22617, 34532,
- 38588, 20276, 21028, 21322, 21453, 21467, 24070, 25644, 26001, 26495,
- 27710, 27726, 29256, 29359, 29677, 30036, 32321, 33324, 34281, 36009,
- 31684, [12196, 37318], 29033, 38930, 39151, 25405, 26217, 30058, 30436,
- 30928, 34115, 34542, 21290, 21329, 21542, 22915, 24199, 24444, 24754,
- 25161, 25209, 25259, 26000, [12112, 27604], 27852, 30130, [12138, 30382],
- 30865, 31192, 32203, 32631, 32933, 34987, 35513, 36027, 36991,
- [12206, 38750], [12214, 39131], 27147, 31800, 20633, 23614, 24494, 26503,
- 27608, 29749, 30473, 32654, [12240, 40763], 26570, 31255, 21305,
- [12134, 30091], 39661, 24422, 33181, 33777, 32920, 24380, 24517, 30050,
- 31558, 36924, 26727, 23019, 23195, 32016, 30334, 35628, 20469, 24426,
- 27161, 27703, 28418, 29922, 31080, 34920, 35413, 35961, 24287, 25551,
- 30149, 31186, 33495, 37672, 37618, 33948, 34541, 39981, 21697, 24428,
- 25996, 27996, 28693, 36007, 36051, 38971, 25935, 29942, 19981, 20184,
- 22496, 22827, 23142, 23500, 20904, 24067, 24220, 24598, 25206, 25975,
- 26023, 26222, 28014, [12119, 29238], 31526, 33104, 33178, 33433, 35676,
- 36000, 36070, 36212, [12201, 38428], 38468, 20398, 25771, 27494, 33310,
- 33889, 34154, 37096, 23553, 26963, [12213, 39080], 33914, 34135, 20239,
- 21103, 24489, 24133, 26381, 31119, 33145, 35079, 35206, 28149, 24343,
- 25173, 27832, 20175, 29289, 39826, 20998, 21563, 22132, 22707, 24996,
- 25198, 28954, 22894, 31881, 31966, 32027, 38640, [12098, 25991], 32862,
- 19993, 20341, 20853, 22592, 24163, 24179, 24330, 26564, 20006, 34109,
- 38281, 38491, [12150, 31859], [12212, 38913], 20731, 22721, 30294, 30887,
- 21029, 30629, 34065, 31622, 20559, 22793, [12122, 29255], 31687, 32232,
- 36794, 36820, 36941, 20415, 21193, 23081, 24321, 38829, 20445, 33303,
- 37610, 22275, 25429, 27497, 29995, 35036, 36628, 31298, 21215, 22675,
- 24917, 25098, 26286, [11935, 27597], 31807, 33769, 20515, 20472, 21253,
- 21574, 22577, 22857, 23453, 23792, 23791, 23849, 24214, 25265, 25447,
- 25918, [12101, 26041], 26379, 27861, 27873, 28921, 30770, 32299, 32990,
- 33459, 33804, 34028, 34562, 35090, 35370, 35914, 37030, 37586, 39165,
- 40179, 40300, 20047, 20129, 20621, 21078, 22346, 22952, 24125,
- {f: 2, c: 24536}, 25151, 26292, 26395, 26576, 26834, 20882, 32033, 32938,
- 33192, 35584, 35980, 36031, 37502, 38450, 21536, 38956, 21271, 20693,
- [12056, 21340], 22696, 25778, 26420, 29287, 30566, 31302, 37350, 21187,
- 27809, 27526, 22528, 24140, 22868, 26412, 32763, 20961, 30406, 25705,
- 30952, 39764, [12231, 40635], 22475, 22969, 26151, 26522, 27598, 21737,
- 27097, 24149, 33180, 26517, 39850, 26622, 40018, 26717, 20134, 20451,
- [12060, 21448], 25273, 26411, 27819, 36804, 20397, 32365, 40639, 19975,
- 24930, 28288, 28459, 34067, 21619, 26410, 39749, [11922, 24051], 31637,
- 23724, 23494, 34588, 28234, 34001, 31252, 33032, 22937, 31885,
- [11936, 27665], 30496, 21209, 22818, 28961, 29279, [12141, 30683], 38695,
- 40289, 26891, 23167, 23064, 20901, 21517, 21629, 26126, 30431, 36855,
- 37528, 40180, 23018, 29277, 28357, 20813, 26825, 32191, 32236,
- [12207, 38754], 40634, 25720, 27169, 33538, 22916, 23391, [12113, 27611],
- 29467, 30450, 32178, 32791, 33945, 20786, [12106, 26408], 40665,
- [12140, 30446], 26466, 21247, 39173, 23588, 25147, 31870, 36016, 21839,
- 24758, 32011, [12200, 38272], 21249, 20063, 20918, 22812, 29242, 32822,
- 37326, 24357, [12142, 30690], 21380, 24441, 32004, 34220, 35379, 36493,
- 38742, 26611, 34222, 37971, 24841, 24840, 27833, 30290, 35565, 36664,
- 21807, 20305, 20778, 21191, 21451, 23461, 24189, 24736, 24962, 25558,
- 26377, 26586, 28263, 28044, {f: 2, c: 29494}, 30001, 31056, 35029, 35480,
- 36938, [12194, 37009], 37109, 38596, 34701, [12067, 22805], 20104, 20313,
- 19982, 35465, 36671, 38928, 20653, 24188, 22934, 23481, 24248, 25562,
- 25594, 25793, 26332, 26954, 27096, 27915, 28342, 29076, [12132, 29992],
- 31407, [12154, 32650], 32768, 33865, 33993, 35201, 35617, 36362, 36965,
- 38525, 39178, 24958, 25233, 27442, 27779, 28020, 32716, 32764, 28096,
- 32645, 34746, 35064, 26469, 33713, 38972, 38647, 27931, 32097, 33853,
- 37226, 20081, 21365, 23888, 27396, 28651, 34253, 34349, 35239, 21033,
- 21519, 23653, 26446, 26792, 29702, 29827, 30178, 35023, 35041,
- [12197, 37324], 38626, 38520, 24459, 29575, [12148, 31435], 33870, 25504,
- 30053, 21129, 27969, 28316, 29705, 30041, 30827, 31890, 38534,
- [12015, 31452], [12243, 40845], 20406, 24942, 26053, 34396, 20102, 20142,
- 20698, 20001, 20940, 23534, 26009, 26753, 28092, 29471, 30274, 30637,
- 31260, 31975, 33391, 35538, 36988, 37327, 38517, 38936, [12050, 21147],
- 32209, 20523, 21400, 26519, 28107, 29136, 29747, 33256, 36650, 38563,
- 40023, 40607, 29792, 22593, 28057, 32047, 39006, 20196, 20278, 20363,
- 20919, 21169, 23994, 24604, 29618, 31036, 33491, 37428, 38583, 38646,
- 38666, 40599, 40802, 26278, 27508, 21015, 21155, 28872, 35010, 24265,
- 24651, 24976, 28451, 29001, 31806, 32244, 32879, 34030, 36899, 37676,
- 21570, 39791, 27347, 28809, 36034, 36335, 38706, 21172, 23105, 24266,
- 24324, 26391, 27004, 27028, 28010, 28431, 29282, 29436, 31725,
- [12156, 32769], 32894, 34635, 37070, 20845, 40595, 31108, 32907, 37682,
- 35542, 20525, 21644, 35441, 27498, 36036, 33031, 24785, 26528, 40434,
- 20121, 20120, 39952, 35435, 34241, 34152, 26880, 28286, 30871, 33109,
- 24332, 19984, 19989, 20010, 20017, [12034, 20022], 20028, [12035, 20031],
- 20034, 20054, 20056, 20098, [12037, 20101], 35947, 20106, 33298, 24333,
- 20110, {f: 2, c: 20126}, [12039, 20128], 20130, 20144, 20147, 20150, 20174,
- 20173, 20164, 20166, 20162, 20183, 20190, 20205, 20191, 20215, 20233,
- 20314, 20272, 20315, 20317, 20311, 20295, 20342, 20360, 20367, 20376,
- 20347, 20329, 20336, 20369, 20335, 20358, 20374, 20760, 20436, 20447,
- 20430, 20440, 20443, 20433, 20442, 20432, {f: 2, c: 20452}, 20506, 20520,
- 20500, 20522, 20517, 20485, 20252, 20470, 20513, 20521, 20524, 20478,
- 20463, 20497, 20486, 20547, 20551, 26371, 20565, 20560, 20552, 20570,
- 20566, 20588, 20600, 20608, 20634, 20613, 20660, 20658, {f: 2, c: 20681},
- 20659, 20674, 20694, 20702, 20709, 20717, 20707, 20718, 20729, 20725,
- 20745, {f: 2, c: 20737}, 20758, 20757, 20756, 20762, 20769, 20794, 20791,
- 20796, 20795, [12041, 20799], [11918, 20800], 20818, 20812, 20820, 20834,
- 31480, {f: 2, c: 20841}, 20846, 20864, [12044, 20866], 22232, 20876, 20873,
- 20879, 20881, 20883, 20885, [12045, 20886], 20900, 20902, 20898,
- {f: 2, c: 20905}, [12046, 20907], 20915, {f: 2, c: 20913}, 20912, 20917,
- 20925, 20933, 20937, 20955, [12047, 20960], 34389, 20969, 20973, 20976,
- [12048, 20981], 20990, 20996, 21003, 21012, 21006, 21031, 21034, 21038,
- 21043, 21049, 21071, 21060, {f: 2, c: 21067}, 21086, 21076, 21098, 21108,
- 21097, 21107, 21119, 21117, 21133, 21140, 21138, 21105, 21128, 21137,
- 36776, 36775, {f: 2, c: 21164}, 21180, 21173, 21185, 21197, 21207, 21214,
- 21219, 21222, 39149, 21216, 21235, 21237, 21240, [12051, 21241], 21254,
- 21256, 30008, 21261, 21264, 21263, [12052, 21269], [12053, 21274], 21283,
- 21295, 21297, 21299, [12054, 21304], 21312, 21318, 21317, 19991, 21321,
- 21325, 20950, 21342, [12057, 21353], 21358, 22808, 21371, 21367,
- [12058, 21378], 21398, 21408, 21414, 21413, 21422, 21424, [12059, 21430],
- 21443, 31762, 38617, 21471, 26364, 29166, 21486, 21480, 21485, 21498,
- 21505, 21565, 21568, {f: 2, c: 21548}, 21564, 21550, 21558, 21545, 21533,
- 21582, 21647, 21621, 21646, 21599, 21617, 21623, 21616, 21650, 21627,
- 21632, 21622, 21636, 21648, 21638, 21703, 21666, 21688, 21669, 21676,
- 21700, 21704, 21672, 21675, 21698, 21668, 21694, 21692, 21720,
- {f: 2, c: 21733}, 21775, 21780, 21757, 21742, 21741, 21754, 21730, 21817,
- 21824, 21859, 21836, 21806, 21852, 21829, {f: 2, c: 21846}, 21816, 21811,
- 21853, 21913, 21888, 21679, 21898, 21919, 21883, 21886, 21912, 21918,
- 21934, 21884, 21891, 21929, 21895, 21928, 21978, 21957, 21983, 21956,
- 21980, 21988, 21972, 22036, 22007, 22038, 22014, 22013, 22043, 22009,
- 22094, 22096, 29151, 22068, 22070, 22066, 22072, 22123, 22116, 22063,
- 22124, 22122, 22150, 22144, 22154, 22176, 22164, 22159, 22181, 22190,
- 22198, 22196, 22210, 22204, 22209, 22211, 22208, 22216, 22222, 22225,
- 22227, [12062, 22231], 22254, 22265, 22272, 22271, 22276, 22281, 22280,
- 22283, 22285, 22291, 22296, 22294, 21959, 22300, 22310, {f: 2, c: 22327},
- 22350, 22331, 22336, 22351, 22377, 22464, 22408, 22369, 22399, 22409,
- 22419, 22432, 22451, 22436, 22442, 22448, 22467, 22470, 22484,
- {f: 2, c: 22482}, 22538, 22486, 22499, 22539, 22553, 22557, 22642, 22561,
- 22626, 22603, 22640, 27584, 22610, 22589, 22649, 22661, 22713, 22687,
- 22699, 22714, 22750, 22715, 22712, 22702, 22725, 22739, 22737, 22743,
- 22745, 22744, 22757, 22748, 22756, 22751, 22767, 22778, 22777,
- {f: 3, c: 22779}, [12065, 22786], [12066, 22794], 22800, 22811, 26790,
- 22821, {f: 2, c: 22828}, 22834, 22840, 22846, 31442, 22869, 22864, 22862,
- 22874, 22872, 22882, 22880, 22887, 22892, 22889, 22904, 22913, 22941,
- 20318, 20395, 22947, 22962, 22982, 23016, 23004, 22925, {f: 2, c: 23001},
- 23077, 23071, 23057, 23068, 23049, 23066, 23104, 23148, 23113,
- {f: 2, c: 23093}, 23138, 23146, 23194, 23228, 23230, 23243, 23234, 23229,
- 23267, 23255, 23270, 23273, 23254, {f: 2, c: 23290}, 23308, 23307, 23318,
- 23346, 23248, 23338, 23350, 23358, 23363, 23365, 23360, 23377, 23381,
- {f: 2, c: 23386}, 23397, 23401, 23408, 23411, 23413, 23416, 25992, 23418,
- [12071, 23424], 23427, 23462, 23480, 23491, 23495, 23497, 23508, 23504,
- 23524, 23526, 23522, 23518, 23525, 23531, 23536, 23542, 23539, 23557,
- {f: 2, c: 23559}, 23565, 23571, 23584, [11920, 12074, 23586], 23592,
- [12075, 23608], 23609, 23617, 23622, 23630, 23635, 23632, 23631, 23409,
- 23660, [12076, 23662], 20066, 23670, 23673, 23692, 23697, 23700, 22939,
- 23723, 23739, 23734, 23740, 23735, 23749, 23742, 23751, 23769, 23785,
- 23805, 23802, 23789, 23948, 23786, 23819, 23829, 23831, 23900, 23839,
- 23835, 23825, 23828, 23842, 23834, 23833, 23832, 23884, 23890, 23886,
- 23883, 23916, 23923, 23926, 23943, 23940, 23938, 23970, 23965, 23980,
- 23982, 23997, 23952, 23991, 23996, 24009, 24013, 24019, 24018, 24022,
- [12078, 24027], 24043, 24050, 24053, 24075, 24090, 24089, 24081, 24091,
- {f: 2, c: 24118}, 24132, 24131, 24128, 24142, 24151, 24148, 24159, 24162,
- 24164, 24135, {f: 2, c: 24181}, [11923, 12083, 24186], 40636,
- [12084, 24191], 24224, {f: 2, c: 24257}, 24264, 24272, 24271, 24278, 24291,
- 24285, {f: 2, c: 24282}, 24290, 24289, {f: 2, c: 24296}, 24300, 24305,
- 24307, 24304, [12085, 24308], 24312, [12086, 24318], 24323, 24329, 24413,
- 24412, [12087, 24331], 24337, 24342, 24361, 24365, 24376, 24385, 24392,
- 24396, 24398, 24367, [11924, 24401], {f: 2, c: 24406}, 24409,
- [12090, 24417], 24429, [12091, 24435], 24439, 24451, 24450, 24447, 24458,
- 24456, 24465, 24455, 24478, 24473, 24472, 24480, 24488, 24493, 24508,
- 24534, 24571, 24548, 24568, 24561, 24541, 24755, 24575, 24609, 24672,
- 24601, 24592, 24617, 24590, 24625, 24603, 24597, 24619, 24614, 24591,
- 24634, 24666, 24641, 24682, 24695, 24671, 24650, 24646, 24653, 24675,
- 24643, 24676, 24642, 24684, 24683, 24665, 24705, 24717, 24807, 24707,
- 24730, 24708, 24731, {f: 2, c: 24726}, 24722, 24743, 24715, 24801, 24760,
- 24800, 24787, 24756, 24560, 24765, 24774, 24757, 24792, 24909, 24853,
- 24838, {f: 2, c: 24822}, 24832, 24820, 24826, 24835, 24865, 24827, 24817,
- {f: 2, c: 24845}, 24903, 24894, 24872, 24871, 24906, 24895, 24892, 24876,
- 24884, 24893, 24898, 24900, 24947, 24951, {f: 3, c: 24920}, 24939, 24948,
- 24943, 24933, 24945, 24927, 24925, 24915, 24949, 24985, 24982, 24967,
- 25004, 24980, 24986, 24970, 24977, 25003, 25006, 25036, 25034, 25033,
- 25079, 25032, 25027, 25030, 25018, 25035, 32633, 25037, 25062, 25059,
- 25078, 25082, 25076, 25087, 25085, 25084, 25086, 25088, [12093, 25096],
- 25097, 25101, 25100, 25108, 25115, 25118, 25121, 25130, 25134, 25136,
- {f: 2, c: 25138}, 25153, 25166, 25182, 25187, 25179, 25184, 25192, 25212,
- 25218, 25225, 25214, {f: 2, c: 25234}, 25238, 25300, 25219, 25236, 25303,
- 25297, 25275, 25295, 25343, 25286, 25812, 25288, 25308, 25292, 25290,
- 25282, 25287, 25243, 25289, 25356, 25326, 25329, 25383, 25346, 25352,
- 25327, 25333, 25424, 25406, 25421, 25628, 25423, 25494, 25486, 25472,
- 25515, 25462, 25507, 25487, 25481, 25503, 25525, 25451, 25449, 25534,
- 25577, 25536, 25542, 25571, 25545, 25554, 25590, 25540, 25622, 25652,
- 25606, 25619, 25638, 25654, 25885, 25623, 25640, 25615, 25703, 25711,
- 25718, 25678, 25898, 25749, 25747, 25765, 25769, 25736, 25788, 25818,
- 25810, 25797, 25799, 25787, 25816, 25794, 25841, 25831, 33289,
- {f: 2, c: 25824}, 25260, 25827, 25839, 25900, 25846, 25844, 25842, 25850,
- 25856, 25853, 25880, 25884, 25861, 25892, 25891, 25899, [12097, 25908],
- [11929, 25909], 25911, 25910, 25912, 30027, 25928, 25942, 25941, 25933,
- 25944, 25950, 25949, 25970, 25976, {f: 2, c: 25986}, 35722, 26011, 26015,
- 26027, 26039, 26051, 26054, 26049, 26052, 26060, 26066, 26075, 26073,
- [12102, 26080], [11931, 26081], 26097, 26482, 26122, 26115, 26107, 26483,
- {f: 2, c: 26165}, 26164, 26140, 26191, 26180, 26185, 26177, 26206, 26205,
- 26212, {f: 2, c: 26215}, 26207, 26210, 26224, 26243, 26248, 26254, 26249,
- 26244, 26264, 26269, 26305, 26297, 26313, 26302, 26300, 26308, 26296,
- 26326, 26330, 26336, 26175, 26342, 26345, [12104, 26352], 26357, 26359,
- 26383, 26390, 26398, {f: 2, c: 26406}, 38712, 26414, 26431, 26422, 26433,
- 26424, 26423, 26438, 26462, 26464, 26457, {f: 2, c: 26467}, 26505, 26480,
- 26537, 26492, 26474, 26508, 26507, 26534, 26529, 26501, 26551, 26607,
- 26548, 26604, 26547, 26601, 26552, 26596, 26590, 26589, 26594, 26606,
- 26553, 26574, 26566, 26599, 27292, 26654, 26694, 26665, 26688, 26701,
- 26674, 26702, 26803, 26667, 26713, 26723, 26743, 26751, 26783, 26767,
- 26797, 26772, 26781, 26779, 26755, 27310, 26809, 26740, 26805, 26784,
- 26810, 26895, 26765, 26750, 26881, 26826, 26888, 26840, 26914, 26918,
- 26849, 26892, 26829, 26836, 26855, 26837, 26934, 26898, 26884, 26839,
- 26851, 26917, 26873, 26848, 26863, 26920, 26922, 26906, 26915, 26913,
- 26822, 27001, 26999, 26972, 27000, 26987, 26964, 27006, 26990, 26937,
- 26996, 26941, 26969, 26928, 26977, 26974, 26973, 27009, 26986, 27058,
- 27054, 27088, 27071, 27073, 27091, 27070, 27086, 23528, 27082, 27101,
- 27067, 27075, 27047, 27182, 27025, 27040, 27036, 27029, 27060, 27102,
- 27112, 27138, 27163, 27135, 27402, 27129, 27122, 27111, 27141, 27057,
- 27166, 27117, 27156, 27115, 27146, 27154, 27329, 27171, 27155, 27204,
- 27148, 27250, 27190, 27256, 27207, 27234, 27225, 27238, 27208, 27192,
- 27170, 27280, 27277, 27296, 27268, {f: 2, c: 27298}, 27287, 34327, 27323,
- 27331, 27330, 27320, 27315, 27308, 27358, 27345, 27359, 27306, 27354,
- 27370, 27387, 27397, 34326, 27386, 27410, 27414, 39729, 27423, 27448,
- 27447, 30428, 27449, 39150, 27463, 27459, 27465, 27472, 27481, 27476,
- 27483, 27487, 27489, 27512, [12109, 27513], {f: 2, c: 27519}, 27524, 27523,
- 27533, 27544, 27541, 27550, 27556, {f: 2, c: 27562}, 27567, 27570, 27569,
- [12110, 27571], 27575, 27580, 27590, [12111, 27595], 27603, 27615, 27628,
- 27627, 27635, 27631, 40638, 27656, 27667, [12115, 27668], 27675, 27684,
- 27683, 27742, 27733, 27746, 27754, 27778, 27789, 27802, 27777, 27803,
- 27774, 27752, 27763, 27794, 27792, 27844, 27889, 27859, 27837, 27863,
- 27845, 27869, 27822, 27825, 27838, 27834, 27867, 27887, 27865, 27882,
- 27935, 34893, 27958, 27947, 27965, 27960, 27929, 27957, 27955, 27922,
- 27916, 28003, 28051, 28004, 27994, 28025, 27993, 28046, 28053, 28644,
- 28037, 28153, 28181, 28170, 28085, 28103, 28134, 28088, 28102, 28140,
- 28126, 28108, 28136, 28114, 28101, 28154, 28121, 28132, 28117, 28138,
- 28142, 28205, 28270, 28206, 28185, 28274, 28255, 28222, 28195, 28267,
- 28203, 28278, 28237, 28191, 28227, 28218, 28238, 28196, 28415, 28189,
- 28216, 28290, 28330, 28312, 28361, 28343, 28371, 28349, 28335, 28356,
- 28338, {f: 2, c: 28372}, 28303, 28325, 28354, 28319, 28481, 28433, 28748,
- 28396, 28408, 28414, 28479, 28402, 28465, 28399, 28466, 28364, 28478,
- 28435, 28407, 28550, 28538, 28536, 28545, 28544, 28527, 28507, 28659,
- 28525, 28546, 28540, 28504, 28558, 28561, 28610, 28518, 28595, 28579,
- 28577, 28580, 28601, 28614, 28586, 28639, 28629, 28652, 28628, 28632,
- 28657, 28654, 28635, 28681, 28683, 28666, 28689, 28673, 28687, 28670,
- 28699, 28698, 28532, 28701, 28696, 28703, 28720, 28734, 28722, 28753,
- 28771, 28825, 28818, 28847, 28913, 28844, 28856, 28851, 28846, 28895,
- 28875, 28893, 28889, 28937, 28925, 28956, 28953, 29029, 29013, 29064,
- 29030, 29026, 29004, 29014, 29036, 29071, 29179, 29060, 29077, 29096,
- 29100, 29143, 29113, 29118, 29138, 29129, 29140, 29134, 29152, 29164,
- 29159, 29173, 29180, 29177, 29183, 29197, 29200, 29211, 29224, 29229,
- 29228, 29232, 29234, [12120, 29243], 29244, [12121, 29247], 29248, 29254,
- 29259, 29272, 29300, 29310, 29314, 29313, 29319, 29330, 29334, 29346,
- 29351, 29369, 29362, 29379, 29382, 29380, 29390, 29394, 29410,
- {f: 2, c: 29408}, 29433, 29431, 20495, 29463, 29450, 29468, 29462, 29469,
- 29492, 29487, 29481, 29477, 29502, {f: 2, c: 29518}, 40664, 29527, 29546,
- 29544, 29552, 29560, 29557, 29563, 29562, 29640, 29619, 29646, 29627,
- 29632, 29669, 29678, 29662, 29858, 29701, 29807, 29733, 29688, 29746,
- 29754, 29781, 29759, 29791, 29785, 29761, 29788, 29801, 29808, 29795,
- 29802, 29814, 29822, 29835, 29854, 29863, 29898, 29903, 29908, 29681,
- 29920, 29923, 29927, 29929, 29934, 29938, {f: 2, c: 29936}, 29944, 29943,
- 29956, 29955, 29957, 29964, 29966, 29965, 29973, 29971, 29982, 29990,
- 29996, 30012, 30020, 30029, 30026, 30025, 30043, 30022, 30042, 30057,
- 30052, 30055, 30059, 30061, 30072, 30070, {f: 2, c: 30086}, 30068, 30090,
- 30089, 30082, 30100, 30106, 30109, 30117, 30115, 30146, 30131, 30147,
- 30133, 30141, 30136, 30140, 30129, 30157, 30154, 30162, 30169, 30179,
- 30174, {f: 2, c: 30206}, 30204, 30209, 30192, 30202, {f: 2, c: 30194},
- 30219, 30221, 30217, 30239, 30247, {f: 3, c: 30240}, 30244, 30260, 30256,
- 30267, {f: 2, c: 30279}, 30278, 30300, 30296, {f: 2, c: 30305},
- {f: 3, c: 30312}, 30311, 30316, 30320, 30322, [12136, 30326], 30328, 30332,
- 30336, 30339, 30344, 30347, 30350, 30358, 30355, {f: 2, c: 30361}, 30384,
- 30388, {f: 3, c: 30392}, 30402, 30413, 30422, 30418, 30430, 30433, 30437,
- 30439, 30442, 34351, 30459, 30472, 30471, 30468, 30505, 30500, 30494,
- {f: 2, c: 30501}, 30491, {f: 2, c: 30519}, 30535, 30554, 30568, 30571,
- 30555, 30565, 30591, 30590, 30585, 30606, 30603, 30609, 30624, 30622,
- 30640, 30646, 30649, 30655, {f: 2, c: 30652}, 30651, 30663, 30669, 30679,
- 30682, 30684, 30691, 30702, 30716, 30732, 30738, 31014, 30752, 31018,
- 30789, 30862, 30836, 30854, 30844, 30874, 30860, 30883, 30901, 30890,
- 30895, 30929, 30918, 30923, 30932, 30910, 30908, 30917, 30922, 30956,
- 30951, 30938, 30973, 30964, 30983, 30994, 30993, 31001, 31020, 31019,
- 31040, 31072, 31063, 31071, 31066, 31061, 31059, 31098, 31103, 31114,
- 31133, 31143, 40779, 31146, 31150, 31155, {f: 2, c: 31161}, 31177, 31189,
- 31207, 31212, 31201, 31203, 31240, 31245, {f: 2, c: 31256}, 31264, 31263,
- 31104, 31281, 31291, 31294, 31287, 31299, 31319, 31305, {f: 2, c: 31329},
- 31337, 40861, 31344, 31353, 31357, 31368, 31383, 31381, 31384, 31382,
- 31401, 31432, 31408, 31414, 31429, 31428, 31423, 36995, 31431, 31434,
- 31437, 31439, 31445, 31443, {f: 2, c: 31449}, 31453, {f: 2, c: 31457},
- 31462, 31469, 31472, 31490, 31503, 31498, 31494, 31539, {f: 2, c: 31512},
- 31518, 31541, 31528, 31542, 31568, 31610, 31492, 31565, 31499, 31564,
- 31557, 31605, 31589, 31604, 31591, {f: 2, c: 31600}, 31596, 31598, 31645,
- 31640, 31647, 31629, 31644, 31642, 31627, 31634, 31631, 31581, 31641,
- 31691, 31681, 31692, 31695, 31668, 31686, 31709, 31721, 31761, 31764,
- 31718, 31717, 31840, 31744, 31751, 31763, 31731, 31735, 31767, 31757,
- 31734, 31779, 31783, 31786, 31775, 31799, 31787, 31805, 31820, 31811,
- 31828, 31823, 31808, 31824, 31832, 31839, 31844, 31830, 31845, 31852,
- 31861, 31875, 31888, 31908, 31917, 31906, 31915, 31905, 31912, 31923,
- 31922, 31921, 31918, 31929, 31933, 31936, 31941, 31938, 31960, 31954,
- 31964, 31970, 39739, 31983, 31986, 31988, 31990, 31994, 32006, 32002,
- 32028, 32021, 32010, 32069, 32075, 32046, 32050, 32063, 32053, 32070,
- 32115, 32086, 32078, 32114, 32104, 32110, 32079, 32099, 32147, 32137,
- 32091, 32143, 32125, 32155, 32186, 32174, 32163, 32181, 32199, 32189,
- 32171, 32317, 32162, 32175, 32220, 32184, 32159, 32176, 32216, 32221,
- 32228, 32222, 32251, 32242, 32225, 32261, 32266, 32291, 32289, 32274,
- 32305, 32287, 32265, 32267, 32290, 32326, 32358, 32315, 32309, 32313,
- 32323, 32311, 32306, 32314, 32359, 32349, 32342, 32350, {f: 2, c: 32345},
- 32377, 32362, 32361, 32380, 32379, 32387, 32213, 32381, 36782, 32383,
- {f: 2, c: 32392}, 32396, 32402, 32400, {f: 2, c: 32403}, 32406, 32398,
- {f: 2, c: 32411}, 32568, 32570, 32581, {f: 3, c: 32588}, 32592,
- [12153, 32593], 32597, 32596, 32600, {f: 2, c: 32607}, {f: 2, c: 32616},
- 32615, 32632, 32642, 32646, 32643, 32648, 32647, 32652, 32660, 32670,
- 32669, 32666, 32675, 32687, 32690, 32697, 32686, 32694, 32696, 35697,
- {f: 2, c: 32709}, 32714, 32725, 32724, 32737, 32742, 32745, 32755, 32761,
- 39132, 32774, 32772, 32779, [12158, 32786], {f: 2, c: 32792}, 32796, 32801,
- 32808, 32831, 32827, 32842, 32838, 32850, 32856, 32858, 32863, 32866,
- 32872, 32883, 32882, 32880, 32886, 32889, 32893, [12160, 32895], 32900,
- 32902, 32901, 32923, 32915, 32922, 32941, 20880, 32940, 32987, 32997,
- 32985, 32989, 32964, 32986, 32982, 33033, 33007, 33009, 33051, 33065,
- 33059, 33071, 33099, 38539, 33094, 33086, 33107, 33105, 33020, 33137,
- 33134, {f: 2, c: 33125}, 33140, 33155, 33160, 33162, 33152, 33154, 33184,
- 33173, 33188, 33187, 33119, 33171, 33193, 33200, 33205, 33214, 33208,
- 33213, 33216, 33218, 33210, 33225, 33229, 33233, 33241, 33240, 33224,
- 33242, {f: 2, c: 33247}, 33255, {f: 2, c: 33274}, 33278, {f: 2, c: 33281},
- 33285, 33287, 33290, 33293, 33296, 33302, 33321, 33323, 33336, 33331,
- 33344, 33369, 33368, 33373, 33370, 33375, 33380, 33378, 33384,
- {f: 2, c: 33386}, 33326, 33393, 33399, [12171, 33400], 33406, 33421, 33426,
- 33451, 33439, 33467, 33452, 33505, 33507, 33503, 33490, 33524, 33523,
- 33530, 33683, 33539, 33531, 33529, 33502, 33542, 33500, 33545, 33497,
- 33589, 33588, 33558, 33586, 33585, 33600, 33593, 33616, 33605, 33583,
- 33579, {f: 2, c: 33559}, 33669, 33690, 33706, 33695, 33698, 33686, 33571,
- 33678, 33671, 33674, 33660, 33717, 33651, 33653, 33696, 33673, 33704,
- 33780, 33811, 33771, 33742, 33789, 33795, 33752, 33803, 33729, 33783,
- 33799, 33760, 33778, 33805, 33826, 33824, 33725, 33848, 34054, 33787,
- 33901, 33834, 33852, 34138, 33924, 33911, 33899, 33965, 33902, 33922,
- 33897, 33862, 33836, 33903, 33913, 33845, 33994, 33890, 33977, 33983,
- 33951, 34009, 33997, 33979, 34010, 34000, 33985, 33990, 34006, 33953,
- 34081, 34047, 34036, {f: 2, c: 34071}, 34092, 34079, 34069, 34068, 34044,
- 34112, 34147, 34136, 34120, 34113, 34306, 34123, 34133, 34176, 34212,
- 34184, 34193, 34186, 34216, 34157, 34196, 34203, 34282, 34183, 34204,
- 34167, 34174, 34192, 34249, 34234, 34255, 34233, 34256, 34261, 34269,
- 34277, 34268, 34297, 34314, 34323, 34315, 34302, 34298, 34310, 34338,
- 34330, 34352, 34367, [12172, 34381], 20053, 34388, 34399, 34407, 34417,
- 34451, 34467, {f: 2, c: 34473}, {f: 2, c: 34443}, 34486, 34479, 34500,
- 34502, 34480, 34505, 34851, 34475, 34516, 34526, 34537, 34540, 34527,
- 34523, 34543, 34578, 34566, 34568, 34560, 34563, 34555, 34577, 34569,
- 34573, 34553, 34570, 34612, 34623, 34615, 34619, 34597, 34601, 34586,
- 34656, 34655, 34680, 34636, 34638, 34676, 34647, 34664, 34670, 34649,
- 34643, 34659, 34666, 34821, 34722, 34719, 34690, 34735, 34763, 34749,
- 34752, 34768, 38614, 34731, 34756, 34739, 34759, 34758, 34747, 34799,
- 34802, 34784, 34831, 34829, 34814, {f: 2, c: 34806}, 34830, 34770, 34833,
- 34838, 34837, 34850, 34849, 34865, 34870, 34873, 34855, 34875, 34884,
- 34882, 34898, 34905, 34910, 34914, 34923, 34945, 34942, 34974, 34933,
- 34941, 34997, 34930, 34946, 34967, 34962, 34990, 34969, 34978, 34957,
- 34980, 34992, 35007, 34993, {f: 2, c: 35011}, 35028, {f: 2, c: 35032},
- 35037, 35065, 35074, 35068, 35060, 35048, 35058, 35076, 35084, 35082,
- 35091, 35139, 35102, 35109, {f: 2, c: 35114}, 35137, 35140, 35131, 35126,
- 35128, 35148, 35101, 35168, 35166, 35174, 35172, 35181, 35178, 35183,
- 35188, 35191, [12177, 35198], 35203, 35208, 35210, 35219, 35224, 35233,
- 35241, 35238, 35244, 35247, 35250, 35258, 35261, {f: 2, c: 35263}, 35290,
- {f: 2, c: 35292}, 35303, 35316, 35320, 35331, 35350, 35344, 35340, 35355,
- 35357, 35365, 35382, 35393, 35419, 35410, 35398, 35400, 35452, 35437,
- 35436, 35426, 35461, 35458, 35460, 35496, 35489, 35473, {f: 2, c: 35493},
- 35482, 35491, 35524, 35533, 35522, 35546, 35563, 35571, 35559, 35556,
- 35569, 35604, 35552, 35554, 35575, 35550, 35547, 35596, 35591, 35610,
- 35553, 35606, 35600, 35607, 35616, 35635, 38827, 35622, 35627, 35646,
- 35624, 35649, 35660, 35663, 35662, 35657, 35670, 35675, 35674, 35691,
- 35679, 35692, 35695, 35700, 35709, 35712, 35724, 35726, {f: 2, c: 35730},
- 35734, {f: 2, c: 35737}, 35898, 35905, 35903, 35912, 35916, 35918, 35920,
- [12183, 35925], 35938, 35948, [12184, 35960], 35962, 35970, 35977, 35973,
- 35978, {f: 2, c: 35981}, 35988, 35964, 35992, 25117, 36013, 36010, 36029,
- {f: 2, c: 36018}, 36014, 36022, 36040, 36033, 36068, 36067, 36058, 36093,
- {f: 2, c: 36090}, {f: 2, c: 36100}, 36106, 36103, 36111, 36109, 36112,
- 40782, 36115, 36045, 36116, 36118, 36199, 36205, 36209, 36211, 36225,
- 36249, 36290, 36286, 36282, 36303, 36314, 36310, 36300, 36315, 36299,
- {f: 2, c: 36330}, 36319, 36323, 36348, {f: 2, c: 36360}, 36351,
- {f: 2, c: 36381}, 36368, 36383, 36418, 36405, 36400, 36404, 36426, 36423,
- 36425, 36428, 36432, 36424, 36441, 36452, 36448, 36394, 36451, 36437,
- 36470, 36466, 36476, 36481, 36487, 36485, 36484, 36491, 36490, 36499,
- 36497, 36500, 36505, 36522, 36513, 36524, 36528, 36550, 36529, 36542,
- 36549, 36552, 36555, 36571, 36579, 36604, 36603, 36587, 36606, 36618,
- 36613, 36629, 36626, 36633, 36627, 36636, 36639, 36635, 36620, 36646,
- 36659, 36667, 36665, 36677, 36674, 36670, 36684, 36681, 36678, 36686,
- 36695, 36700, {f: 3, c: 36706}, 36764, 36767, 36771, 36781, 36783, 36791,
- 36826, 36837, 36834, 36842, 36847, 36999, 36852, 36869, {f: 2, c: 36857},
- 36881, 36885, 36897, 36877, 36894, 36886, 36875, 36903, 36918, 36917,
- 36921, 36856, {f: 4, c: 36943}, 36878, 36937, 36926, 36950, 36952, 36958,
- 36968, 36975, 36982, 38568, 36978, 36994, 36989, 36993, 36992, 37002,
- 37001, 37007, 37032, 37039, 37041, 37045, 37090, 37092, 25160, 37083,
- 37122, 37138, 37145, 37170, 37168, 37194, 37206, 37208, 37219, 37221,
- 37225, 37235, 37234, 37259, 37257, 37250, 37282, 37291, 37295, 37290,
- 37301, 37300, 37306, {f: 2, c: 37312}, 37321, 37323, 37328, 37334, 37343,
- 37345, 37339, 37372, {f: 2, c: 37365}, 37406, 37375, 37396, 37420, 37397,
- 37393, 37470, 37463, 37445, 37449, 37476, 37448, 37525, 37439, 37451,
- 37456, 37532, 37526, 37523, 37531, 37466, 37583, 37561, 37559, 37609,
- 37647, 37626, 37700, 37678, 37657, 37666, 37658, 37667, 37690, 37685,
- 37691, 37724, 37728, 37756, 37742, 37718, 37808, {f: 2, c: 37804}, 37780,
- 37817, {f: 2, c: 37846}, 37864, 37861, 37848, 37827, 37853, 37840, 37832,
- 37860, 37914, 37908, 37907, 37891, 37895, 37904, 37942, 37931, 37941,
- 37921, 37946, 37953, 37970, 37956, 37979, 37984, 37986, 37982, 37994,
- 37417, 38000, 38005, 38007, 38013, 37978, 38012, 38014, 38017, 38015,
- 38274, 38279, 38282, 38292, 38294, {f: 2, c: 38296}, 38304, 38312, 38311,
- 38317, 38332, 38331, 38329, 38334, 38346, 28662, 38339, 38349, 38348,
- 38357, 38356, 38358, 38364, 38369, 38373, 38370, 38433, 38440,
- {f: 2, c: 38446}, 38466, 38476, 38479, 38475, 38519, 38492, 38494, 38493,
- 38495, 38502, 38514, 38508, 38541, 38552, 38549, 38551, 38570, 38567,
- {f: 2, c: 38577}, 38576, 38580, [12202, 38582], 38584, [12203, 38585],
- 38606, 38603, 38601, 38605, 35149, 38620, 38669, 38613, 38649, 38660,
- 38662, 38664, 38675, 38670, 38673, 38671, 38678, 38681, 38692, 38698,
- 38704, 38713, {f: 2, c: 38717}, 38724, 38726, 38728, 38722, 38729, 38748,
- 38752, 38756, 38758, 38760, 21202, 38763, 38769, 38777, 38789, 38780,
- 38785, 38778, 38790, 38795, {f: 2, c: 38799}, 38812, 38824, 38822, 38819,
- {f: 2, c: 38835}, 38851, 38854, 38856, [12209, 38859], 38876,
- [12210, 38893], 40783, 38898, 31455, 38902, 38901, 38927, 38924, 38968,
- 38948, 38945, 38967, 38973, 38982, 38991, 38987, 39019, {f: 3, c: 39023},
- 39028, 39027, 39082, 39087, 39089, 39094, 39108, 39107, 39110, 39145,
- 39147, 39171, 39177, 39186, 39188, 39192, 39201, {f: 2, c: 39197}, 39204,
- 39200, 39212, 39214, {f: 2, c: 39229}, 39234, 39241, 39237, 39248, 39243,
- {f: 2, c: 39249}, 39244, 39253, {f: 2, c: 39319}, 39333, {f: 2, c: 39341},
- 39356, 39391, 39387, 39389, 39384, 39377, {f: 2, c: 39405},
- {f: 2, c: 39409}, 39419, 39416, 39425, 39439, 39429, 39394, 39449, 39467,
- 39479, 39493, 39490, 39488, 39491, 39486, 39509, 39501, 39515, 39511,
- 39519, 39522, 39525, 39524, 39529, 39531, 39530, 39597, 39600, 39612,
- 39616, 39631, 39633, {f: 2, c: 39635}, 39646, [12221, 39647],
- {f: 2, c: 39650}, 39654, 39663, 39659, 39662, 39668, 39665, 39671, 39675,
- 39686, 39704, 39706, 39711, {f: 2, c: 39714}, [12222, 39717],
- {f: 4, c: 39719}, 39726, [12223, 39727], [12224, 39730], 39748, 39747,
- 39759, {f: 2, c: 39757}, 39761, 39768, 39796, 39827, 39811, 39825,
- {f: 2, c: 39830}, {f: 2, c: 39839}, 39848, 39860, 39872, 39882, 39865,
- 39878, 39887, {f: 2, c: 39889}, 39907, 39906, 39908, 39892, 39905, 39994,
- 39922, 39921, 39920, 39957, 39956, 39945, 39955, 39948, 39942, 39944,
- 39954, 39946, 39940, 39982, 39963, 39973, 39972, 39969, 39984, 40007,
- 39986, 40006, 39998, 40026, 40032, 40039, 40054, 40056, 40167, 40172,
- 40176, 40201, 40200, 40171, 40195, 40198, 40234, 40230, 40367, 40227,
- 40223, 40260, 40213, 40210, 40257, 40255, 40254, 40262, 40264,
- {f: 2, c: 40285}, 40292, 40273, 40272, 40281, 40306, 40329, 40327, 40363,
- 40303, 40314, 40346, 40356, 40361, 40370, 40388, 40385, 40379, 40376,
- 40378, 40390, 40399, 40386, 40409, 40403, 40440, 40422, 40429, 40431,
- 40445, {f: 2, c: 40474}, 40478, [12228, 40565], 40569, 40573, 40577, 40584,
- {f: 2, c: 40587}, 40594, 40597, 40593, 40605, [12230, 40613], 40617, 40632,
- 40618, 40621, 38753, 40652, {f: 3, c: 40654}, 40660, 40668, 40670, 40669,
- 40672, 40677, 40680, 40687, 40692, {f: 2, c: 40694}, [12235, 40697],
- {f: 2, c: 40699}, [12236, 40701], {f: 2, c: 40711}, 30391, 40725, 40737,
- 40748, 40766, [12241, 40778], [12242, 40786], 40788, 40803,
- {f: 3, c: 40799}, {f: 2, c: 40806}, 40812, 40810, 40823, 40818, 40822,
- 40853, [12244, 40860], [12245, 40864], 22575, 27079, 36953, 29796, 0,
- {f: 76, c: 9472}, {f: 20, c: 9312}, {f: 10, c: 8544}, 13129, 13076, 0,
- 13133, 0, 13095, 0, 13110, 13137, 0, 13069, 13094, 0, 13099, 13130, 0,
- {f: 3, c: 13212}, {f: 2, c: 13198}, 13252, 13217, 12317, 12319, 8470,
- 13261, 0, {f: 5, c: 12964}, {f: 2, c: 12849}, 12857, 13182, 13181, 13180,
- 8750, 8721, {s: 3}, 8735, 8895, 0, 0, 21854, {s: 7}, 167133, 0, 0, 28976,
- 0, 40407, {s: 4}, 64054, 0, 0, 22169, 15694, {s: 4}, 20448, 0, 0, 36544, 0,
- 194797, {s: 4}, 153716, 32363, 33606, 167670, {s: 3}, 40572, 0, 0, 26171,
- 0, 40628, {s: 4}, 26629, {s: 5}, 23650, 0, 194780, 0, 32353, 0, 0, 64070,
- {s: 5}, 34083, 37292, {s: 7}, 34796, {s: 8}, 25620, 0, 0, 39506, {s: 4},
- 64074, 0, 194692, {s: 4}, 31774, {s: 6}, 64016, 25681, 0, 0, 63980, 22625,
- 39002, 0, 194679, {s: 3}, 31153, 0, 28678, {s: 9}, 22218, {s: 3}, 21085, 0,
- 28497, 37297, {s: 10}, 64106, {s: 6}, 38960, 0, 40629, {s: 9}, 33802,
- 63939, {f: 2, c: 63890}, 63897, 0, 34847, 194575, 0, 194771, 194584,
- {s: 7}, 137754, 23643, {s: 4}, 25890, 0, 0, 26618, 0, 26766, 0, 148432,
- 194848, {s: 21}, 34110, {s: 15}, 30562, {s: 12}, 65075, 0,
- {f: 2, c: 65073}, {s: 4}, 65072, {f: 2, c: 65077}, {f: 2, c: 65081}, 0, 0,
- {f: 2, c: 65079}, {f: 2, c: 65087}, {f: 2, c: 65085}, {f: 4, c: 65089},
- {f: 2, c: 65083}, {s: 41}, {f: 3, c: 12436}, 0, 0, 22099, {s: 41}, 65508,
- 65287, 65282, 0, 9665, 9655, 8681, 8679, 8678, 8680, 9634, 9831, 9825,
- 9828, 9826, 13216, 13218, {f: 2, c: 13220}, 13207, 8467, 13208, 13235,
- 13234, 13233, 13232, {f: 3, c: 13189}, 13259, 13200, 13268, 13206, 13090,
- 13078, 13080, 13077, 13059, 13091, 13143, 13122, 13113, 13115, 13056,
- 13105, 13127, 13086, 13098, 0, 13183, 8481, 9742, 12342, 12320, {s: 3},
- {f: 9, c: 9352}, {f: 20, c: 9332}, 12881, {f: 10, c: 8560},
- {f: 10, c: 12882}, {f: 26, c: 9372}, 12867, 12861, 12863, 12852, 12856,
- 12851, 12860, 12866, 12862, 12854, 12853, 12859, 12864, 12858, 12976,
- 12973, 12969, 12975, 12948, 12970, 12952, 12971, 12946, 12945, 12947,
- 12972, 12974, 12950, {s: 8}, {f: 3, c: 9131}, 0, {f: 3, c: 9127}, 0, 13260,
- 13061, 0, 0, 13215, 13219, 13222, 0, 0, 12958, {f: 2, c: 13192}, 13256,
- 8749, 0, 12848, {f: 6, c: 12842}, 12855, 12865, 10145, {s: 3}, 9673, 9824,
- 9829, 9827, 9830, {f: 4, c: 9728}, 9758, {f: 2, c: 9756}, 9759, 12953,
- 9450, {f: 2, c: 8554}, {s: 3}, {f: 8, c: 9601}, 9615, 9614, 9613, 9612,
- 9611, 9610, 9609, {f: 2, c: 9620}, {f: 2, c: 9581}, 9584, 9583, 9552, 9566,
- 9578, 9569, {f: 2, c: 9698}, 9701, 9700, 0, 0, {f: 3, c: 9585}, {s: 20},
- 20956, 29081, {f: 9, c: 10102}, {s: 3}, {f: 2, c: 8570}, {s: 3}, 8575,
- 8458, 8457, 0, 0, 12292, 8646, {f: 2, c: 8644}, 0, {f: 4, c: 12535}, 0, 0,
- 12957, {s: 3}, 13179, {s: 3}, 13107, 13134, {s: 30}, 32394, 35100, 37704,
- 37512, 34012, 20425, 28859, 26161, 26824, 37625, 26363, 24389,
- [12033, 20008], 20193, 20220, 20224, 20227, 20281, 20310, 20370, 20362,
- 20378, 20372, 20429, 20544, 20514, 20479, 20510, 20550, 20592, 20546,
- 20628, 20724, 20696, 20810, 20836, 20893, 20926, 20972, 21013, 21148,
- 21158, 21184, 21211, 21248, 0, 21284, 21362, 21395, 21426, 21469, 64014,
- 21660, 21642, 21673, 21759, 21894, 22361, 22373, 22444, 22472, 22471,
- 64015, 0, 22686, 22706, 22795, 22867, 22875, 22877, 22883, 22948, 22970,
- 23382, 23488, 29999, 23512, 0, 23582, 23718, 23738, 23797, 23847, 23891, 0,
- 23874, 23917, {f: 2, c: 23992}, 24016, 24353, 24372, 24423, 24503, 24542,
- 24669, 24709, 24714, 24798, 24789, 24864, 24818, 24849, 24887, 24880,
- 24984, 25107, 25254, 25589, 25696, 25757, 25806, 25934, 26112, 26133,
- 26121, 26158, 0, 26148, 26213, 26199, 26201, 64018, 26227, 26265, 26272,
- 26290, 26303, 26362, 26382, 0, 26470, 26555, 26706, 26560, 0, 26692, 26831,
- 64019, 26984, 64020, 27032, 27106, 27184, 27243, 27206, 27251, 27262,
- 27362, 27364, 27606, 27711, 27740, 27782, 27759, 27866, 27908, 28039,
- 28015, 28054, 28076, 28111, 28152, 28146, 28156, 28217, 28252, 28199,
- 28220, 28351, 28552, 28597, 28661, 28677, 28679, 28712, 28805, 28843,
- 28943, 28932, 29020, {f: 2, c: 28998}, 0, 29121, 29182, 29361, 29374,
- 29476, 64022, 29559, 29629, 29641, 29654, 29667, 29650, 29703, 29685,
- 29734, 29738, 29737, 29742, 0, 29833, 29855, 29953, 30063, 30338, 30364,
- 30366, 30363, 30374, 64023, 30534, 21167, 30753, 30798, 30820, 30842,
- 31024, {f: 3, c: 64024}, 31124, 64027, 31131, 31441, 31463, 64028, 31467,
- 31646, 64029, 32072, 0, 32183, 32160, 32214, 32338, 32583, 32673, 64030,
- 33537, 33634, 33663, 33735, 33782, 33864, 33972, 34131, 34137, 34155,
- 64031, 34224, {f: 2, c: 64032}, 34823, 35061, 35346, 35383, 35449, 35495,
- 35518, 35551, 64034, 35574, 35667, 35711, 36080, 36084, 36114, 36214,
- 64035, 36559, 0, 64037, 36967, 37086, 64038, 37141, 37159, 37338, 37335,
- 37342, {f: 2, c: 37357}, {f: 2, c: 37348}, 37382, 37392, 37386, 37434,
- 37440, 37436, 37454, 37465, 37457, 37433, 37479, 37543, {f: 2, c: 37495},
- 37607, 37591, 37593, 37584, 64039, 37589, 37600, 37587, 37669, 37665,
- 37627, 64040, 37662, 37631, 37661, 37634, 37744, 37719, 37796, 37830,
- 37854, 37880, 37937, 37957, 37960, 38290, 0, 64041, 38557, 38575, 38707,
- 38715, 38723, 38733, 38735, [12205, 38737], 0, 38999, 39013,
- {f: 2, c: 64042}, 39207, 64044, 39326, 39502, 39641, 39644, 39797, 39794,
- 39823, 39857, 39867, 39936, 40304, 40299, 64045, 40473, 40657, 0, 92,
- {s: 634}, 8364, 8486, 0, 0, 64256, {f: 2, c: 64259}, 257, 299, 363, 275,
- 333, 256, 298, 362, 274, 332, {f: 4, c: 8539}, {f: 2, c: 8531}, 8304,
- {f: 6, c: 8308}, {f: 10, c: 8320}, 461, 282, 0, 7868, 463, 0, 296, 465, 0,
- 467, 366, 360, 462, 283, 0, 7869, 464, 0, 297, 466, 0, 468, 367, 361, 593,
- 8049, 8048, 509, 0, 596, 0, 0, 601, 0, 0, 602, 0, 0, 603, 8051, 8050, 0,
- 331, 629, 652, 0, 0, 658, 643, 720, {s: 682}, {f: 10, c: 12832}, {s: 108},
- {f: 4, c: 12892}, {f: 15, c: 12977}, {s: 50}, {f: 26, c: 9424},
- {f: 26, c: 9398}, {s: 48}, {f: 47, c: 13008}, 0, {f: 10, c: 12928}, 12944,
- {f: 6, c: 12938}, 0, 12959, {s: 6}, {f: 2, c: 12960}, 12955, 12954, 12963,
- 12962, 12951, 0, 12956, 12949, {s: 6}, 9676, {s: 11}, 10111,
- {f: 10, c: 9451}, {s: 510}, 8414, {s: 815}, 13274, {s: 3}, 8448, 13250, 0,
- 0, 8453, 0, 13169, 0, 0, 13197, 13211, {s: 3}, {f: 2, c: 13271}, {s: 3},
- {f: 2, c: 13057}, 13060, 13062, 0, 13064, 0, 13063, 13066, 0, 13065, 0,
- 13067, 0, 13068, {f: 6, c: 13070}, 0, 13079, 0, 13081, 0, {f: 4, c: 13082},
- {f: 3, c: 13087}, 13092, 0, 13093, 0, 0, {f: 2, c: 13096}, 0, 13101, 0, 0,
- {f: 3, c: 13102}, 13106, 0, 0, {f: 2, c: 13108}, 13116, {s: 3}, 13111, 0,
- 13112, 13114, 13117, 13121, {f: 3, c: 13118}, {f: 4, c: 13123}, 13128,
- {f: 2, c: 13131}, {f: 2, c: 13135}, 0, 0, 13138, 13140, 0, 0, 13139,
- {f: 2, c: 13141}, {s: 132}, 8501, 976, 8714, 8463, 0, 981, 987, 977, 0,
- {f: 2, c: 9832}, 9836, {s: 5}, 12347, 0, {f: 3, c: 12339}, 8252, 8265,
- {s: 5}, 8723, 0, 8771, {f: 2, c: 8818}, {s: 6}, {f: 2, c: 12312},
- {f: 2, c: 65375}, {s: 10}, 9115, {f: 2, c: 9117}, 9120, {s: 4}, 9121,
- {f: 2, c: 9123}, 9126, {s: 12}, [9116, 9119, 9122, 9125, 9130], {s: 8},
- 9986, 0, 0, 12349, 0, 12447, 0, 0, 8709, 8864, 8854, 8856, 8853, 8855,
- {s: 4}, 9664, 9654, {s: 4}, 8656, 8596, {f: 2, c: 8600}, {f: 2, c: 8598},
- 8652, 8651, {s: 10}, 12336, 8967, {s: 8}, 10048, 10047, {s: 7}, 9643, 0,
- 9642, 0, 10010, {s: 12}, 9702, {s: 4}, 10070, {s: 379}, {f: 2, c: 65093},
- {s: 679}, 64103, 64098, 32227, [12232, 40643], 28331, 64082, 64061, 64069,
- 64062, 27114, 28212, 64096, 64071, 64056, 64066, 64078, 34395, 64105,
- 64052, 64099, 25581, 25802, 30799, 64084, 63856, 64077, 64097, 64072,
- 64076, {f: 2, c: 64091}, 64081, 64067, 64090, 28041, 29376, 0, 194885,
- 64086, 64080, 64049, 64059, 24034, 64063, 64101, 21373, 64055, 64095,
- 24501, 64064, 0, 64083, 0, 64085, 64104, 64068, 64089, 26202, 64053, 64075,
- 64100, 64065, 64048, 0, 64057, 64051, 27493, 64058, 27599, 64050, 25150,
- 64079, 63773, 63964, 63798, 28122, 63952, 26310, 27511, 64087, 37706, 0,
- 37636, {s: 120}, 133390, {s: 120}, 35999, 11991, [11965, 158033], {s: 5},
- 37555, 38321, 0, 0, 194812, {s: 13}, 194965, {s: 8}, 194794, 0, 26478,
- 11974, 0, 194594, {s: 13}, 13314, 0, 0, 26083, {s: 4}, 134071, {s: 10},
- 171339, 0, 194611, 24378, {s: 8}, 11945, 0, 20465, {s: 7}, 63753, {s: 7},
- 11964, 0, 0, 194732, 26435, {s: 3}, 133732, 35329, 25142, 0, 0, 21555,
- 23067, {s: 3}, 25221, 0, 0, 194819, {s: 6}, 21567, {s: 9}, 27506, {s: 4},
- 29986, 19256, 0, 0, 24063, {s: 6}, 194827, 29626, 134047, {s: 3}, 194600,
- 0, 194849, {s: 5}, 194623, {s: 16}, 194675, {f: 2, c: 11916}, 23577,
- {s: 3}, 131083, 23426, 194642, {s: 5}, 11997, [11999, 39136],
- [11998, 169599], 14221, 0, [11927, 14586], 0, 194887, 0, [11909, 20155],
- 131490, {s: 7}, 13599, 0, 194738, 0, 0, [11971, 35200], {s: 4}, 31237,
- {s: 4}, 35498, 0, 32085, 0, 28568, {s: 7}, 25591, 30246, {s: 4},
- [11978, 163767], {s: 5}, 146686, {s: 5}, 13351, 0, 0, 33067, 0, 0, 194842,
- {s: 5}, 11950, {s: 5}, 194714, {s: 3}, 194831, {s: 19}, 22305, 135741,
- 194586, 0, 64003, {s: 7}, 21534, 15240, 20839, {s: 4}, 63839, {s: 9},
- 20023, {s: 13}, [11946, 150804], 24421, 23020, 194658, 0, 24217, {s: 46},
- 13416, {s: 8}, 21200, {s: 9}, 26625, 0, 195024, 195039, {s: 5}, 153215, 0,
- 0, 11959, {s: 4}, 36534, 63775, {s: 3}, 63875, {s: 5}, 31867, 63906, 0,
- 63898, 0, [11961, 32770], 157360, {s: 4}, [11911, 132648], 0, 0, 131210,
- 194604, [11915, 13630], {s: 4}, 21589, 0, 22841, 0, 0, 23414, 194669,
- 23572, 14306, 23782, 0, 20040, 0, 0, 194742, {s: 4}, 158105, 25371, 0, 0,
- 26211, 0, 194779, 0, 0, 27126, 27014, {s: 3}, 27596, 0, 28183, 0, 0, 27818,
- {s: 3}, [11942, 20012], 0, 0, 29935, 30069, 30188, 30286, 16305, 30570,
- 30633, {s: 6}, 31571, 0, 0, 16996, {s: 3}, 194924, 0, 0, 32328, {s: 5},
- 11955, {s: 4}, 33089, 17491, 0, [11966, 33401], [11967, 64094],
- [11968, 64093], 0, 20857, 33626, {s: 3}, 17701, 0, 34292, 131248, {s: 4},
- 34429, 0, 13358, 35014, {s: 6}, 18406, {s: 8}, 36808, {s: 19}, 166279, 0,
- 0, 167447, 0, 0, 38969, {s: 6}, 39432, {s: 4}, 39903, {s: 10}, 148206,
- {s: 5}, 21385, 0, 64017, 194785, 0, 146622, 132625, 0, {f: 2, c: 19972},
- 19999, 20011, {f: 2, c: 20015}, {f: 2, c: 20032}, 20036, [11907, 20058],
- 20095, 20109, 20118, 20153, 20176, 20192, 20221, 20223, 20235, 20245,
- 20320, 20283, 20297, 20308, 20346, {f: 2, c: 20349}, 20375, 20414, 20431,
- 20477, {f: 2, c: 20480}, 20496, 20507, 20519, 20526, 20567, 20582, 20586,
- 20539, 20623, 20630, 20636, 20684, 20710, 20713, 20719, 20744, 20747,
- 20752, 20763, 20766, 20831, 20897, 20924, 0, 20974, 20980, 20993,
- [11913, 20994], 21011, 21065, 21089, 21094, 21139, 21192, 21232,
- {f: 2, c: 21258}, 21310, 21324, 21323, 21345, 21356, 21419, 21466, 21478,
- 21493, 21543, 21581, 21606, 21611, 21620, 21645, 21654, 21665, 21677,
- 21689, 21695, 21702, 21709, 21774, 21803, 21813, 21834, 21856, 0, 21896,
- 21902, 22024, {f: 2, c: 22030}, 22071, 22079, 22089, 22091, 22095, 22118,
- 22121, 22127, {f: 2, c: 22129}, 22165, 22170, {f: 2, c: 22188}, 22193,
- 22217, 22237, 22244, 22282, 22293, 22307, 22319, {f: 2, c: 22323}, 22348,
- 22384, 22412, 22428, 22456, 22502, 22509, {f: 2, c: 22517}, 22527, 22537,
- 22560, 22578, 22652, 22656, 22697, 22734, 22736, 22740, 22746, 22761,
- 22796, 22820, 22831, 22881, 22893, 22986, 22994, 23005, {f: 2, c: 23011},
- 23044, 23052, 23075, 23111, 23125, 23139, 23149, 23166, 23198, 23207,
- 23212, 23219, 23264, 23296, 23321, 23333, 23341, 23361, 23420,
- {f: 2, c: 23422}, 23434, [11919, 23587], 23595, 23600, 23651, 23657, 23676,
- 23755, 23762, 23796, 23844, 23846, 23875, 23878, 23882, 23954, 23956,
- 23961, 23968, 24024, 24032, 24056, 24064, 24082, {f: 2, c: 24084}, 24088,
- 24110, 24152, {f: 2, c: 24171}, 24232, 24234, {f: 2, c: 24254}, 0, 24274,
- 24327, 24334, {f: 2, c: 24348}, 24354, 24360, 24374, 24379, 24384,
- [12089, 24400], 24408, 24420, 24457, 24476, 24487, 24484, 24495, 24504,
- [11926, 24516], 24521, 24545, 24553, 24557, 24572, 24599, 24602, 24627,
- 24673, 24703, 24734, 24740, 24752, 24779, 24795, 24824, {f: 3, c: 24850},
- 24860, 24956, 24973, 24991, 25000, 25026, 25055, 25109, 25129, 25155,
- 25158, [11928, 25164], 25169, 25174, 25284, 25340, 25354, 25357, 25368,
- 25401, {f: 2, c: 25410}, 25445, 25460, 25469, 25476, 25479, 25488, 25502,
- 25553, 25564, 25609, 25616, 25634, 25684, 25691, 25709, 25723,
- {f: 2, c: 25790}, 25829, 25847, 25851, 25860, 25878, 25881, 25927, 25959,
- 25985, 25989, 26050, 26096, 26098, 26156, 26188, {f: 2, c: 26203}, 26209,
- 26219, 0, 26276, 26312, 26348, 26373, 26387, 26419, 26440, 26444, 26486,
- 26491, 26544, 26546, 26617, 26583, 26585, 26608, 26668, {f: 2, c: 26672},
- 26715, 26738, 26741, 26746, 26756, 26789, 26802, 26832, 26838, 26856,
- 26861, {f: 2, c: 26864}, 26876, 26897, 26899, 26933, 26939, 26967, 26979,
- 26994, {f: 2, c: 27007}, 27046, 27053, 27063, {f: 2, c: 27094}, 27137,
- 27151, 27157, 27176, 27188, 27198, 27205, {f: 2, c: 27216}, 27222, 27227,
- 27267, 27273, 27281, {f: 3, c: 27293}, 27356, 27367, 27372, 27422, 27428,
- 27445, 27462, 27478, 27488, 27522, 27582, 27617, 27633, 27664, 27699,
- [11937, 27701], 11938, 27737, 27766, 27771, 27781, 27797, 27804, 27856,
- 27860, 27862, 27872, {f: 2, c: 27883}, 27886, 27914, 27918, 27921, 27950,
- 27991, 27998, 28005, 28034, 28095, 28100, 28106, 28118, 28137, 28194,
- 28241, 28359, 28362, 28366, 28413, 28442, 28458, 28463, 28467, 28506,
- 28510, 28514, 28541, 28555, 28557, 28562, 28564, 28570, {f: 2, c: 28583},
- 28598, 28634, 28638, 0, 28729, 28732, 0, 28756, {f: 2, c: 28765}, 28772,
- [11939, 28780], 28798, 28801, 28821, 28855, {f: 2, c: 28883}, 28888, 28892,
- 28935, 28960, 28977, 29002, 29010, 29024, 29049, 29074, 0, 29131, 29139,
- 29142, 29184, 29213, 29227, 29240, 29249, 29267, {f: 2, c: 29269}, 29276,
- 29325, [11944, 29357], 29364, 29383, 29435, {f: 2, c: 29444}, 29480, 29489,
- 29507, 29548, 29564, 29571, {f: 2, c: 29573}, 29589, {f: 3, c: 29598},
- 29606, 29611, 29621, 29623, 29628, 29647, 29657, 29673, 29684, 29693,
- 29700, 29706, {f: 2, c: 29722}, 29732, 29736, 29740, {f: 3, c: 29743},
- 29753, 29764, 29767, 29771, 29773, 29777, 29783, 29798, 29803, 29809,
- 29824, {f: 3, c: 29829}, 29840, 29848, 29852, 29856, 29859, 29864, 29867,
- 29877, 29887, 29896, 29914, 29918, 30030, 30073, 30081, 30096,
- [12135, 30098], 30099, 30132, 30180, 30201, 30208, 30218, {f: 2, c: 30229},
- 30233, 30238, 30253, 30261, 30275, 30283, 30309, 30317, 30319, 30321,
- 30324, {f: 2, c: 30372}, 30405, 30412, 30444, 30460, 30516, 30518, 30556,
- {f: 2, c: 30559}, 30578, 30589, 30613, 30634, 30694, 30704, 30708, 30726,
- 30754, {f: 2, c: 30765}, 30768, 30773, 30824, 30878, 30920, 30924, 30926,
- 30948, {f: 2, c: 30944}, 30962, 30967, 30971, 31025, 0, [11949, 31035],
- 31037, 31045, {f: 2, c: 31067}, 31115, 31126, 31128, [12145, 31160], 31163,
- 31178, 31194, 31235, 31241, 31249, 31262, 31277, 31289, 31301, 31308,
- 31325, 0, 31341, 31352, 31392, 31395, 31411, {f: 2, c: 31419}, 31430,
- 31495, 31508, 31527, 31537, 31559, 31566, 31584, 31593, 31597, 31602,
- 31633, 31663, 31703, 31705, 31755, 31759, 31776, 31782, 31793, 31798,
- 31825, 31833, 31847, 31854, 31856, 31932, 31935, {f: 2, c: 31944}, 31959,
- 31961, 31965, 31979, {f: 3, c: 32007}, 32019, 32029, 32035, 32065, 32083,
- 32089, 32093, 32122, 32134, {f: 2, c: 32139}, 32204, 32235, 32241, 32249,
- 32264, 32273, 32277, 32288, 32327, 32354, 32366, 32371, 32397, 32401,
- 32408, 32580, 32591, [11947, 11954, 32594], [11953, 32595], 32609, 32657,
- 32703, 32718, 32735, 32741, 32748, {f: 2, c: 32750}, 32762, 32782, 32785,
- 32788, 32804, 32806, 32826, 32828, 32864, 32881, 32885, 32926, 32934,
- 32939, {f: 2, c: 32983}, 33046, 33048, 33082, 33098, 33100, 33153, 33156,
- 33204, 33231, 33273, 33283, 33313, 33330, 33332, 33350, 33355, 33359,
- 33422, 33454, 33463, 33470, 33478, 33534, 33603, 33617, 33621, 33670,
- 33677, 33682, 33688, 33705, {f: 2, c: 33727}, 33770, 33807, 33809, 33866,
- 33910, 33960, 33967, 33984, 33986, 34032, 34045, 34060, 34100, 34142,
- 34191, 34231, 34254, 34221, 34322, 34345, 34386, 34403, 34412, 34415,
- 34426, 34445, 34449, 34456, {f: 2, c: 34471}, 34554, 34557, 34571, 34579,
- 34585, 34590, 34600, 34622, 34673, 34696, 34713, {f: 2, c: 34732}, 34741,
- 34774, 34795, 34797, 34817, 0, 34822, 34827, 34836, 34844, 34902, 34911,
- [11970, 34916], 34968, 34986, {f: 2, c: 35005}, 35018, 35026, 35035,
- {f: 2, c: 35056}, 35078, {f: 3, c: 35096}, 35111, 35120, 35134, 35195,
- 35284, 35286, 35301, 35313, 35335, 35343, 35349, 35362, 35406, 35455,
- 35572, 35615, 35639, {f: 2, c: 35651}, 35668, 35740, 35742, 35911, 35924,
- 35955, 36004, 36057, 36065, 36088, 36094, 36123, 36201, 36204, 36228,
- 36237, 36245, 36262, 36294, 36302, 36324, 36332, 36384, 36427, 36460,
- 36464, 36474, 36498, 36526, 36531, 36561, 36564, 36601, 36631, 36662,
- 36774, [12193, 36789], [11981, 36790], 0, 36832, 36836, 36854, 36866,
- 36908, 36932, 37000, 37013, 37017, 37019, 37026, 37044, 37079, 37085,
- 37108, 37143, 37148, 37169, 37178, 37181, 37192, 37211, 37217, 37220,
- 37262, 37278, 37288, {f: 2, c: 37293}, 37298, 37308, 37360, 37367, 37371,
- 37383, 37416, 37427, 37432, 37443, 37447, 37455, 37472, 37570,
- {f: 2, c: 37579}, 37599, 37645, 37653, 37663, 37671, 37703, 37714, 0,
- 37738, 37741, 37787, 37818, 37801, 37825, 37834, 37858, 37882, 37885,
- 37903, 37940, 37951, 37973, 37995, 38002, [11986, 38264], 38310, 38313, 0,
- 38324, 38333, 38362, [11983, 11990, 38429], 38465, 38488, 38532, 38564,
- 38569, 38610, 195060, 38622, 38633, 38641, 38658, 38665, 38746, 38755,
- 38766, 38771, 38810, 38818, {f: 2, c: 38837}, 38873, 38878, 38900, 38922,
- 38926, 38942, 38947, 38955, 38974, {f: 2, c: 38994}, 39001, 39020, 39096,
- 39098, 39103, 39112, 39141, {f: 2, c: 39218}, 39232, 39245, 39260, 39263,
- 39345, {f: 2, c: 39353}, 39369, 39426, 39446, 39460, 39463,
- {f: 2, c: 39469}, 39478, 39480, 39498, 39510, {f: 2, c: 39605}, 39673,
- 39683, 39712, {f: 2, c: 39731}, 39795, 39801, 39847, 39873, 39879, 39895,
- 39911, 39915, 39927, 39930, 39933, 39947, 39975, 39978, 39990, 40001,
- 40019, 40035, 40048, 40055, 40194, 40258, 40263, 40291, 40297, 40316,
- 40318, 40333, 40369, 40387, 40391, 40406, 40415, 40427, 40436, 40469,
- 40477, 40612, 40616, 40620, 40679, 40686, 40720, 40722, 40727, 40729,
- 40751, 40759, 40761, 40769, 40773, 40791, 40808, 40817, 40821, 40848,
- 40852, 40866, 0, 13317, 194564, 22048, 24267, 11925, 0, 144954, 0, 28665,
- 28390, 29107, [11940, 64073], {s: 4}, [11980, 64102], 0, 23986, 0, 20435,
- 20697, 20720, 20931, 22134, 27220, 27905, 28112, 28226, 28377, 29668,
- 29729, 30060, 30801, 34805, 144382, 29608, 15091, 13531, 17420, 16010, 0,
- 0, 19432, 0, 16090, 15138, 0, 17786, 16531, 0, 18021, 16643, 17043, 18094,
- 13448, 140809, {f: 3, c: 63584}, 63610, 63615, {s: 23}, {f: 2, c: 8836},
- {f: 2, c: 8842}, 8713, 0, {f: 2, c: 8965}, {s: 9}, {f: 2, c: 8741},
- {s: 14}, 8802, 0, 8773, 8776, {f: 2, c: 8822}, {s: 4}, 8487, {s: 209},
- {f: 2, c: 8922}, 8533, 8984, {f: 2, c: 7742}, {f: 2, c: 504}, 470, 472,
- 474, 476, 260, 728, 317, 346, 350, 356, 377, 379, 261, 731, 318, 347, 711,
- 351, 357, 378, 733, 380, 340, 258, 313, 262, 268, 280, 270, 323, 327, 336,
- 344, 368, 354, 341, 259, 314, 263, 269, 281, 271, 273, 324, 328, 337, 345,
- 369, 355, 729, 264, 284, 292, 308, 348, 364, 265, 285, 293, 309, 349, 365,
- 625, 651, 638, 620, 622, 633, 648, 598, 627, 637, 642, 656, 635, 621, 607,
- 626, 669, 654, 609, 624, 641, 295, 661, 660, 614, 664, 450, 595, 599, 644,
- 608, 403, 616, 649, 600, 604, 606, 592, 623, 650, 612, 594, 653, 613, 674,
- 673, 597, 657, 634, 615, 865, 712, 716, 721, 8255, 783, {f: 5, c: 741}, 0,
- 0, 805, 812, 825, 796, {f: 2, c: 799}, 829, 809, 815, 734, 804, 816, 828,
- 820, {f: 2, c: 797}, {f: 2, c: 792}, 810, {f: 2, c: 826}, 794, {s: 3},
- {f: 2, c: 610}, 618, 628, 630, 632, 640, 655, 665, 668, 671, 688, 690, 695,
- 704, {f: 2, c: 736}, {s: 6}, 8862, {s: 287}, 12348, 12543, 0,
- {f: 2, c: 12310}, 9838, 9835, {f: 2, c: 10548}, 10687, 0, 12448, 0,
- {f: 2, c: 10746}, {s: 13}, 962, {f: 10, c: 9461}, {f: 2, c: 9750}, 9649,
- {f: 10, c: 12784}, 0, {f: 6, c: 12794}, {f: 15, c: 9150}, 0, 0, 10003, 0,
- 9251, 9166, {f: 4, c: 9680}, {f: 2, c: 8263}, 0, 8273, 8258,
- {f: 16, c: 12688}, {s: 13}, {f: 2, c: 9136}, {f: 12, c: 9842},
- {f: 2, c: 12441}, 8413, {s: 450}, 20296, 20319, 20330, 20332, 20494, 20504,
- 20545, 20722, 20688, 20742, 20739, 20789, 20821, 20823, 13493, 20938,
- 20962, 21079, 21196, 21206, 21243, 21276, 21347, 21405, 21522, 21631,
- 21640, 21840, 21889, 21933, 21966, 22075, 22174, 22185, 22195, 22391,
- 22396, 135963, 22479, 22500, 22628, 22665, 136302, 22738, 22752, 34369,
- 22923, 22930, 22979, 23059, 23143, 23159, 23172, 23236, 137405, 23421,
- 23443, 23570, 64060, 136884, 23674, 23695, 23711, 23715, 23722, 23760,
- 138804, 23821, 23879, 23937, 23972, 23975, 24011, 24158, 24313, 24320,
- 24322, 24355, 24381, 24404, 24445, 24589, 24596, 24600, 24629, 24647,
- 24733, 24788, 24797, 24875, 25020, 25017, 25122, 25178, 25199, 25302,
- 25468, 25573, 25721, 25796, 25808, 25897, 26013, 26170, 26146, 26155,
- 26160, 26163, 26184, 143812, {f: 2, c: 26231}, 26253, 26299, 26331, 26344,
- 26439, 26497, 26515, 26520, 26523, 26620, 26653, 26787, 26890, 26953,
- 144836, 26946, 26980, 27045, 27087, 15286, 15299, 27113, 27125, 145215,
- 27195, 145251, 27284, 27301, 15375, 27419, 27436, 27495, 27561, 27565,
- 27607, 27647, 27653, 27764, 27800, 27899, 27846, 27953, 27961, 27967,
- 27992, 28052, 28074, 28123, 28125, 28228, 28254, 28337, 28353, 28432,
- 28505, 28513, 28542, 28556, 28576, 28604, 28615, 28618, 28656, 28750,
- 28789, 28836, 28900, 28971, 28958, 28974, 29009, 29032, 29061, 29063,
- 29114, 29124, 29205, 15935, 29339, 149489, 29479, 29520, 29542, 29602,
- 29739, 29766, 29794, 29805, 29862, 29865, 29897, 29951, 29975, 16242,
- 30158, 30210, 30216, 30308, 30337, 30365, 30378, 30390, 30414, 30420,
- 30438, 30449, 30474, 30489, {f: 2, c: 30541}, 30586, 30592, 30612, 30688,
- 152718, 30787, 30830, 30896, 152846, 30893, 30976, 31004, 31022, 31028,
- 31046, 31097, 31176, 153457, 31188, 31198, 31211, 31213, 31365, 154052,
- 31438, 31485, 31506, 31533, 31547, 31599, 31745, 31795, 155041, 31853,
- 31865, 31887, 31892, 31904, 31957, 32049, 32092, 32131, 32166, 32194,
- 32296, 32663, 32731, 32821, 32823, 32970, 32992, 33011, 33120,
- {f: 2, c: 33127}, 33133, 33211, 33226, 33239, 17499, 33376, 33396, 158463,
- 33441, {f: 2, c: 33443}, 33449, 33471, 33493, 33533, 33536, 33570, 33581,
- 33594, 33607, 33661, 33703, 33743, 33745, 33761, 33793, 33798, 33887,
- 33904, 33907, 33925, 33950, 33978, 159296, 34098, 34078, 34095, 34148,
- 34170, 34188, 34210, 34251, 34285, 34303, {f: 2, c: 34308}, 34320, 159988,
- 34328, 34360, 34391, 34402, 17821, 34421, 34488, 34556, 34695, 17898,
- 34826, 34832, 35022, 161412, 35122, 35129, 35136, 35220, 35318, 35399,
- 35421, 35425, 35445, 35536, 35654, 35673, 35689, 35741, 35913, 35944,
- 36271, 36305, 36311, 36387, 36413, 36475, 164471, 18500, 36602, 36638,
- 36653, 36692, 164813, 36840, 36846, 36872, 36909, 37015, 37043, 37054,
- {f: 2, c: 37060}, 37063, 37103, 37140, 37142, {f: 2, c: 37154}, 37167,
- 37172, 37251, 37361, 37705, {f: 2, c: 37732}, 37795, 37855, 37892, 37939,
- 37962, 37987, 38001, 38286, 38303, 38316, 38326, 38347, 38352, 38355,
- 18864, 38366, 38565, 38639, 38734, 38805, 38830, 38842, 38849, 38857,
- 38875, 38998, 39143, 39256, 39427, 39617, 39619, 39630, 39638, 39682,
- 39688, 19479, 39725, 39774, 39782, 39812, 39818, 39838, 39886, 39909,
- 39928, 39971, {f: 2, c: 40015}, 40037, {f: 2, c: 40221}, 40259, 40274,
- 40330, 40342, 40384, 40364, 40380, 172432, 40423, 40455, 40606, 40623,
- 40855, 131209, 19970, 19983, 19986, 20009, 20014, 20039, 131234, 20049,
- 13318, 131236, 20073, 20125, 13356, 20156, 20163, 20168, 20203, 20186,
- 20209, 20213, 20246, 20324, 20279, 20286, 20312, 131603, {f: 2, c: 20343},
- 20354, 20357, 20454, 20402, 20421, 20427, 20434, 13418, 20466, 20499,
- 20508, 20558, 20563, 20579, 20643, 20616, {f: 2, c: 20626}, 20629, 20650,
- 131883, 20657, {f: 2, c: 20666}, 20676, 20679, 20723, 131969, 20686,
- 131953, 20692, 20705, 13458, 132089, 20759, 132170, 20832, 132361, 20851,
- 20867, 20875, 13500, 20888, 20899, 20909, 13511, 132566, 20979, 21010,
- 21014, 132943, 21077, 21084, 21100, 21111, 21124, 21122, 133127, 21144,
- 133178, 21156, {f: 2, c: 21178}, 21194, 21201, 133305, 21239, 21301, 21314,
- 133500, 133533, 21351, 21370, 21412, 21428, 133843, 21431, 21440, 133917,
- {f: 2, c: 13661}, 21461, 13667, 21492, 21540, 21544, 13678, 21571, 21602,
- 21612, 21653, 21664, 21670, 21678, 21687, 21690, 21699, 134469, 21740,
- 21743, 21745, 21747, {f: 2, c: 21760}, 21769, 21820, 21825, 13734, 21831,
- 13736, 21860, 134625, 21885, 21890, 21905, 13765, 21970, 134805, 134765,
- 21951, 21961, 21964, 21969, 21981, 13786, 21986, 134756, 21993, 22056,
- 135007, 22023, 22032, 22064, 13812, 22077, 22080, 22087, 22110, 22112,
- 22125, 13829, 22152, 22156, 22173, 22184, 22194, 22213, 22221, 22239,
- 22248, {f: 2, c: 22262}, 135681, 135765, 22313, 135803, {f: 2, c: 22341},
- 22349, 135796, 22376, 22383, {f: 3, c: 22387}, 22395, 135908, 135895,
- 22426, {f: 2, c: 22429}, 22440, 22487, 135933, 22476, 135990, 136004,
- 22494, 22512, 13898, 22520, 22523, 22525, 22532, 22558, 22567, 22585,
- 136132, 22601, 22604, 22631, {f: 2, c: 22666}, 22669, {f: 2, c: 22671},
- 22676, 22685, 22698, 22705, 136301, 22723, 22733, 22754, {f: 2, c: 22771},
- {f: 2, c: 22789}, 22797, 22804, 136663, 13969, 22845, 13977, 22854, 13974,
- 158761, 22879, 136775, {f: 2, c: 22901}, 22908, 22943, 22958, 22972, 22984,
- 22989, 23006, 23015, 23022, 136966, 137026, 14031, 23053, 23063, 23079,
- 23085, 23141, 23162, 23179, 23196, {f: 2, c: 23199}, 23202, 23217, 23221,
- 23226, 23231, 23258, 23260, 23269, 23280, 23278, 23285, 23304, 23319,
- 23348, 23372, 23378, 23400, 23407, 23425, 23428, 137667, 23446, 23468,
- {f: 2, c: 14177}, 23502, 23510, 14188, 14187, 23537, 23549, 14197, 23555,
- 23593, 138326, 23647, {f: 2, c: 23655}, 23664, 138541, 138565, 138616,
- 138594, 23688, 23690, 14273, 138657, 138652, 23712, 23714, 23719, 138642,
- 23725, 23733, 138679, 23753, 138720, 138803, 23814, 23824, 23851, 23837,
- 23840, 23857, 23865, 14312, 23905, 23914, 14324, 23920, 139038, 14333,
- 23944, 14336, 23959, 23984, 23988, 139126, 24017, 24023, 139258, 24036,
- 24041, 14383, 14390, 14400, 24095, 24126, 24137, 14428, 24150, 14433,
- {f: 2, c: 24173}, 139643, 24229, 24236, 24249, 24262, 24281, 140062, 24317,
- 24328, 140205, 24350, 24391, 24419, 24434, 24446, 24463, 24482, 24519,
- 24523, {f: 3, c: 24530}, 24546, {f: 2, c: 24558}, 24563, 14615, 24610,
- 24612, 14618, 24652, 24725, 24744, 141043, 24753, 24766, 24776, 24793,
- 24814, 24821, 24848, 24857, 24862, 24890, 14703, 24897, 24902, 24928,
- 141403, {f: 2, c: 24978}, 24983, 24997, 25005, 141483, 25045, 25053, 25077,
- 141711, 25123, 25170, 25185, 25188, 25211, 25197, 25203, 25241, 25301,
- 142008, 25341, 25347, 25360, {f: 2, c: 142159}, 25394, 25397,
- {f: 2, c: 25403}, 25409, 25412, 25422, 142150, 25433, 142365, 142246,
- 25452, 25497, 142372, 25492, 25533, {f: 2, c: 25556}, 25568,
- {f: 2, c: 25579}, 25586, 25630, 25637, 25641, 25647, 25690, 25693, 25715,
- 25725, 25735, 25745, 25759, {f: 2, c: 25803}, 25813, 25815, 142817, 25828,
- 25855, 14958, 25871, 25876, 14963, 25886, 25906, 25924, 25940, 25963,
- 25978, 25988, 25994, 26034, 26037, 26040, 26047, 26057, 26068, 15062,
- 26105, 26108, 26116, 26120, 26145, 26154, 26181, 26193, 26190, 15082,
- 143811, 143861, 143798, 26218, {f: 2, c: 26220}, 26235, 26240, 26256,
- 26258, 15118, 26285, 26289, 26293, 15130, 15132, 15063, 26369, 26386,
- 144242, 26393, 144339, 144338, 26445, 26452, 26461, 144336, 144356, 144341,
- 26484, 144346, 26514, 144351, 33635, 26640, 26563, 26568, 26578, 26587,
- 26615, 144458, 144465, 144459, 26648, 26655, 26669, 144485, 26675, 26683,
- 26686, 26693, 26697, 26700, 26709, 26711, 15223, 26731, 26734, 26748,
- 26754, 26768, 26774, 15213, {f: 3, c: 26776}, 26780, {f: 2, c: 26794},
- 26804, 26811, 26875, 144612, 144730, 26819, 26821, 26828, 26841,
- {f: 2, c: 26852}, 26860, 26871, 26883, 26887, 15239, 144788, 15245, 26950,
- 26985, 26988, 27002, 27026, 15268, 27030, 27056, 27066, 27068, 27072,
- 27089, 144953, 144967, 144952, 27107, {f: 2, c: 27118}, 27123, 15309,
- 27124, 27134, 27153, 27162, 27165, 145180, {f: 2, c: 27186}, 27199, 27209,
- 27258, 27214, 27218, 27236, 145164, 27275, 15344, 27297, 145252, 27307,
- 27325, 27334, 27348, 27344, 27357, 145407, 145383, {f: 3, c: 27377}, 27389,
- 145444, 27403, {f: 3, c: 27407}, 145469, 27415, 15398, 27439, 27466, 27480,
- 27500, 27509, [11934, 27514], 27521, 27547, 27566, 146072, 27581,
- {f: 3, c: 27591}, 27610, {f: 2, c: 27622}, 27630, 27650, 27658, 27662,
- 27702, 146559, 27725, 27739, 27757, 27780, 27785, 15555, 27796, 27799,
- 27821, 27842, 15570, 27868, 27881, 27885, 146688, 27904, 27940,
- {f: 2, c: 27942}, 27751, 27951, 27964, 27995, 28000, 28016,
- {f: 2, c: 28032}, 28042, 28045, 28049, 28056, 146752, 146938, 146937,
- 146899, 28075, 28078, 28084, 28098, 27956, 28104, 28110, 28127, 28150,
- 28214, 28190, 15633, 28210, {f: 2, c: 28232}, {f: 2, c: 28235}, 28239,
- {f: 2, c: 28243}, 28247, 28259, 15646, 28307, 28327, 28340, 28355, 28469,
- 28395, 28409, 28411, 28426, 28428, 28440, 28453, 28470, 28476, 147326,
- 28498, 28503, 28512, 28520, 28560, 28566, 28606, 28575, 28581, 28591,
- 15716, {f: 2, c: 28616}, 28649, 147606, 28668, 28672, 28682, 28707, 147715,
- 28730, 28739, 28743, 28747, 15770, 28773, 28777, 28782, 28790, 28806,
- 28823, 147910, 28831, 28849, 147966, 28908, 28874, 28881, 28931, 28934,
- 28936, 28940, 15808, 28975, 29008, 29011, 29022, 15828, 29078, 29056,
- 29083, 29088, 29090, {f: 2, c: 29102}, 148412, 29145, 29148, 29191, 15877,
- 29236, 29241, 29250, 29271, 29283, 149033, {f: 2, c: 29294}, 29304, 29311,
- 29326, 149157, 29358, 29360, 29377, 15968, 29388, 15974, 15976, 29427,
- 29434, 29447, 29458, {f: 2, c: 29464}, 16003, 29497, 29484, 29491, 29501,
- 29522, 16020, 29547, 149654, {f: 2, c: 29550}, 29553, 29569, 29578, 29588,
- 29592, 29596, 29605, 29625, 29631, 29637, 29643, 29665, 29671, 29689,
- 29715, 29690, 29697, 29779, 29760, 29763, 29778, 29789, 29825, 29832,
- 150093, 29842, 29847, 29849, 29857, 29861, 29866, 29881, 29883, 29882,
- 29910, 29912, 29931, 150358, 29946, 150383, 29984, 29988, 29994, 16215,
- 150550, {f: 2, c: 30013}, 30016, 30024, 30032, 30034, 30066, 30065, 30074,
- {f: 2, c: 30077}, 30092, 16245, 30114, 16247, 30128, 30135,
- {f: 2, c: 30143}, 30150, 30159, 30163, 30173, {f: 2, c: 30175}, 30183,
- 30190, 30193, 30211, 30232, 30215, 30223, 16302, 151054, 30227,
- {f: 2, c: 30235}, 151095, 30245, 30248, 30268, 30259, 151146, 16329, 30273,
- 151179, 30281, 30293, 16343, 30318, 30357, 30369, 30368, {f: 2, c: 30375},
- 30383, 151626, 30409, 151637, 30440, 151842, 30487, 30490, 30509, 30517,
- 151977, 16441, 152037, 152013, 30552, 152094, 30588, 152140, 16472, 30618,
- 30623, 30626, 30628, {f: 2, c: 30686}, 30692, 30698, 30700, 30715, 152622,
- 30725, 30729, 30733, 30745, 30764, 30791, 30826, 152793, 30858, 30868,
- 30884, 30877, 30879, 30907, 30933, 30950, {f: 2, c: 30969}, 30974, 152999,
- 30992, 31003, 31013, 31050, 31064, 16645, 31079, 31090, 31125, 31137,
- 31145, 31156, 31170, 31175, {f: 2, c: 31180}, 31190, 16712, 153513, 153524,
- 16719, 31242, 31253, 31259, 16739, 31288, 31303, 31318, 31321, 31324,
- 31327, 31335, 31338, 31349, 31362, 31370, 31376, 31404, 154068, 16820,
- 31417, 31422, 16831, 31436, 31464, 31476, 154340, 154339, 154353, 31549,
- 31530, {f: 2, c: 31534}, 16870, 16883, 31615, 31553, 16878, 31573, 31609,
- 31588, 31590, 31603, 154546, 16903, 31632, 31643, 16910, 31669, 31676,
- 31685, 31690, 154699, 154724, 31700, 31702, 31706, 31722, 31728, 31747,
- 31758, 31813, 31818, 31831, 31838, 31841, 31849, 31855, 155182, 155222,
- 155237, 31910, 155234, {f: 2, c: 31926}, 155352, 31940, 155330, 31949,
- 155368, 155427, 31974, 155484, 31989, 32003, 17094, 32018, 32030, 155616,
- 155604, {f: 2, c: 32061}, 32064, 32071, 155660, 155643, 17110, 32090,
- 32106, 32112, 17117, 32127, 155671, 32136, 32151, 155744, 32157, 32167,
- 32170, 32182, 32192, 32215, 32217, 32230, 17154, 155885, 64088, 32272,
- 32279, 32285, 32295, 32300, 32325, 32373, 32382, {f: 2, c: 32390}, 17195,
- 32410, 17219, 32572, 32571, 32574, 32579, 13505, 156272, 156294,
- {f: 2, c: 32611}, 32621, {f: 2, c: 32637}, 32656, 20859, 146702, 32662,
- 32668, 32685, 156674, 32707, 32719, 32739, 32754, 32778, 32776, 32790,
- 32812, 32816, 32835, 32870, 32891, 32921, 32924, 32932, 32935, 32952,
- 157310, 32965, 32981, 32998, 33037, 33013, 33019, 17390, 33077, 33054,
- 17392, 33060, 33063, 33068, 157469, 33085, 17416, 33129, 17431, 17436,
- 33157, 17442, 33176, 33202, 33217, 33219, 33238, 33243, 157917, 33252,
- 157930, 33260, 33277, 33279, 158063, 33284, 158173, 33305, 33314, 158238,
- 33340, 33353, 33349, 158296, 17526, 17530, 33367, 158348, 33372, 33379,
- 158391, 17553, 33405, 33407, 33411, 33418, 33427, {f: 2, c: 33447}, 33458,
- 33460, 33466, 33468, 33506, 33512, 33527, {f: 2, c: 33543}, 33548, 33620,
- 33563, 33565, 33584, 33596, 33604, 33623, 17598, 17620, 17587,
- {f: 2, c: 33684}, 33691, 33693, 33737, 33744, 33748, 33757, 33765, 33785,
- 33813, 158835, 33815, 33849, 33871, {f: 2, c: 33873}, {f: 2, c: 33881},
- 33884, 158941, 33893, 33912, 33916, 33921, 17677, 33943, 33958, 33982,
- 17672, {f: 2, c: 33998}, 34003, 159333, 34023, 34026, 34031, 34033, 34042,
- 34075, {f: 2, c: 34084}, 34091, 34127, 34159, 17731, 34129,
- {f: 2, c: 34145}, 159636, 34171, 34173, 34175, 34177, 34182, 34195, 34205,
- 34207, 159736, {f: 2, c: 159734}, 34236, 34247, 34250, {f: 2, c: 34264},
- 34271, 34273, 34278, 34294, 34304, 34321, 34334, 34337, 34340, 34343,
- 160013, 34361, 34364, 160057, 34368, 34387, 34390, 34423, 34439, 34441,
- {f: 2, c: 34460}, 34481, 34483, 34497, 34499, 34513, 34517, 34519, 34531,
- 34534, 17848, 34565, 34567, 34574, 34576, 34591, 34593, 34595, 34609,
- 34618, 34624, 34627, 34641, 34648, {f: 2, c: 34660}, 34674, 34684, 160731,
- 160730, 34727, 34697, 34699, 34707, 34720, 160766, 17893, 34750, 160784,
- 34753, 34766, 34783, 160841, 34787, {f: 2, c: 34789}, 34794, 34835, 34856,
- 34862, 34866, 34876, 17935, 34890, 34904, 161301, 161300, 34921, 161329,
- 34927, 34976, 35004, 35008, 161427, 35025, 35027, 17985, 35073, 161550,
- 35127, 161571, 35138, 35141, 35145, 161618, 35170, 35209, 35216, 35231,
- 35248, 35255, 35288, 35307, 18081, 35315, 35325, 35327, 18095, 35345,
- 35348, 162181, 35361, 35381, 35390, 35397, 35405, 35416, 35502, 35472,
- 35511, 35543, 35580, 162436, 35594, 35589, 35597, 35612, 35629, 18188,
- 35665, 35678, 35702, 35713, 35723, {f: 2, c: 35732}, 35897, 162739, 35901,
- 162750, 162759, 35909, 35919, 35927, 35945, 35949, 163000, 35987, 35986,
- 35993, 18276, 35995, 36054, 36053, 163232, 36081, 163344, 36105, 36110,
- 36296, 36313, 36364, 18429, 36349, 36358, 163978, 36372, 36374,
- {f: 2, c: 36385}, 36391, 164027, 18454, 36406, 36409, 36436, 36450, 36461,
- 36463, 36504, 36510, 36533, 36539, 164482, 18510, 164595, 36608, 36616,
- 36651, 36672, 36682, 36696, 164876, 36772, 36788, 164949, 36801, 36806,
- 64036, 36810, 36813, 36819, 36821, 36849, 36853, 36859, 36876, 36919,
- 165227, 36931, 36957, {f: 2, c: 165320}, 36997, 37004, 37008, 37025, 18613,
- 37040, 37046, 37059, 37064, 165591, 37084, 37087, 165626, 37110, 37106,
- 37120, 37099, {f: 2, c: 37118}, 37124, 37126, 37144, 37150, 37175, 37177,
- {f: 2, c: 37190}, 37207, 37209, 37236, 37241, 37253, 37299, 37302,
- {f: 2, c: 37315}, 166217, 166214, 37356, 37377, {f: 2, c: 37398}, 166251,
- 37442, 37450, 37462, 37473, 37477, 37480, 166280, {f: 2, c: 37500}, 37503,
- 37513, 37517, 37527, 37529, 37535, 37547, {f: 2, c: 166330}, 37554,
- {f: 2, c: 37567}, 37574, 37582, 37605, 37649, 166430, 166441, 37623, 37673,
- 166513, 166467, 37713, 37722, 37739, 37745, 37747, 37793, 166553, 166605,
- 37768, 37771, 37775, 37790, 37877, 166628, 166621, 37873, 37831, 37852,
- 37863, 37897, {f: 2, c: 37910}, 37883, 37938, 37947, 166849, 166895, 37997,
- 37999, 38265, 38278, {f: 2, c: 38284}, 167184, 167281, 38344, 167419,
- 167455, 38444, {f: 2, c: 38451}, 167478, 38460, 38497, 167561, 38530,
- 167659, 38554, 167730, 18919, 38579, 38586, 38589, 18938, 167928, 38616,
- 38618, 38621, 18948, 38676, 38691, 18985, 38710, 38721, 38727, 38743,
- 38747, 38762, 168608, 168625, 38806, 38814, {f: 2, c: 38833}, 38846, 38860,
- 38865, 38868, 38872, 38881, 38897, 38916, 38925, 38932, 38934, 19132,
- 169104, {f: 2, c: 38962}, 38949, 38983, 39014, 39083, 39085, 39088, 169423,
- 39095, {f: 2, c: 39099}, 39106, 39111, 39115, 39137, 39139, 39146,
- {f: 2, c: 39152}, 39155, 39176, 19259, 169712, {f: 2, c: 39190}, 169753,
- {f: 3, c: 39194}, 169808, 39217, {f: 3, c: 39226}, 39233, 39238, 39246,
- 39264, 39331, 39334, 39357, 39359, 39363, 39380, 39385, 39390, 170182,
- 39408, 39417, 39420, 39434, 39441, 39450, 39456, 39473, 39492, 39500,
- 39512, 19394, 39599, 19402, 39607, 19410, 39609, 170610, 39622, 39632,
- 39634, 39637, 39648, 39653, 39657, 39692, 39696, 39698, 39702, 39708,
- 39723, 39741, 19488, 39755, 39779, 39781, {f: 2, c: 39787},
- {f: 2, c: 39798}, 39846, 39852, 171483, 39858, 39864, 39870, 39923, 39896,
- 39901, 39914, 39919, 39918, 171541, 171658, 171593, 39958,
- {f: 3, c: 39960}, 39965, 39970, 39977, 171716, 39985, 39991, 40005, 40028,
- 171753, {f: 2, c: 40009}, 171739, 40020, 40024, 40027, 40029, 40031,
- {f: 3, c: 40041}, {f: 2, c: 40045}, 40050, 40053, 40058, 40166, 40178,
- 40203, [171982, 171991], 40209, {f: 2, c: 40215}, 172079, 19652, 172058,
- 40242, 19665, 40266, 40287, 40290, 172281, 172162, 40307, {f: 2, c: 40310},
- 40324, 40345, 40353, 40383, 40373, 40377, 40381, 40393, 40410, 40416,
- 40419, 19719, 40458, 40450, 40461, 40476, 40571, 139800, 40576, 40581,
- 40603, 172940, 40637, 173111, 40671, 40703, 40706, 19831, 40707, 40762,
- 40765, 40774, 40787, 40789, 40792, 173553, 40797, 173570, 40809, 40813,
- 40816, 173746, 11948, 13844, 14509, 15820, 16348, 17854, 17936, 19326,
- 19512, 19681, 19980, {f: 2, c: 20003}, 20089, 20211, 20236, 20249, 20267,
- 20270, 20273, 20356, 20382, 20407, 20484, 20492, 20556, 20575, 20578,
- 20599, 20622, 20638, 20642, 20675, 20712, 20721, 20734, 20743,
- {f: 3, c: 20748}, 20787, 20792, 20852, 20868, 20920, 20922, 20936, 20943,
- 20945, {f: 2, c: 20947}, 20952, 20959, 20997, 21030, 21032, 21035,
- {f: 2, c: 21041}, 21045, 21052, 21082, 21088, 21102, {f: 2, c: 21112},
- 21130, 21132, 21217, 21225, 21233, 21251, 21265, 21279, 21293, 21298,
- 21309, 21349, 21357, 21369, 21374, 21396, 21401, 21418, 21423, 21434,
- 21441, {f: 2, c: 21444}, 21472, 21523, 21546, 21553, {f: 2, c: 21556},
- 21580, 21671, 21674, 21681, 21691, 21710, 21738, 21756, 21765, 21768,
- 21781, 21799, 21802, 21814, 21841, 21862, 21903, 21906, 21908, 21924,
- 21938, 21955, 21958, 21971, 21979, 21996, 21998, 22001, 22006, 22008,
- 22021, 22029, {f: 2, c: 22033}, 22060, 22069, 22073, 22093, 22100, 22149,
- 22175, 22182, 22199, 22220, 22223, 22233, 22241, 22251, 22253, 22257,
- 22279, 22284, {f: 2, c: 22298}, 22301, 22316, 22318, {f: 2, c: 22333},
- 22367, 22379, 22381, 22394, 22403, 22423, 22446, 22485, 22503, 22541,
- 22566, 22605, 22607, 22623, 22637, 22655, 22657, 22680, 22716, 22815,
- 22819, 22873, 22905, 22935, 22959, 22963, 23007, 23025, 23032, 23218,
- 23224, 23274, 23286, 23323, 23325, 23329, 23352, 23479, 23511, 23520,
- 23583, 23594, 23596, 23606, 23641, 23644, 23661, 23773, 23809, 23860,
- 23869, 23897, 23934, 23939, 24007, 24057, 24104, 24114, 24117, 24155,
- 24168, 24170, 24183, 24192, 24203, 24243, 24253, 24273, {f: 2, c: 24276},
- 24397, 24492, 24554, 24583, 24649, 24660, 24679, 24763, 24772, 24829,
- 24842, 24854, 24874, 24886, 24926, 24932, 24955, 24957, 24959, 24989,
- 25016, 25052, 25058, 25061, 25064, 25092, 25095, 25137, 25145, 25149,
- 25210, 25232, 25256, 25306, 25332, 25366, 25386, 25398, 25414, 25419,
- 25427, 25457, 25461, 25471, 25474, 25482, {f: 2, c: 25518}, 25578,
- {f: 2, c: 25592}, 25618, 25624, 25632, 25636, 25642, 25653, 25661, 25663,
- 25682, 25695, 25716, 25744, {f: 2, c: 25752}, 25772, 25779, 25837, 25840,
- 25883, 25887, 25902, 25929, 25952, 26002, 26005, 26036, 26046, 26056,
- 26062, 26064, 26079, 26238, {f: 2, c: 26251}, 26291, 26304, 26319, 26405,
- 26421, 26453, 26496, 26511, 26513, 26532, 26545, 26549, 26558, 26664,
- 26758, 26859, 26869, 26903, 26931, 26936, 26971, 26981, 27048, 27051,
- 27055, 27109, 27121, 27210, 27221, 27239, 27249, 27311, {f: 2, c: 27336},
- 27395, 27451, 27455, {f: 2, c: 27517}, 27568, 27639, 27641, 27652, 27657,
- 27661, 27692, 27722, 27730, 27732, 27769, 27820, 27828, 27858, 28001,
- 28028, 28089, 28144, 28229, 28275, 28283, 28285, 28297, 28348,
- {f: 2, c: 28378}, 28454, 28457, 28464, 28551, 28573, 28590, 28599, 28685,
- 28704, 28745, 28824, 28848, {f: 2, c: 28885}, 28997, 29106, 29172, 29207,
- 29215, 29251, {f: 2, c: 29263}, 29274, 29280, 29288, 29303, 29316, 29385,
- 29413, 29428, 29442, 29451, 29470, 29474, {f: 2, c: 29498}, 29517, 29528,
- 29543, 29810, 29871, 29919, 29924, 29940, 29947, 29974, 29985, 30015,
- 30046, 30105, 30116, 30145, 30148, 30156, 30167, 30172, 30177, 30191,
- 30212, 30220, 30237, 30258, 30264, 30277, 30282, 30303, 30381, 30397,
- 30425, 30443, 30448, 30457, 30464, 30478, 30498, 30504, 30511, 30521,
- 30526, 30533, 30538, 30543, 30558, 30564, 30567, 30572, 30596,
- {f: 2, c: 30604}, 30614, 30631, 30639, 30647, 30654, 30665, 30673, 30681,
- 30705, 30775, 30812, 30846, 30872, 30881, 30897, 30899, 30921, 30931,
- 30988, 31007, {f: 2, c: 31015}, 31039, 31042, 31060, 31083, 31100, 31147,
- 31172, 31210, 31234, 31244, 31280, 31290, 31300, 31360, 31366, 31380,
- 31413, 31421, 31486, 31531, 31607, 31648, 31660, 31664, 31720, 31730,
- 31736, 31740, 31742, 31753, 31784, 31791, 31810, {f: 2, c: 31826},
- {f: 3, c: 31835}, 31858, 31869, 31879, 31902, 31930, 31943, 31955, 31962,
- 32060, 32077, 32130, 32133, 32141, 32145, 32158, 32179, 32185, 32208,
- 32229, {f: 2, c: 32245}, 32303, 32310, 32324, 32367, 32376, 32385, 32573,
- 32603, 32605, 32613, 32625, {f: 2, c: 32639}, 32651, 32674,
- {f: 3, c: 32765}, 32775, 32781, 32798, 32825, 32904, 32910, 32975, 32980,
- 33005, 33008, 33015, 33018, 33022, 33027, 33047, 33072, 33111, 33135,
- 33139, 33163, 33168, 33179, 33182, 33227, 33237, {f: 2, c: 33245}, 33249,
- 33263, 33270, 33280, 33291, {f: 2, c: 33299}, 33306, 33338, 33348, 33389,
- 33412, 33417, 33425, 33450, 33456, 33488, 33514, 33519, 33526, 33622,
- 33656, 33784, 33788, 33880, 33939, 33969, 33981, 34043, 34118, 34134,
- 34141, 34181, 34200, 34370, 34374, 34496, 34580, 34594, 34606, 34617,
- 34653, 34683, 34700, 34702, {f: 2, c: 34711}, 34718, 34723, 34734, 34751,
- 34761, 34778, 34840, 34843, 34861, 34874, 34885, 34891, 34894, 34901,
- 34906, 34926, {f: 3, c: 34970}, 35021, 35040, 35055, {f: 2, c: 35086},
- 35110, 35125, 35162, 35164, 35179, 35184, 35196, 35237, 35253, 35260,
- 35285, 35401, 35415, 35431, 35454, 35462, 35478, 35510, 35529, 35537,
- 35549, 35564, 35573, 35590, 35599, 35601, 35653, 35666, 35693, 35704,
- 35708, 35710, 35717, 35743, 35915, 35923, 35963, 36026, 36037, 36041,
- 36050, 36076, 36085, 36087, 36097, 36099, 36119, 36124, 36206, 36241,
- 36255, 36267, 36274, 36309, 36327, {f: 2, c: 36337}, 36340, 36353, 36363,
- 36390, 36401, {f: 2, c: 36416}, 36429, 36431, 36444, 36449, 36457, 36465,
- 36469, 36471, 36489, 36496, 36501, 36506, 36519, 36521, 36525, 36584,
- 36592, 36615, 36632, 36645, 36647, 36652, 36661, 36666, 36675, 36679,
- 36689, 36693, {f: 3, c: 36768}, 36773, 36868, 36891, 36911, 36940, 36955,
- 36976, 36980, 36985, 37003, 37016, 37024, 37042, 37053, 37065, 37104,
- 37125, 37157, 37210, 37223, 37242, 37258, 37265, 37269, 37296, 37307,
- 37309, 37314, 37317, 37376, 37385, 37411, 37494, 37518, 37551,
- {f: 2, c: 37563}, 37569, 37571, 37573, 37576, 37652, 37683, 37686, 37720,
- 37759, 37762, 37770, 37819, 37836, 37862, 37881, 37890, {f: 2, c: 37901},
- 37934, 37964, 38280, 38305, 38335, 38342, 38345, {f: 2, c: 38353}, 38368,
- 38372, 38374, 38436, 38449, 38456, 38461, 38484, 38516, 38523, 38527,
- 38529, 38531, 38537, 38550, 38574, 38659, 38683, {f: 2, c: 38689}, 38696,
- 38705, 38759, 38774, 38781, 38783, 38809, 38815, 38828, 38841, 38861,
- 38880, 38895, 38919, 38950, 38958, {f: 2, c: 39010}, 39092, 39109, 39170,
- 39185, 39189, 39221, 39240, 39252, 39262, 39393, 39436, 39440, 39459,
- 39489, 39505, {f: 2, c: 39613}, 39681, 39689, 39691, {f: 2, c: 39693},
- 39705, 39733, 39752, 39765, 39784, 39808, 39814, 39824, 39837, 39856,
- 39871, 39880, 39935, 39938, 39964, 39989, 40004, 40022, 40033, 40040,
- 40240, 40253, 40298, 40315, 40421, 40425, 40435, 40570, {f: 3, c: 40578},
- 40624, 40676, 40688, 40690, 40713, 40719, 40724, 40731, 40738, 40742,
- {f: 2, c: 40746}, 40756, 40794, 40815, 40862, 40869, 131317, 151044,
- 151538, 163187, 194581, 194630, 194713, 194726, 194789, 195038, 13790,
- {s: 4}, 172722, 0, 0, 131416, {s: 4}, 132529, 0, 0, 132844, {s: 6}, 134488,
- {s: 21}, 154060, {s: 9}, 14756, 14776, 142914, 0, 0, 14940, 0, 0, 143339,
- 0, 0, 162228, 0, 15044, 15051, {s: 5}, 14981, {s: 8}, 15347, 27384, {s: 5},
- 15665, {s: 9}, 147531, 0, 15936, 14497, {s: 34}, 158878, {s: 12}, 18207,
- 162876, {s: 4}, 18462, {s: 71}, 39709, 39724, 20482, 20958, 21255, 23532,
- 63784, 26142, 63785, 28746, 64021, 21857, 27706, 31328, 156492, 34819,
- 38315, 38741, 171581, 173594],
- 'Adobe-Korea1': [{f: 95, c: 32}, 8361, 8208, 169, 0, 0, [12288, 12644],
- {f: 2, c: 12289}, 12539, 8229, [8230, 8943], 168, 12291, {f: 2, c: 8211},
- 8214, 65340, 65374, {f: 2, c: 8216}, {f: 2, c: 8220}, {f: 2, c: 12308},
- {f: 10, c: 12296}, 177, 215, 247, 8800, {f: 2, c: 8804}, 8734, 8756, 176,
- {f: 2, c: 8242}, 8451, 8491, {f: 2, c: 65504}, 65509, 9794, 9792, 8736,
- 8869, 8978, 8706, 8711, 8801, 8786, 167, 8251, 9734, 9733, 9675, 9679,
- 9678, 9671, 9670, 9633, 9632, 9651, 9650, 9661, 9660, 8594,
- {f: 2, c: 8592}, {f: 2, c: 8595}, 12307, 171, 187, 8730, 8765, 8733, 8757,
- {f: 2, c: 8747}, 8712, 8715, {f: 2, c: 8838}, {f: 2, c: 8834}, 8746, 8745,
- {f: 2, c: 8743}, 65506, 8658, 8660, 8704, 8707, 180, 732, 711, 728, 733,
- 730, 729, 184, 731, 161, 191, 8758, 8750, 8721, 8719, 164, 8457, 8240,
- 9665, 9664, 9655, 9654, 9828, {f: 2, c: 9824}, 9829, 9831, 9827, 9673,
- 9672, 9635, {f: 2, c: 9680}, 9618, {f: 2, c: 9636}, 9640, 9639, 9638, 9641,
- 9832, 9743, 9742, 9756, 9758, 182, {f: 2, c: 8224}, 8597, 8599, 8601, 8598,
- 8600, 9837, {f: 2, c: 9833}, 9836, 12927, 12828, 8470, 13255, 8482, 13250,
- 13272, 8481, {f: 59, c: 65281}, 65510, {f: 33, c: 65341}, 65507,
- {f: 51, c: 12593}, {f: 42, c: 12645}, {f: 10, c: 8560}, {f: 10, c: 8544},
- {f: 17, c: 913}, {f: 7, c: 931}, {f: 17, c: 945}, {f: 7, c: 963}, 9472,
- 9474, 9484, 9488, 9496, 9492, 9500, 9516, 9508, 9524, 9532, 9473, 9475,
- 9487, 9491, 9499, 9495, 9507, 9523, 9515, 9531, 9547, 9504, 9519, 9512,
- 9527, 9535, 9501, 9520, 9509, 9528, 9538, 9490, 9489, 9498, 9497, 9494,
- 9493, 9486, 9485, {f: 2, c: 9502}, {f: 2, c: 9505}, {f: 2, c: 9510},
- {f: 2, c: 9513}, {f: 2, c: 9517}, {f: 2, c: 9521}, {f: 2, c: 9525},
- {f: 2, c: 9529}, {f: 2, c: 9533}, {f: 2, c: 9536}, {f: 8, c: 9539},
- {f: 3, c: 13205}, 8467, 13208, 13252, {f: 4, c: 13219}, {f: 10, c: 13209},
- 13258, {f: 3, c: 13197}, 13263, {f: 2, c: 13192}, 13256, {f: 2, c: 13223},
- {f: 10, c: 13232}, {f: 5, c: 13184}, {f: 6, c: 13242}, {f: 5, c: 13200},
- 8486, {f: 2, c: 13248}, {f: 3, c: 13194}, 13270, 13253, {f: 3, c: 13229},
- 13275, {f: 4, c: 13225}, 13277, 13264, 13267, 13251, 13257, 13276, 13254,
- 198, 208, 170, 294, 306, 319, 321, 216, 338, 186, 222, 358, 330,
- {f: 28, c: 12896}, {f: 26, c: 9424}, {f: 15, c: 9312}, 189,
- {f: 2, c: 8531}, 188, 190, {f: 4, c: 8539}, 230, 273, 240, 295, 305, 307,
- 312, 320, 322, 248, 339, 223, 254, 359, 331, 329, {f: 28, c: 12800},
- {f: 26, c: 9372}, {f: 15, c: 9332}, 185, {f: 2, c: 178}, 8308, 8319,
- {f: 4, c: 8321}, {f: 83, c: 12353}, {f: 86, c: 12449}, {f: 6, c: 1040},
- 1025, {f: 32, c: 1046}, 1105, {f: 26, c: 1078}, {f: 2, c: 44032}, 44036,
- {f: 4, c: 44039}, {f: 8, c: 44048}, {f: 5, c: 44057}, 44064, 44068,
- {f: 2, c: 44076}, {f: 3, c: 44079}, {f: 2, c: 44088}, 44092, 44096, 44107,
- 44109, 44116, 44120, 44124, {f: 2, c: 44144}, 44148, {f: 2, c: 44151},
- 44154, {f: 2, c: 44160}, {f: 4, c: 44163}, {f: 4, c: 44169}, 44176, 44180,
- {f: 2, c: 44188}, {f: 3, c: 44191}, {f: 3, c: 44200}, 44204,
- {f: 2, c: 44207}, {f: 2, c: 44216}, {f: 3, c: 44219}, 44225, 44228, 44232,
- 44236, 44245, 44247, {f: 2, c: 44256}, 44260, {f: 2, c: 44263}, 44266,
- 44268, {f: 3, c: 44271}, 44275, {f: 2, c: 44277}, {f: 2, c: 44284}, 44288,
- 44292, 44294, {f: 2, c: 44300}, 44303, 44305, 44312, 44316, 44320, 44329,
- {f: 2, c: 44332}, {f: 2, c: 44340}, 44344, 44348, {f: 2, c: 44356}, 44359,
- 44361, 44368, 44372, 44376, 44385, 44387, {f: 2, c: 44396}, 44400,
- {f: 4, c: 44403}, {f: 3, c: 44411}, 44415, {f: 2, c: 44417},
- {f: 2, c: 44424}, 44428, 44432, {f: 2, c: 44444}, 44452, 44471,
- {f: 2, c: 44480}, 44484, 44488, {f: 2, c: 44496}, 44499, 44508, 44512,
- 44516, {f: 2, c: 44536}, 44540, {f: 3, c: 44543}, {f: 2, c: 44552}, 44555,
- 44557, 44564, {f: 2, c: 44592}, 44596, {f: 2, c: 44599}, 44602,
- {f: 2, c: 44608}, 44611, {f: 2, c: 44613}, 44618, {f: 3, c: 44620}, 44624,
- 44628, 44630, {f: 2, c: 44636}, {f: 3, c: 44639}, 44645, {f: 2, c: 44648},
- 44652, 44656, {f: 2, c: 44664}, {f: 3, c: 44667}, {f: 2, c: 44676}, 44684,
- {f: 3, c: 44732}, 44736, 44740, {f: 2, c: 44748}, {f: 3, c: 44751},
- {f: 2, c: 44760}, 44764, 44776, 44779, 44781, 44788, 44792, 44796,
- {f: 2, c: 44807}, 44813, 44816, {f: 2, c: 44844}, 44848, 44850, 44852,
- {f: 2, c: 44860}, 44863, {f: 3, c: 44865}, {f: 2, c: 44872}, 44880,
- {f: 2, c: 44892}, {f: 2, c: 44900}, 44921, 44928, 44932, 44936,
- {f: 2, c: 44944}, 44949, 44956, {f: 2, c: 44984}, 44988, 44992,
- {f: 3, c: 44999}, 45003, {f: 2, c: 45005}, 45012, 45020, {f: 2, c: 45032},
- {f: 2, c: 45040}, 45044, 45048, {f: 2, c: 45056}, 45060, 45068, 45072,
- 45076, {f: 2, c: 45084}, 45096, {f: 2, c: 45124}, 45128, 45130, 45132,
- 45134, {f: 3, c: 45139}, 45143, 45145, 45149, {f: 2, c: 45180}, 45184,
- 45188, {f: 2, c: 45196}, 45199, 45201, {f: 3, c: 45208}, 45212,
- {f: 4, c: 45215}, {f: 2, c: 45224}, {f: 5, c: 45227}, 45233,
- {f: 3, c: 45235}, 45240, 45244, {f: 2, c: 45252}, {f: 3, c: 45255},
- {f: 2, c: 45264}, 45268, 45272, 45280, 45285, {f: 2, c: 45320},
- {f: 2, c: 45323}, 45328, {f: 2, c: 45330}, {f: 2, c: 45336},
- {f: 3, c: 45339}, {f: 3, c: 45347}, 45352, 45356, {f: 2, c: 45364},
- {f: 3, c: 45367}, {f: 2, c: 45376}, 45380, 45384, {f: 2, c: 45392},
- {f: 2, c: 45396}, 45400, 45404, 45408, {f: 2, c: 45432}, 45436, 45440,
- 45442, {f: 2, c: 45448}, 45451, 45453, {f: 3, c: 45458}, 45464, 45468,
- 45480, 45516, 45520, 45524, {f: 2, c: 45532}, 45535, {f: 2, c: 45544},
- 45548, 45552, 45561, 45563, 45565, {f: 2, c: 45572}, 45576,
- {f: 2, c: 45579}, {f: 2, c: 45588}, 45591, 45593, 45600, 45620, 45628,
- 45656, 45660, 45664, {f: 2, c: 45672}, {f: 2, c: 45684}, 45692,
- {f: 2, c: 45700}, 45705, {f: 2, c: 45712}, 45716, {f: 3, c: 45720},
- {f: 2, c: 45728}, 45731, {f: 2, c: 45733}, 45738, 45740, 45744, 45748,
- {f: 2, c: 45768}, 45772, 45776, 45778, {f: 2, c: 45784}, 45787, 45789,
- 45794, {f: 3, c: 45796}, 45800, {f: 5, c: 45803}, {f: 3, c: 45811},
- {f: 5, c: 45815}, {f: 3, c: 45823}, 45828, 45832, {f: 2, c: 45840},
- {f: 3, c: 45843}, 45852, {f: 3, c: 45908}, 45912, {f: 2, c: 45915},
- {f: 2, c: 45918}, {f: 2, c: 45924}, 45927, 45929, 45931, 45934,
- {f: 2, c: 45936}, 45940, 45944, {f: 2, c: 45952}, {f: 3, c: 45955}, 45964,
- 45968, 45972, {f: 2, c: 45984}, 45992, 45996, {f: 2, c: 46020}, 46024,
- {f: 2, c: 46027}, 46030, 46032, {f: 2, c: 46036}, 46039, 46041, 46043,
- 46045, 46048, 46052, 46056, 46076, 46096, 46104, 46108, 46112,
- {f: 2, c: 46120}, 46123, 46132, {f: 2, c: 46160}, 46164, 46168,
- {f: 2, c: 46176}, 46179, 46181, 46188, 46208, 46216, 46237, 46244, 46248,
- 46252, 46261, 46263, 46265, 46272, 46276, 46280, 46288, 46293,
- {f: 2, c: 46300}, 46304, {f: 2, c: 46307}, 46310, {f: 2, c: 46316}, 46319,
- 46321, 46328, {f: 2, c: 46356}, 46360, {f: 2, c: 46363}, {f: 2, c: 46372},
- {f: 4, c: 46375}, {f: 2, c: 46384}, 46388, 46392, {f: 2, c: 46400},
- {f: 3, c: 46403}, {f: 3, c: 46411}, 46416, 46420, {f: 2, c: 46428},
- {f: 3, c: 46431}, {f: 2, c: 46496}, 46500, 46504, {f: 2, c: 46506},
- {f: 2, c: 46512}, {f: 3, c: 46515}, {f: 3, c: 46523}, 46528, 46532,
- {f: 2, c: 46540}, {f: 3, c: 46543}, 46552, 46572, {f: 2, c: 46608}, 46612,
- 46616, 46629, 46636, 46644, 46664, 46692, 46696, {f: 2, c: 46748}, 46752,
- 46756, {f: 2, c: 46763}, 46769, 46804, 46832, 46836, 46840,
- {f: 2, c: 46848}, 46853, {f: 2, c: 46888}, 46892, {f: 2, c: 46895},
- {f: 2, c: 46904}, 46907, 46916, 46920, 46924, {f: 2, c: 46932}, 46944,
- 46948, 46952, {f: 2, c: 46960}, 46963, 46965, {f: 2, c: 46972}, 46976,
- 46980, {f: 2, c: 46988}, {f: 4, c: 46991}, {f: 4, c: 46998}, 47004, 47008,
- {f: 2, c: 47016}, {f: 3, c: 47019}, {f: 2, c: 47028}, 47032, 47047, 47049,
- {f: 2, c: 47084}, 47088, 47092, {f: 2, c: 47100}, {f: 3, c: 47103},
- {f: 3, c: 47111}, 47116, 47120, {f: 2, c: 47128}, 47131, 47133,
- {f: 2, c: 47140}, 47144, 47148, {f: 2, c: 47156}, {f: 3, c: 47159}, 47168,
- 47172, 47185, 47187, {f: 2, c: 47196}, 47200, 47204, {f: 2, c: 47212},
- 47215, 47217, 47224, 47228, 47245, 47272, 47280, 47284, 47288,
- {f: 2, c: 47296}, 47299, 47301, 47308, 47312, 47316, 47325, 47327, 47329,
- {f: 2, c: 47336}, 47340, 47344, {f: 2, c: 47352}, 47355, 47357, 47364,
- 47384, 47392, {f: 2, c: 47420}, 47424, 47428, 47436, 47439, 47441,
- {f: 2, c: 47448}, 47452, 47456, {f: 2, c: 47464}, 47467, 47469,
- {f: 2, c: 47476}, 47480, 47484, {f: 2, c: 47492}, 47495, {f: 2, c: 47497},
- {f: 2, c: 47501}, {f: 2, c: 47532}, 47536, 47540, {f: 2, c: 47548}, 47551,
- 47553, {f: 2, c: 47560}, 47564, {f: 5, c: 47566}, {f: 2, c: 47576}, 47579,
- {f: 2, c: 47581}, 47585, {f: 3, c: 47587}, 47592, 47596, {f: 2, c: 47604},
- {f: 4, c: 47607}, {f: 2, c: 47616}, 47624, 47637, {f: 2, c: 47672}, 47676,
- 47680, 47682, {f: 2, c: 47688}, 47691, {f: 2, c: 47693}, {f: 3, c: 47699},
- 47704, 47708, {f: 2, c: 47716}, {f: 3, c: 47719}, {f: 2, c: 47728}, 47732,
- 47736, {f: 3, c: 47747}, 47751, 47756, {f: 2, c: 47784}, {f: 2, c: 47787},
- 47792, 47794, {f: 2, c: 47800}, 47803, 47805, 47812, 47816,
- {f: 2, c: 47832}, 47868, 47872, 47876, 47885, 47887, 47889, 47896, 47900,
- 47904, 47913, 47915, {f: 3, c: 47924}, 47928, {f: 4, c: 47931},
- {f: 2, c: 47940}, 47943, 47945, 47949, {f: 2, c: 47951}, 47956, 47960,
- 47969, 47971, 47980, 48008, 48012, 48016, 48036, 48040, 48044, 48052,
- 48055, 48064, 48068, 48072, 48080, 48083, {f: 2, c: 48120}, 48124,
- {f: 2, c: 48127}, 48130, {f: 2, c: 48136}, {f: 3, c: 48139}, 48143, 48145,
- {f: 5, c: 48148}, {f: 5, c: 48155}, {f: 2, c: 48164}, 48167, 48169, 48173,
- {f: 2, c: 48176}, 48180, 48184, {f: 2, c: 48192}, {f: 3, c: 48195}, 48201,
- {f: 2, c: 48204}, 48208, 48221, {f: 2, c: 48260}, 48264, {f: 2, c: 48267},
- 48270, {f: 2, c: 48276}, 48279, {f: 2, c: 48281}, {f: 2, c: 48288}, 48292,
- {f: 2, c: 48295}, {f: 2, c: 48304}, {f: 3, c: 48307}, {f: 2, c: 48316},
- 48320, 48324, 48333, {f: 3, c: 48335}, 48341, 48344, 48348,
- {f: 3, c: 48372}, 48376, 48380, {f: 2, c: 48388}, 48391, 48393, 48400,
- 48404, 48420, 48428, 48448, {f: 2, c: 48456}, 48460, 48464,
- {f: 2, c: 48472}, 48484, 48488, {f: 2, c: 48512}, 48516, {f: 4, c: 48519},
- {f: 2, c: 48528}, 48531, 48533, {f: 2, c: 48537}, 48540, 48548, 48560,
- 48568, {f: 2, c: 48596}, 48600, 48604, 48617, 48624, 48628, 48632, 48640,
- 48643, 48645, {f: 2, c: 48652}, 48656, 48660, {f: 2, c: 48668}, 48671,
- {f: 2, c: 48708}, 48712, 48716, 48718, {f: 2, c: 48724}, 48727,
- {f: 3, c: 48729}, {f: 2, c: 48736}, 48740, 48744, 48746, {f: 2, c: 48752},
- {f: 3, c: 48755}, {f: 3, c: 48763}, 48768, 48772, {f: 2, c: 48780},
- {f: 3, c: 48783}, {f: 2, c: 48792}, 48808, {f: 2, c: 48848}, 48852,
- {f: 2, c: 48855}, 48864, {f: 3, c: 48867}, 48876, 48897, {f: 2, c: 48904},
- {f: 2, c: 48920}, {f: 3, c: 48923}, {f: 2, c: 48960}, 48964, 48968,
- {f: 2, c: 48976}, 48981, 49044, 49072, 49093, {f: 2, c: 49100}, 49104,
- 49108, 49116, 49119, 49121, 49212, 49233, 49240, 49244, 49248,
- {f: 2, c: 49256}, {f: 2, c: 49296}, 49300, 49304, {f: 2, c: 49312}, 49315,
- 49317, {f: 2, c: 49324}, {f: 2, c: 49327}, {f: 4, c: 49331},
- {f: 2, c: 49340}, {f: 3, c: 49343}, 49349, {f: 2, c: 49352}, 49356, 49360,
- {f: 2, c: 49368}, {f: 3, c: 49371}, {f: 2, c: 49380}, 49384, 49388,
- {f: 2, c: 49396}, 49399, 49401, 49408, 49412, 49416, 49424, 49429,
- {f: 5, c: 49436}, {f: 2, c: 49443}, {f: 2, c: 49446}, {f: 2, c: 49452},
- {f: 3, c: 49455}, 49462, {f: 2, c: 49464}, 49468, 49472, {f: 2, c: 49480},
- {f: 3, c: 49483}, {f: 2, c: 49492}, 49496, 49500, {f: 2, c: 49508},
- {f: 3, c: 49511}, 49520, 49524, 49528, 49541, {f: 3, c: 49548}, 49552,
- 49556, 49558, {f: 2, c: 49564}, 49567, 49569, 49573, {f: 2, c: 49576},
- 49580, 49584, 49597, 49604, 49608, 49612, 49620, {f: 2, c: 49623}, 49632,
- 49636, 49640, {f: 2, c: 49648}, 49651, {f: 2, c: 49660}, 49664, 49668,
- {f: 2, c: 49676}, 49679, 49681, {f: 2, c: 49688}, 49692, {f: 2, c: 49695},
- {f: 2, c: 49704}, 49707, 49709, 49711, {f: 2, c: 49713}, 49716, 49736,
- {f: 2, c: 49744}, 49748, 49752, 49760, 49765, {f: 2, c: 49772}, 49776,
- 49780, {f: 2, c: 49788}, 49791, 49793, {f: 2, c: 49800}, 49808, 49816,
- 49819, 49821, {f: 2, c: 49828}, 49832, {f: 2, c: 49836}, {f: 2, c: 49844},
- 49847, 49849, {f: 2, c: 49884}, 49888, {f: 2, c: 49891}, {f: 3, c: 49899},
- 49903, 49905, 49910, {f: 2, c: 49912}, {f: 2, c: 49915}, 49920,
- {f: 2, c: 49928}, {f: 2, c: 49932}, {f: 3, c: 49939}, 49944, 49948,
- {f: 2, c: 49956}, {f: 2, c: 49960}, 49989, {f: 2, c: 50024}, 50028, 50032,
- 50034, {f: 2, c: 50040}, {f: 2, c: 50044}, 50052, 50056, 50060, 50112,
- {f: 2, c: 50136}, 50140, {f: 2, c: 50143}, 50146, {f: 2, c: 50152}, 50157,
- {f: 2, c: 50164}, 50168, 50184, 50192, 50212, 50220, 50224, 50228,
- {f: 2, c: 50236}, 50248, {f: 2, c: 50276}, 50280, 50284, {f: 2, c: 50292},
- 50297, 50304, 50324, 50332, 50360, 50364, 50409, {f: 2, c: 50416}, 50420,
- 50424, 50426, {f: 3, c: 50431}, 50444, 50448, 50452, 50460,
- {f: 2, c: 50472}, 50476, 50480, {f: 2, c: 50488}, 50491, 50493,
- {f: 2, c: 50500}, {f: 3, c: 50504}, {f: 3, c: 50508}, {f: 3, c: 50515},
- {f: 3, c: 50519}, {f: 2, c: 50525}, {f: 2, c: 50528}, 50532, 50536,
- {f: 2, c: 50544}, {f: 3, c: 50547}, {f: 2, c: 50556}, 50560, 50564, 50567,
- {f: 2, c: 50572}, 50575, 50577, 50581, {f: 2, c: 50583}, 50588, 50592,
- 50601, {f: 2, c: 50612}, {f: 2, c: 50616}, {f: 4, c: 50619},
- {f: 7, c: 50628}, 50636, 50638, {f: 2, c: 50640}, 50644, 50648,
- {f: 2, c: 50656}, 50659, 50661, {f: 3, c: 50668}, 50672, 50676,
- {f: 2, c: 50678}, {f: 6, c: 50684}, {f: 4, c: 50693}, 50700, 50704,
- {f: 2, c: 50712}, {f: 2, c: 50715}, {f: 2, c: 50724}, 50728,
- {f: 3, c: 50732}, 50736, {f: 3, c: 50739}, 50743, 50745, 50747,
- {f: 2, c: 50752}, 50756, 50760, {f: 2, c: 50768}, {f: 3, c: 50771},
- {f: 2, c: 50780}, 50784, 50796, 50799, 50801, {f: 2, c: 50808}, 50812,
- 50816, {f: 2, c: 50824}, 50827, 50829, {f: 2, c: 50836}, 50840, 50844,
- {f: 2, c: 50852}, 50855, 50857, {f: 2, c: 50864}, 50868, {f: 3, c: 50872},
- {f: 2, c: 50880}, 50883, 50885, {f: 2, c: 50892}, 50896, 50900,
- {f: 2, c: 50908}, {f: 2, c: 50912}, {f: 2, c: 50920}, 50924, 50928,
- {f: 2, c: 50936}, 50941, {f: 2, c: 50948}, 50952, 50956, {f: 2, c: 50964},
- 50967, 50969, {f: 2, c: 50976}, 50980, 50984, {f: 2, c: 50992}, 50995,
- 50997, 50999, {f: 2, c: 51004}, 51008, 51012, 51018, {f: 2, c: 51020},
- 51023, {f: 8, c: 51025}, 51036, 51040, 51048, 51051, {f: 2, c: 51060},
- 51064, {f: 3, c: 51068}, {f: 3, c: 51075}, {f: 4, c: 51079}, 51086,
- {f: 2, c: 51088}, 51092, {f: 3, c: 51094}, 51098, {f: 2, c: 51104},
- {f: 4, c: 51107}, {f: 2, c: 51116}, 51120, 51124, {f: 2, c: 51132},
- {f: 3, c: 51135}, {f: 2, c: 51144}, 51148, 51150, 51152, 51160, 51165,
- 51172, 51176, 51180, {f: 2, c: 51200}, 51204, 51208, 51210,
- {f: 2, c: 51216}, 51219, {f: 2, c: 51221}, {f: 2, c: 51228}, 51232, 51236,
- {f: 2, c: 51244}, 51247, 51249, 51256, 51260, 51264, {f: 2, c: 51272},
- {f: 2, c: 51276}, 51284, {f: 2, c: 51312}, 51316, 51320, 51322,
- {f: 2, c: 51328}, 51331, {f: 3, c: 51333}, {f: 3, c: 51339}, 51348, 51357,
- 51359, 51361, 51368, {f: 2, c: 51388}, 51396, 51400, 51404,
- {f: 2, c: 51412}, 51415, 51417, {f: 2, c: 51424}, 51428, 51445,
- {f: 2, c: 51452}, 51456, {f: 3, c: 51460}, {f: 2, c: 51468}, 51471, 51473,
- 51480, 51500, 51508, {f: 2, c: 51536}, 51540, 51544, {f: 2, c: 51552},
- 51555, 51564, 51568, 51572, 51580, {f: 2, c: 51592}, 51596, 51600,
- {f: 2, c: 51608}, 51611, 51613, {f: 2, c: 51648}, 51652, {f: 2, c: 51655},
- 51658, {f: 2, c: 51664}, 51667, {f: 2, c: 51669}, {f: 2, c: 51673},
- {f: 2, c: 51676}, 51680, 51682, 51684, 51687, {f: 2, c: 51692},
- {f: 3, c: 51695}, {f: 2, c: 51704}, 51708, 51712, {f: 2, c: 51720},
- {f: 3, c: 51723}, 51732, 51736, 51753, {f: 2, c: 51788}, 51792, 51796,
- {f: 2, c: 51804}, {f: 3, c: 51807}, 51816, 51837, 51844, 51864,
- {f: 2, c: 51900}, 51904, 51908, {f: 2, c: 51916}, 51919, 51921, 51923,
- {f: 2, c: 51928}, 51936, 51948, 51956, 51976, 51984, 51988, 51992,
- {f: 2, c: 52000}, 52033, {f: 2, c: 52040}, 52044, 52048, {f: 2, c: 52056},
- 52061, 52068, {f: 2, c: 52088}, 52124, 52152, 52180, 52196, 52199, 52201,
- {f: 2, c: 52236}, 52240, 52244, {f: 2, c: 52252}, {f: 2, c: 52257},
- {f: 3, c: 52263}, 52268, 52270, 52272, {f: 2, c: 52280}, {f: 4, c: 52283},
- {f: 2, c: 52292}, 52296, 52300, {f: 2, c: 52308}, {f: 3, c: 52311}, 52320,
- 52324, 52326, 52328, 52336, 52341, {f: 2, c: 52376}, 52380, 52384,
- {f: 2, c: 52392}, {f: 3, c: 52395}, {f: 2, c: 52404}, 52408, 52412,
- {f: 2, c: 52420}, 52423, 52425, 52432, 52436, 52452, 52460, 52464, 52481,
- {f: 2, c: 52488}, 52492, 52496, {f: 2, c: 52504}, 52507, 52509, 52516,
- 52520, 52524, 52537, 52572, 52576, 52580, {f: 2, c: 52588}, 52591, 52593,
- 52600, 52616, {f: 2, c: 52628}, 52632, 52636, {f: 2, c: 52644}, 52647,
- 52649, 52656, 52676, 52684, 52688, 52712, 52716, 52720, {f: 2, c: 52728},
- 52731, 52733, 52740, 52744, 52748, 52756, 52761, {f: 2, c: 52768}, 52772,
- 52776, {f: 2, c: 52784}, 52787, 52789, {f: 2, c: 52824}, 52828,
- {f: 3, c: 52831}, {f: 2, c: 52840}, 52843, 52845, {f: 2, c: 52852}, 52856,
- 52860, {f: 2, c: 52868}, 52871, 52873, {f: 2, c: 52880}, 52884, 52888,
- {f: 2, c: 52896}, {f: 3, c: 52899}, {f: 2, c: 52908}, 52929,
- {f: 2, c: 52964}, 52968, {f: 2, c: 52971}, {f: 2, c: 52980},
- {f: 3, c: 52983}, {f: 2, c: 52992}, 52996, 53000, {f: 2, c: 53008}, 53011,
- 53013, 53020, 53024, 53028, {f: 2, c: 53036}, {f: 3, c: 53039}, 53048,
- {f: 2, c: 53076}, 53080, 53084, {f: 2, c: 53092}, 53095, 53097,
- {f: 2, c: 53104}, 53108, 53112, 53120, 53125, 53132, 53153, 53160, 53168,
- 53188, {f: 2, c: 53216}, 53220, 53224, {f: 2, c: 53232}, 53235, 53237,
- 53244, 53248, 53252, 53265, 53272, 53293, {f: 2, c: 53300}, 53304, 53308,
- {f: 2, c: 53316}, 53319, 53321, 53328, 53332, 53336, 53344,
- {f: 2, c: 53356}, 53360, 53364, {f: 2, c: 53372}, 53377, {f: 2, c: 53412},
- 53416, 53420, {f: 2, c: 53428}, 53431, 53433, {f: 2, c: 53440}, 53444,
- {f: 2, c: 53448}, {f: 2, c: 53456}, {f: 3, c: 53459}, {f: 2, c: 53468},
- 53472, 53476, {f: 2, c: 53484}, {f: 3, c: 53487}, 53496, 53517,
- {f: 2, c: 53552}, 53556, 53560, 53562, {f: 2, c: 53568}, {f: 3, c: 53571},
- {f: 2, c: 53580}, 53584, 53588, {f: 2, c: 53596}, 53599, 53601, 53608,
- 53612, 53628, 53636, 53640, {f: 2, c: 53664}, 53668, 53672,
- {f: 2, c: 53680}, 53683, 53685, 53690, 53692, 53696, 53720, 53748, 53752,
- 53767, 53769, 53776, {f: 2, c: 53804}, 53808, 53812, {f: 2, c: 53820},
- 53823, 53825, 53832, 53852, 53860, {f: 2, c: 53888}, 53892, 53896,
- {f: 2, c: 53904}, 53909, 53916, 53920, 53924, 53932, 53937,
- {f: 2, c: 53944}, 53948, {f: 2, c: 53951}, 53954, {f: 2, c: 53960}, 53963,
- 53972, 53976, 53980, {f: 2, c: 53988}, {f: 2, c: 54000}, 54004, 54008,
- {f: 2, c: 54016}, 54019, 54021, {f: 3, c: 54028}, 54032, 54036, 54038,
- {f: 2, c: 54044}, {f: 3, c: 54047}, 54053, {f: 2, c: 54056}, 54060, 54064,
- {f: 2, c: 54072}, {f: 3, c: 54075}, {f: 2, c: 54084}, {f: 2, c: 54140},
- 54144, 54148, {f: 2, c: 54156}, {f: 3, c: 54159}, {f: 2, c: 54168}, 54172,
- 54176, {f: 2, c: 54184}, 54187, 54189, 54196, 54200, 54204,
- {f: 2, c: 54212}, {f: 2, c: 54216}, 54224, 54232, 54241, 54243,
- {f: 2, c: 54252}, 54256, 54260, {f: 2, c: 54268}, 54271, 54273, 54280,
- 54301, 54336, 54340, 54364, 54368, 54372, 54381, 54383, {f: 2, c: 54392},
- 54396, {f: 2, c: 54399}, 54402, {f: 2, c: 54408}, 54411, 54413, 54420,
- 54441, 54476, 54480, 54484, 54492, 54495, 54504, 54508, 54512, 54520,
- 54523, 54525, 54532, 54536, 54540, {f: 2, c: 54548}, 54551,
- {f: 2, c: 54588}, 54592, 54596, {f: 2, c: 54604}, 54607, 54609,
- {f: 2, c: 54616}, 54620, 54624, 54629, {f: 2, c: 54632}, 54635, 54637,
- {f: 2, c: 54644}, 54648, 54652, {f: 2, c: 54660}, {f: 3, c: 54663}, 54672,
- 54693, {f: 2, c: 54728}, 54732, 54736, 54738, {f: 2, c: 54744}, 54747,
- 54749, {f: 2, c: 54756}, 54760, 54764, {f: 2, c: 54772}, 54775, 54777,
- {f: 2, c: 54784}, 54788, 54792, {f: 2, c: 54800}, {f: 3, c: 54803}, 54812,
- 54816, 54820, 54829, {f: 2, c: 54840}, 54844, 54848, 54853,
- {f: 2, c: 54856}, 54859, 54861, 54865, {f: 2, c: 54868}, 54872, 54876,
- 54887, 54889, {f: 2, c: 54896}, 54900, 54915, 54917, {f: 2, c: 54924},
- 54928, 54932, 54941, 54943, 54945, 54952, 54956, 54960, 54969, 54971,
- {f: 2, c: 54980}, 54984, 54988, 54993, 54996, 54999, 55001, 55008, 55012,
- 55016, 55024, 55029, {f: 2, c: 55036}, 55040, 55044, 55057,
- {f: 2, c: 55064}, 55068, 55072, {f: 2, c: 55080}, 55083, 55085,
- {f: 2, c: 55092}, 55096, 55100, 55108, 55111, 55113, {f: 2, c: 55120},
- 55124, {f: 4, c: 55126}, {f: 2, c: 55136}, 55139, 55141, 55145, 55148,
- 55152, 55156, {f: 2, c: 55164}, 55169, {f: 2, c: 55176}, 55180, 55184,
- {f: 2, c: 55192}, 55195, 55197, 20285, 20339, 20551, 20729, 21152, 21487,
- 21621, 21733, 22025, 23233, 23478, 26247, {f: 2, c: 26550}, 26607, 27468,
- 29634, 30146, 31292, 33499, 33540, 34903, 34952, 35382, [36040, 63747],
- 36303, 36603, 36838, 39381, 21051, 21364, 21508, 24682, 24932, 27580,
- 29647, 33050, 35258, [12179, 35282], 38307, 20355, 21002, 22718, 22904,
- 23014, [12082, 24178], 24185, 25031, 25536, 26438, 26604, 26751, 28567,
- 30286, 30475, 30965, 31240, 31487, 31777, 32925, [12169, 33390], 33393,
- 35563, 38291, 20075, 21917, 26359, 28212, 30883, 31469, 33883, 35088,
- 34638, 38824, 21208, 22350, 22570, 23884, 24863, 25022, 25121, 25954,
- 26577, 27204, 28187, [12130, 29976], 30131, 30435, 30640, 32058, 37039,
- {f: 2, c: 37969}, 40853, 21283, 23724, 30002, 32987, 37440, 38296, 21083,
- 22536, 23004, 23713, 23831, 24247, 24378, 24394, 24951, 27743, 30074,
- 30086, 31968, 32115, 32177, 32652, 33108, 33313, 34193, 35137, 35611,
- 37628, [38477, 64009], 40007, 20171, 20215, 20491, 20977, 22607, 24887,
- 24894, 24936, 25913, 27114, 28433, 30117, 30342, 30422, 31623, 33445,
- 33995, 37799, 38283, 21888, 23458, 22353, 31923, 32697, 37301, 20520,
- 21435, 23621, 24040, 25298, 25454, 25818, 25831, 28192, 28844, 31067,
- 36317, 36382, 36989, 37445, 37624, 20094, 20214, 20581, [12081, 24062],
- 24314, 24838, 26967, 33137, 34388, 36423, 37749, 39467, 20062, 20625,
- 26480, 26688, 20745, 21133, 21138, 27298, 30652, 37392, 40660, 21163,
- 24623, 36850, 20552, 25001, 25581, 25802, 26684, 27268, 28608, 33160,
- 35233, 38548, 22533, 29309, [12125, 29356], 29956, 32121, 32365, 32937,
- [12178, 35211, 64010], 35700, 36963, 40273, 25225, 27770, 28500, 32080,
- 32570, 35363, 20860, 24906, 31645, 35609, 37463, 37772, 20140, 20435,
- 20510, 20670, 20742, 21185, 21197, 21375, 22384, 22659, 24218, 24465,
- 24950, 25004, 25806, 25964, 26223, 26299, [26356, 63745], 26775, 28039,
- 28805, 28913, 29855, 29861, 29898, 30169, 30828, 30956, 31455, 31478,
- 32069, 32147, 32789, 32831, 33051, 33686, 35686, 36629, 36885, 37857,
- 38915, 38968, 39514, 39912, 20418, 21843, 22586, [22865, 63753], 23395,
- 23622, 24760, 25106, 26690, 26800, 26856, 28330, 30028, 30328, 30926,
- 31293, 31995, 32363, 32380, 35336, 35489, 35903, 38542, 40388, 21476,
- 21481, 21578, 21617, 22266, 22993, 23396, 23611, 24235, 25335, 25911,
- 25925, 25970, 26272, 26543, 27073, 27837, 30204, 30352, 30590, 31295,
- 32660, 32771, 32929, 33167, 33510, 33533, 33776, 34241, 34865, 34996,
- 35493, 36764, 37678, 38599, 39015, [12220, 39640], [12238, 40723], 21741,
- 26011, 26354, 26767, 31296, [12181, 35895], 40288, 22256, 22372, 23825,
- 26118, 26801, 26829, 28414, 29736, 34974, 39908, 27752, [12219, 39592],
- 20379, 20844, 20849, 21151, 23380, [12079, 24037], 24656, 24685, 25329,
- 25511, 25915, 29657, 31354, 34467, 36002, 38799, [20018, 63749], 23521,
- [12093, 25096], 26524, [12128, 29916], 31185, 33747, 35463, 35506, 36328,
- 36942, 37707, 38982, [24275, 64011], 27112, 34303, 37101, 20896, 23448,
- 23532, 24931, 26874, 27454, 28748, 29743, 29912, 31649, 32592, 33733,
- 35264, 36011, 38364, 39208, 21038, 24669, 25324, 36866, 20362, 20809,
- 21281, 22745, 24291, 26336, 27960, 28826, 29378, 29654, 31568, 33009,
- 37979, 21350, 25499, 32619, 20054, 20608, 22602, 22750, 24618, 24871,
- 25296, 27088, 39745, 23439, 32024, 32945, 36703, 20132, 20689, 21676,
- 21932, 23308, 23968, 24039, 25898, 25934, 26657, 27211, 29409, 30350,
- 30703, 32094, 32761, 33184, 34126, 34527, 36611, 36686, 37066, 39171,
- 39509, 39851, 19992, 20037, 20061, 20167, 20465, 20855, 21246, 21312,
- [12061, 21475], [21477, 63750], 21646, 22036, 22389, 22434, 23495, 23943,
- 24272, 25084, 25304, 25937, 26552, 26601, 27083, 27472, 27590, 27628,
- 27714, 28317, 28792, 29399, 29590, 29699, 30655, 30697, 31350, 32127,
- 32777, [12165, 33276], 33285, 33290, 33503, 34914, 35635, 36092, 36544,
- 36881, 37041, 37476, 37558, 39378, 39493, 40169, 40407,
- [12244, 40860, 63751, 63752], 22283, 23616, 33738, 38816, 38827, 40628,
- 21531, 31384, 32676, 35033, 36557, 37089, 22528, 23624, 25496, 31391,
- 23470, [12088, 24339], 31353, 31406, 33422, 36524, 20518, 21048, 21240,
- 21367, 22280, 25331, 25458, 27402, 28099, 30519, 21413, 29527, 34152,
- 36470, 38357, 26426, 27331, 28528, 35437, 36556, 39243, 26231, 27512,
- 36020, [12225, 39740], 21483, 22317, 22862, 25542, 27131, 29674, 30789,
- 31418, 31429, 31998, 33909, 35215, 36211, 36917, 38312, 21243, 22343,
- 30023, 31584, 33740, 37406, 27224, 20811, 21067, 21127, 25119, 26840,
- 26997, 38553, 20677, 21156, 21220, 25027, [12100, 26020], 26681, 27135,
- 29822, 31563, 33465, 33771, 35250, 35641, 36817, 39241, 20170, 22935,
- 25810, 26129, 27278, 29748, 31105, 31165, 33449, {f: 2, c: 34942}, 35167,
- 37670, 20235, 21450, 24613, 25201, 27762, 32026, 32102, 20120, 20834,
- 30684, 32943, 20225, 20238, 20854, 20864, 21980, 22120, 22331, 22522,
- 22524, 22804, 22855, 22931, 23492, 23696, 23822, [12080, 24049], 24190,
- 24524, 25216, 26071, 26083, {f: 2, c: 26398}, 26462, 26827, 26820, 27231,
- 27450, 27683, 27773, 27778, 28103, 29592, 29734, 29738, 29826, 29859,
- 30072, 30079, 30849, 30959, 31041, {f: 2, c: 31047}, 31098, 31637, 32000,
- 32186, 32648, 32774, 32813, 32908, 35352, 35663, [35912, 63744], 36215,
- 37665, 37668, 39138, 39249, {f: 2, c: 39438}, 39525, 40594, 32202, 20342,
- 21513, 25326, 26708, [12198, 37329, 63754], 21931, 20794, 23068, 25062,
- [25295, 63835], 25343, 37027, [35582, 63837], 26262, 29014, 38627, 25423,
- 25466, 21335, 26511, 26976, 28275, 30007, 32013, 34930, 22218, 23064,
- 20035, 20839, [22856, 63756], 26608, 32784, [12069, 22899, 63873],
- [24180, 63886], [25754, 63889], [31178, 63893], [24565, 63907], 24684,
- 25288, [25467, 63908], [23527, 63839, 63914], 23511, 21162, 22900, 24361,
- [24594, 63840], 29785, 39377, 28611, 33215, 36786, 24817, 33126,
- [23615, 63933], 23273, 35365, [26491, 63944], [32016, 63951], 33021, 23612,
- [27877, 63971], [21311, 63979], [28346, 63980], 22810, [33590, 63998],
- [20025, 63838], 20150, 20294, 21934, 22296, 22727, 24406, 26039, 26086,
- 27264, 27573, 28237, 30701, 31471, 31774, 32222, 34507, 34962, 37170,
- 37723, 25787, 28606, 29562, 30136, 36948, 21846, 22349, 25018, 25812,
- 26311, 28129, 28251, 28525, 28601, 30192, 32835, 33213, 34113, 35203,
- 35527, 35674, 37663, 27795, 30035, 31572, 36367, 36957, 21776, 22530,
- 22616, 24162, 25095, 25758, 26848, 30070, [31958, 64003], 34739, 40680,
- 20195, 22408, 22382, [12068, 22823], 23565, 23729, 24118, 24453, 25140,
- 25825, 29619, 33274, 34955, 36024, 38538, 40667, [23429, 64004], 24503,
- 24755, 20498, [12049, 20992], 21040, 22294, 22581, 22615, 23566, 23648,
- 23798, 23947, [24230, 64001], 24466, 24764, 25361, 25481, 25623, 26691,
- 26873, 27330, 28120, 28193, 28372, 28644, 29182, 30428, 30585, 31153,
- 31291, 33796, 35241, 36077, 36339, 36424, 36867, 36884, 36947, 37117,
- 37709, 38518, 38876, 27602, 28678, 29272, 29346, 29544, 30563, 31167,
- 31716, 32411, [35712, 63834], 22697, 24775, 25958, 26109, 26302, 27788,
- 28958, 29129, 35930, 38931, 20077, 31361, 20189, 20908, 20941, 21205,
- 21516, 24999, 26481, 26704, 26847, [27934, 64005], 28540, 30140, 30643,
- 31461, 33012, 33891, 37509, 20828, [12099, 26007], 26460, 26515, 30168,
- 31431, 33651, [12182, 35910], 36887, 38957, 23663, 33216, 33434, 36929,
- 36975, 37389, 24471, 23965, 27225, 29128, 30331, 31561, 34276, 35588,
- 37159, 39472, [21895, 63755], [25078, 63757], [30313, 63758],
- [32645, 63759], [34367, 63760], [34746, 63761], [35064, 63762],
- [37007, 63763], [27931, 63765], [28889, 63766], [29662, 63767], 32097,
- [33853, 63768], [37226, 63769], [39409, 63770], [20098, 63771],
- [21365, 63772], [27396, 63773], 27410, 28734, [29211, 63774],
- [34349, 63775], [40478, 63776], 21068, 36771, [23888, 63777], 25829, 25900,
- 27414, [28651, 63778], 31811, 32412, [34253, 63779], [35172, 63780], 35261,
- [25289, 63781], [33240, 63782], [34847, 63783], [24266, 63784],
- [26391, 63785], [28010, 63786], [29436, 63787], 29701, 29807, 34690,
- [37086, 63788], [20358, 63789], 23821, 24480, 33802, [20919, 63790],
- [25504, 63861], [30053, 63862], [20142, 63863], 20486, [20841, 63864],
- [20937, 63865], [26753, 63866], 27153, 31918, 31921, [31975, 63867],
- [33391, 63868], [35538, 63869], 36635, [37327, 63870], 20406, 20791,
- [21237, 63871], [21570, 63872], [24300, 63874], 24942, 25150,
- [26053, 63875], 27354, [28670, 63876], [31018, 63877], 34268, 34851,
- [38317, 63878], 39522, [39530, 63879], [40599, 63880], [40654, 63881],
- [12050, 21147, 63882], [26310, 63883], [27511, 63884], 28701, 31019,
- [36706, 63885], 38722, [24976, 63887], [25088, 63888], 25891,
- [28451, 63890], [29001, 63891], [29833, 63892], [32244, 63894],
- [32879, 63895], [34030, 63897], [36646, 63896], [36899, 63898],
- [37706, 63899], 20925, [21015, 63900], [21155, 63901], 27916,
- [28872, 63903], [35010, 63904], [24265, 63906], 25986, [27566, 63909],
- 28610, [31806, 63910], [29557, 63911], [20196, 63912], 20278,
- [22265, 63913], 23738, [23994, 63915], [24604, 63916], [29618, 63917],
- 31533, [32666, 63919], 32718, [32838, 63920], 36894, [37428, 63921],
- [38646, 63922], [38728, 63923], [38936, 63924], 40801, [20363, 63925],
- 28583, [31150, 63926], [37300, 63927], [38583, 63928], [21214, 63791],
- 25736, [25796, 63792], [27347, 63793], 28510, 28696, [29200, 63794],
- [30439, 63795], [12156, 32769, 63796], [34310, 63797], [34396, 63798],
- [36335, 63799], 36613, [38706, 63800], [39791, 63801], [40442, 63802],
- [12228, 40565], [30860, 63803], [31103, 63804], [32160, 63805],
- [33737, 63806], [37636, 63807], [12229, 40575, 63808], 40595,
- [35542, 63809], [22751, 63810], [24324, 63811], 26407, 28711, 29903,
- [31840, 63812], [32894, 63813], 20769, 28712, [29282, 63814],
- [30922, 63815], [36034, 63816], 36058, 36084, [38647, 63817],
- [20102, 63930], [20698, 63931], [23534, 63932], 24278, [26009, 63934],
- [29134, 63936], [30274, 63937], 30637, 32842, [34044, 63938],
- [36988, 63939], 39719, [12243, 40845, 63940], [22744, 63818], 23105,
- [23650, 63819], [27155, 63820], [28122, 63821], [28431, 63822], 30267,
- [32047, 63823], [32311, 63824], 34078, 35128, 37860, [38475, 63825],
- [21129, 63943], 26066, [26611, 63945], 27060, [27969, 63946],
- [28316, 63947], 28687, [29705, 63948], 29792, [30041, 63949], 30244,
- [30827, 63950], 35628, [39006, 63952], [20845, 63953], [25134, 63954],
- [38520, 63955], 20374, [20523, 63956], [23833, 63957], [28138, 63958],
- 32184, [36650, 63959], [24459, 63960], [24900, 63961], [26647, 63962],
- [38534, 63964], [21202, 63826], [32907, 63827], [20956, 63828],
- [20940, 63829], 26974, [31260, 63830], [32190, 63831], [33777, 63832],
- [38517, 63833], 20442, [21033, 63965], 21400, [21519, 63966], 21774,
- [23653, 63967], 24743, [26446, 63969], [26792, 63970], 28012, 29313, 29432,
- [29702, 63972], 29827, [30178, 63973], 31852, [32633, 63974], 32696, 33673,
- [35023, 63975], [35041, 63976], [12197, 37324, 63977], 37328,
- [38626, 63978], 39881, [21533, 63981], 28542, [29136, 63982],
- [29848, 63983], [34298, 63984], 36522, [38563, 63985], [40023, 63986],
- [40607, 63987], [26519, 63988], [28107, 63989], 29747, [33256, 63990],
- 38678, 30764, [12148, 31435, 63991], [31520, 63992], [31890, 63993], 25705,
- 29802, 30194, 30908, 30952, [12218, 39340], 39764, [12231, 40635], 23518,
- 24149, 28448, 33180, 33707, 37000, 19975, 21325, 23081, 24018, 24398,
- 24930, 25405, 26217, 26364, 28415, 28459, 28771, 30622, 33836, 34067,
- 34875, 36627, 39237, 39995, 21788, 25273, 26411, 27819, 33545, 35178,
- 38778, 20129, 22916, {f: 2, c: 24536}, 26395, 32178, 32596, 33426, 33579,
- 33725, 36638, 37017, 22475, 22969, 23186, 23504, 26151, 26522, 26757,
- 27599, 29028, 32629, 36023, 36067, 36993, 39749, 33032, 35978, 38476,
- 39488, [12230, 40613], 23391, 27667, 29467, 30450, 30431, 33804, 20906,
- 35219, 20813, 20885, 21193, 26825, 27796, 30468, 30496, 32191, 32236,
- [12207, 38754], 40629, 28357, 34065, 20901, 21517, 21629, 26126, 26269,
- 26919, 28319, [12139, 30399], 30609, 33559, 33986, 34719, 37225, 37528,
- 40180, 34946, 20398, 20882, 21215, 22982, 24125, 24917, {f: 2, c: 25720},
- 26286, 26576, 27169, 27597, [12113, 27611], 29279, 29281, 29761, 30520,
- [12141, 30683], 32791, 33468, 33541, 35584, 35624, 35980, [12106, 26408],
- 27792, 29287, [12140, 30446], 30566, 31302, 40361, 27519, 27794, 22818,
- 26406, 33945, 21359, 22675, 22937, 24287, 25551, 26164, 26483, 28218,
- 29483, 31447, 33495, 37672, 21209, 24043, 25006, 25035, 25098, 25287,
- 25771, [12102, 26080], 26969, 27494, [12111, 27595], 28961, 29687, 30045,
- 32326, 33310, 33538, 34154, 35491, 36031, 38695, 40289, 22696, 40664,
- 20497, 21006, 21563, 21839, [12098, 25991], 27766, {f: 2, c: 32010}, 32862,
- 34442, [12200, 38272], 38639, 21247, 27797, 29289, 21619, 23194, 23614,
- 23883, 24396, 24494, 26410, 26806, 26979, 28220, 28228, 30473,
- [12150, 31859], 32654, 34183, 35598, 36855, 38753, 40692, 23735, 24758,
- 24845, 25003, 25935, {f: 2, c: 26107}, 27665, 27887, 29599, 29641, 32225,
- 38292, 23494, 34588, 35600, 21085, 21338, 25293, 25615, 25778, 26420,
- 27192, 27850, 29632, 29854, 31636, 31893, 32283, 33162, 33334, 34180,
- 36843, 38649, 39361, 20276, 21322, 21453, 21467, 25292, 25644, 25856,
- 26001, 27075, 27886, 28504, 29677, 30036, 30242, 30436, 30460, 30928,
- [30971, 63844], 31020, 32070, 33324, 34784, 36820, 38930, 39151, 21187,
- 25300, 25765, 28196, 28497, 30332, 36299, 37297, 37474, 39662, 39747,
- 20515, 20621, 22346, 22952, 23592, 24135, 24439, 25151, 25918,
- [12101, 26041], 26049, 26121, 26507, 27036, 28354, 30917, 32033, 32938,
- 33152, 33323, 33459, 33953, 34444, 35370, 35607, 37030, 38450, 40848,
- 20493, 20467, 22521, 24472, 25308, 25490, 26479, 28227, 28953, 30403,
- 32972, 32986, {f: 2, c: 35060}, 35097, 36064, 36649, 37197, 38506, 20271,
- 20336, 24091, 26575, 26658, [12137, 30333], 30334, 39748, 24161, 27146,
- 29033, 29140, 30058, 32321, 34115, 34281, 39132, 20240, 31567, 32624,
- 38309, 20961, 24070, 26805, 27710, 27726, 27867, 29359, 31684, 33539,
- 27861, 29754, 20731, 21128, 22721, 25816, 27287, 29863, 30294, 30887,
- 34327, 38370, 38713, 21342, 24321, 35722, 36776, 36783, 37002, 21029,
- 30629, 40009, 40712, 19993, 20482, 20853, 23643, 24183, 26142, 26170,
- 26564, 26821, 28851, 29953, 30149, 31177, 31453, 36647, 39200, 39432,
- 20445, 22561, 22577, 23542, 26222, 27493, 27921, 28282, 28541, 29668,
- 29995, 33769, 35036, 35091, 35676, 36628, 20239, 20693, 21264,
- [12056, 21340], 23443, [24489, 63846], 26381, 31119, 33145, 33583, 34068,
- 35079, 35206, 36665, [36667, 64007], 39333, 39954, 26412, 20086, 20472,
- 22857, 23553, {f: 2, c: 23791}, 25447, 26834, 28925, 29090, 29739, 32299,
- 34028, 34562, 36898, 37586, 40179, [19981, 63847], 20184, 20463, 20613,
- 21078, 21103, 21542, 21648, 22496, 22827, 23142, 23386, 23413, 23500,
- 24220, 25206, 25975, 26023, 28014, 28325, [12119, 29238], 31526, 31807,
- [12152, 32566], {f: 2, c: 33104}, 33178, 33344, 33433, 33705, 35331, 36000,
- 36070, 36091, 36212, 36282, 37096, 37340, [12201, 38428], 38468, 39385,
- 40167, [21271, 63843], 20998, 21545, 22132, 22707, 22868, 22894, 24575,
- 24996, 25198, 26128, 27774, 28954, 30406, 31881, 31966, 32027, 33452,
- 36033, 38640, 20315, 24343, 24447, 25282, 23849, 26379, 26842, 30844,
- 32323, 40300, 19989, 20633, [12052, 21269], 21290, 21329, 22915, 23138,
- 24199, 24754, 24970, 25161, 25209, 26000, 26503, 27047, [12112, 27604],
- {f: 3, c: 27606}, 27832, 29749, 30202, 30738, 30865, 31189, 31192, 31875,
- 32203, 32737, 32933, 33086, 33218, 33778, 34586, 35048, 35513, 35692,
- 36027, 37145, [12206, 38750], [12214, 39131], [12240, 40763], 22188, 23338,
- 24428, 25996, 27315, 27567, 27996, 28657, 28693, 29277, 29613, 36007,
- 36051, 38971, 24977, 27703, 32856, 39425, 20045, 20107, 20123, 20181,
- 20282, 20284, 20351, 20447, 20735, 21490, 21496, 21766, 21987, 22235,
- [12064, 22763], 22882, 23057, 23531, 23546, 23556, 24051, 24107, 24473,
- 24605, 25448, 26012, 26031, 26614, 26619, 26797, 27515, 27801, 27863,
- 28195, 28681, 29509, 30722, 31038, 31040, 31072, 31169, 31721, 32023,
- 32114, 32902, 33293, 33678, 34001, 34503, 35039, 35408, 35422, 35613,
- 36060, 36198, 36781, 37034, 39164, 39391, 40605, 21066, 26388, 20632,
- 21034, [12077, 23665], 25955, 27733, 29642, 29987, 30109, 31639, 33948,
- 37240, 38704, 20087, 25746, [27578, 63856], 29022, 34217, 19977, 26441,
- 26862, 28183, 33439, 34072, 34923, 25591, 28545, 37394, 39087, 19978,
- 20663, 20687, 20767, 21830, 21930, 22039, 23360, 23577, 23776, 24120,
- 24202, 24224, 24258, 24819, 26705, 27233, 28248, 29245, 29248,
- [29376, 63994], 30456, 31077, 31665, 32724, 35059, 35316, 35443, 35937,
- 36062, 38684, [22622, 63852], 29885, 36093, 21959, 31329, [32034, 63850],
- [12170, 33394], 29298, [12131, 29983], 29989, 31513, 22661, 22779, 23996,
- 24207, 24246, 24464, 24661, 25234, 25471, 25933, 26257, 26329, 26360,
- 26646, 26866, 29312, 29790, 31598, 32110, 32214, 32626, 32997, 33298,
- 34223, 35199, 35475, 36893, 37604, [12233, 40653], [12239, 40736],
- [12067, 22805], 22893, 24109, 24796, 26132, 26227, 26512, 27728, 28101,
- 28511, [12143, 30707], 30889, 33990, 37323, 37675, 20185, 20682, 20808,
- 21892, 23307, 23459, 25159, 25982, 26059, 28210, 29053, 29697, 29764,
- 29831, 29887, 30316, 31146, 32218, 32341, 32680, 33146, 33203, 33337,
- 34330, 34796, 35445, 36323, 36984, 37521, 37925, 39245, 39854, 21352,
- 23633, 26964, 27844, 27945, 28203, [12166, 33292], 34203, 35131, 35373,
- [35498, 63855, 63905], 38634, 40807, 21089, 26297, 27570, 32406, 34814,
- 36109, 38275, 38493, 25885, 28041, 29166, 22478, 22995, 23468, 24615,
- 24826, 25104, 26143, 26207, 29481, 29689, 30427, [30465, 63853], 31596,
- 32854, 32882, 33125, 35488, 37266, 19990, 21218, 27506, 27927, 31237,
- 31545, 32048, 36016, 21484, 22063, 22609, 23477, [12073, 23567], 23569,
- 24034, 25152, 25475, 25620, 26157, 26803, 27836, 28040, 28335, 28703,
- 28836, 29138, 29990, 30095, 30094, 30233, 31505, 31712, 31787, 32032,
- 32057, 34092, 34157, 34311, 35380, 36877, 36961, 37045, 37559, 38902,
- 39479, 20439, 23660, 26463, 28049, 31903, 32396, 35606, 36118, 36895,
- 23403, 24061, 25613, 33984, 36956, 39137, [29575, 63841, 63963], 23435,
- 24730, 26494, 28126, 35359, 35494, 36865, 38924, 21047, 28753, 30862,
- 37782, 34928, 37335, 20462, 21463, 22013, 22234, 22402, 22781, 23234,
- 23432, 23723, 23744, 24101, 24833, 25101, [12095, 25163], 25480, 25628,
- 25910, [25976, 63849], 27193, 27530, [12116, 27700], 27929, 28465, 29159,
- 29417, 29560, 29703, 29874, 30246, 30561, 31168, 31319, 31466, 31929,
- 32143, 32172, 32353, 32670, 33065, 33585, 33936, 34010, 34282, 34966,
- 35504, 35728, 36664, 36930, 36995, 37228, 37526, 37561, 38539,
- {f: 2, c: 38567}, 38614, 38656, 38920, [12216, 39318], 39635, 39706, 21460,
- 22654, 22809, 23408, 23487, 28113, 28506, 29087, 29729, 29881, 32901,
- 33789, 24033, 24455, 24490, 24642, 26092, 26642, 26991, 27219, 27529,
- 27957, 28147, 29667, 30462, 30636, 31565, 32020, 33059, 33308, 33600,
- 34036, 34147, 35426, 35524, 37255, 37662, 38918, 39348, 25100, 34899,
- 36848, 37477, 23815, 23847, 23913, 29791, 33181, 34664, 28629,
- [25342, 63859], 32722, 35126, 35186, 19998, 20056, 20711, 21213, 21319,
- 25215, 26119, 32361, 34821, 38494, 20365, 21273, 22070, 22987, 23204,
- [12075, 23608], 23630, 23629, 24066, 24337, 24643, 26045, 26159, 26178,
- 26558, 26612, 29468, [12142, 30690], [12144, 31034], 32709, 33940, 33997,
- 35222, 35430, 35433, 35553, [12183, 35925], 35962, 22516, 23508, 24335,
- 24687, 25325, 26893, 27542, 28252, 29060, 31698, 34645, [35672, 63996],
- 36606, [12215, 39135], 39166, 20280, 20353, 20449, 21627, 23072, 23480,
- 24892, 26032, 26216, 29180, 30003, 31070, 32051, 33102, [12162, 33251],
- 33688, 34218, 34254, 34563, 35338, [12189, 36523], [12191, 36763], 36805,
- 22833, 23460, 23526, 24713, 23529, 23563, [12092, 24515], 27777, 28145,
- 28683, 29978, 33455, 35574, [20160, 63997], [12055, 21313], 38617,
- [12114, 27663], 20126, 20420, 20818, 21854, 23077, 23784, 25105,
- [12123, 29273], 33469, 33706, 34558, 34905, 35357, 38463, 38597, 39187,
- 40201, 40285, 22538, 23731, 23997, 24132, [24801, 63929], 24853, 25569,
- [27138, 63764, 63836, 63935], 28197, 37122, 37716, 38990, 39952, 40823,
- 23433, 23736, 25353, 26191, 26696, 30524, 38593, 38797, 38996, 39839,
- 26017, 35585, 36555, 38332, 21813, 23721, 24022, 24245, 26263, 30284,
- 33780, 38343, 22739, 25276, 29390, 40232, 20208, 22830, 24591, 26171,
- 27523, 31207, 40230, 21395, 21696, 22467, 23830, 24859, 26326, 28079,
- 30861, 33406, 38552, 38724, 21380, 25212, 25494, 28082, 32266, 33099,
- 38989, 27387, 32588, 40367, 40474, 20063, 20539, 20918, 22812, 24825,
- 25590, 26928, 29242, 32822, 37326, 24369, 32004, [33509, 63860], 33903,
- 33979, 34277, 36493, 20335, 22756, 23363, 24665, 25562, 25880, 25965,
- 26264, 26954, 27171, 27915, 28673, 29036, 30162, 30221, 31155, 31344,
- [12154, 32650], 35140, 35731, 37312, 38525, 39178, 22276, 24481, 26044,
- 28417, 30208, 31142, 35486, 39341, [12226, 39770], 40812, 20740, 25014,
- 25233, 27277, 33222, 20547, 22576, 24422, 28937, [12180, 35328], 35578,
- 23420, 34326, 20474, 20796, 22196, 22852, 25513, 28153, 23978, 26989,
- 20870, 20104, 20313, 22914, 27487, 27741, 29877, 30998, 33287, 33349,
- 33593, 36671, 36701, 39192, 20134, 22495, 24441, [26131, 63968], 30123,
- 32377, 35695, 36870, 39515, 22181, 22567, 23032, 23071, 23476, 24310,
- 25424, 25403, 26941, 27783, 27839, 28046, 28051, 28149, 28436, 28895,
- 28982, 29017, 29123, 29141, 30799, 30831, 31605, 32227, 32303, 34893,
- 36575, 37467, 40182, 24709, 28037, 29105, 38321, 21421, 26579, 28814,
- 28976, 29744, 33398, 33490, 38331, 39653, 40573, 26308, 29121,
- [33865, 63854], 22603, 23992, 24433, 26144, 26254, 27001, 27054, 27704,
- 27891, 28214, 28481, 28634, 28699, 28719, 29008, 29151, 29552, 29787,
- 29908, 30408, 31310, 32403, 33521, 35424, 36814, 37704, 38681, 20034,
- 20522, 21000, 21473, 26355, 27757, 28618, 29450, 30591, 31330, 33454,
- 34269, 34306, 35028, 35427, 35709, 35947, 37555, 38675, 38928, 20116,
- 20237, 20425, 20658, 21320, 21566, 21555, 21978, 22626, 22714, 22887,
- 23067, 23524, 24735, 25034, 25942, 26111, 26212, 26791, 27738, 28595,
- 28879, 29100, 29522, 31613, 34568, 35492, 39986, 40711, 23627, 27779,
- 29508, [12127, 29577], 37434, 28331, 29797, 30239, 31337, 32277, 34314,
- 20800, 22725, 25793, 29934, 29973, 30320, 32705, 37013, 38605, 39252,
- 28198, [12129, 29926], {f: 2, c: 31401}, 33253, 34521, 34680, 35355, 23113,
- 23436, 23451, 26785, 26880, 28003, 29609, 29715, 29740, 30871, 32233,
- 32747, 33048, 33109, 33694, 35916, [38446, 63942], 38929, [12104, 26352],
- 24448, 26106, 26505, 27754, 29579, 20525, 23043, 27498, 30702, 22806,
- 23916, 24013, 29477, 30031, 20709, 20985, 22575, 22829, 22934, 23002,
- 23525, 23970, 25303, 25622, 25747, 25854, 26332, 27208, 29183, 29796,
- 31368, 31407, 32327, 32350, 32768, 33136, 34799, 35201, 35616, 36953,
- 36992, 39250, 24958, 27442, 28020, 32287, 35109, 36785, 20433, 20653,
- 20887, 21191, 22471, 22665, 23481, 24248, 24898, 27029, 28044, 28263,
- 28342, 29076, 29794, [12132, 29992], 29996, 32883, 33592, 33993, 36362,
- 37780, 37854, 20110, 20305, 20598, 20778, [12060, 21448], 21451, 21491,
- 23431, 23507, 23588, 24858, 24962, 26100, [12124, 29275], 29591, 29760,
- 30402, 31056, 31121, 31161, 32006, [12155, 32701], 33419, 34261, 34398,
- 36802, 36935, 37109, 37354, 38533, [12204, 38632], 38633, 21206, 24423,
- 26093, 26161, 26671, 29020, 31286, 37057, 38922, 20113, 27218, 27550,
- 28560, 29065, 32792, 33464, 34131, 36939, 38549, 38642, 38907, 34074,
- 39729, 20112, 29066, 38596, 20803, 21407, 21729, 22291, 22290, 22435,
- 23195, 23236, 23491, 24616, 24895, 25588, 27781, 27961, 28274, 28304,
- 29232, 29503, 29783, 33489, 34945, 36677, 36960, 38498, 39000, 40219,
- [12105, 26376], 36234, 37470, 20301, 20553, 20702, 21361, 22285, 22996,
- 23041, 23561, 24944, 26256, 28205, 29234, 29771, 32239, 32963, 33806,
- 33894, 34111, 34655, 34907, 35096, 35586, 36949, [12209, 38859], 39759,
- 20083, 20369, 20754, 20842, 21807, 21929, 23418, 23461, {f: 2, c: 24188},
- 24254, 24736, 24799, {f: 2, c: 24840}, 25540, 25912, 26377, 26580, 26586,
- {f: 2, c: 26977}, 27833, 27943, 28216, 28641, {f: 2, c: 29494}, 29788,
- 30001, 30290, 32173, 33278, 33848, 35029, 35480, 35547, 35565, 36400,
- 36418, 36938, 36926, 36986, [12195, 37193], 37321, 37742, 22537, 27603,
- [12161, 32905], 32946, 20801, 22891, 23609, 28516, 29607, 32996, 36103,
- 37399, 38287, [12160, 32895], 25102, 28700, 32104, 34701, 22432, 24681,
- 24903, 27575, 35518, 37504, 38577, [12036, 20057], 21535, 28139, 34093,
- 38512, [12211, 38899], 39150, 25558, 27875, [12194, 37009], 20957, 25033,
- 33210, 40441, 20381, 20506, 20736, 23452, 24847, 25087, 25836, 26885,
- 27589, 30097, 30691, 32681, 33380, 34191, 34811, [12176, 34915], 35516,
- 35696, 37291, [12038, 20108], 20197, 20234, 22839, 23016, 24050, 24347,
- 24411, 24609, 29246, 29669, [30064, 63842], 30157, 31227, [12157, 32780],
- [12159, 32819], 32900, 33505, 33617, 36029, 36019, 36999, 39156, 39180,
- 28727, 30410, 32714, 32716, 32764, 35610, [12040, 20154], 20161, 20995,
- 21360, [21693, 63902], 22240, 23035, 23493, 24341, 24525, 28270, 32106,
- 33589, 34451, 35469, 38765, 38775, [12032, 19968], 20314, 20350, 22777,
- [12103, 26085], 28322, 36920, 37808, 39353, 20219, 22764, 22922, 23001,
- 24641, 31252, 33615, 36035, [12042, 20837], 21316, 20173, 21097, 23381,
- 33471, 20180, [21050, 63999], 21672, 22985, 23039, [12070, 23376], 23383,
- 23388, 24675, 24904, 28363, [28825, 63995], 29038, 29574, 29943, 30133,
- 30913, 32043, 32773, [12163, 33258], 33576, 34071, 34249, 35566, 36039,
- 38604, 20316, 21242, 22204, 26027, 26152, 28796, 28856, 29237, 32189,
- 33421, 37196, 38592, 40306, 23409, 26855, 27544, 28538, 30430, 23697,
- 26283, 28507, 31668, 31786, 34870, 38620, 19976, 20183, 21280, 22580,
- 22715, 22767, 22892, 23559, 24115, 24196, 24373, 25484, 26290, 26454,
- 27167, 27299, 27404, 28479, 29254, 29520, 29835, 31456, 31911, 33144,
- 33247, 33255, 33674, 33900, 34083, 34196, 34255, 35037, 36115, 37292,
- [12199, 38263], 38556, 20877, 21705, 22312, 23472, 25165, 26448, 26685,
- 26771, 28221, 28371, 28797, 32289, 35009, 36001, 36617, 40779, 40782,
- 29229, 31631, 35533, 37658, 20295, 20302, 20786, 21632, 22992, 24213,
- 25269, 26485, 26990, 27159, 27822, 28186, 29401, 29482, 30141, 31672,
- 32053, 33511, 33785, 33879, 34295, 35419, 36015, 36487, 36889, 37048,
- 38606, 40799, 21219, 21514, 23265, 23490, 25688, 25973, 28404, 29380,
- 30340, 31309, 31515, 31821, 32318, 32735, 33659, 35627, 36042,
- [12186, 36196], 36321, 36447, 36842, 36857, 36969, 37841, 20291, 20346,
- 20659, 20840, 20856, 21069, 21098, 22625, 22652, 22880, 23560, 23637,
- 24283, 24731, 25136, 26643, 27583, 27656, 28593, 29006, 29728,
- [12133, 30000], 30008, 30033, 30322, 31564, 31627, 31661, 31686, 32399,
- 35438, 36670, 36681, 37439, 37523, 37666, 37931, 38651, 39002, 39019,
- 39198, [20999, 64000], 25130, 25240, 27993, 30308, 31434, 31680, 32118,
- 21344, 23742, 24215, 28472, 28857, 31896, 38673, 39822, 40670, 25509,
- 25722, 34678, 19969, 20117, 20141, 20572, 20597, 21576, 22979, 23450,
- 24128, 24237, 24311, 24449, 24773, 25402, 25919, 25972, 26060, 26230,
- 26232, 26622, 26984, 27273, 27491, 27712, 28096, 28136, 28191, 28254,
- 28702, 28833, 29582, 29693, 30010, 30555, 30855, 31118, 31243, 31357,
- 31934, 32142, 33351, 35330, 35562, 35998, 37165, 37194, 37336, 37478,
- 37580, 37664, 38662, 38742, 38748, 38914, [12237, 40718], 21046, 21137,
- 21884, 22564, 24093, 24351, 24716, 25552, 26799, 28639, 31085, 31532,
- 33229, 34234, 35069, 35576, 36420, 37261, 38500, 38555, 38717, 38988,
- [12241, 40778], 20430, 20806, 20939, 21161, 22066, 24340, 24427, 25514,
- 25805, 26089, 26177, 26362, 26361, 26397, 26781, 26839, 27133, 28437,
- 28526, 29031, 29157, [12118, 29226], 29866, 30522, 31062, 31066, 31199,
- 31264, 31381, 31895, 31967, 32068, 32368, 32903, 34299, 34468, 35412,
- 35519, 36249, 36481, 36896, 36973, 37347, 38459, 38613, [12227, 40165],
- 26063, 31751, [12188, 36275], 37827, 23384, 23562, 21330, 25305, 29469,
- 20519, 23447, 24478, 24752, 24939, 26837, 28121, 29742, 31278, 32066,
- 32156, 32305, 33131, 36394, 36405, 37758, 37912, 20304, 22352, 24038,
- 24231, 25387, 32618, 20027, 20303, 20367, 20570, 23005, 32964, 21610,
- 21608, 22014, 22863, 23449, 24030, 24282, 26205, 26417, 26609, 26666,
- 27880, 27954, 28234, 28557, 28855, 29664, 30087, 31820, 32002, 32044,
- 32162, [12168, 33311], 34523, 35387, 35461, [12187, 36208], 36490, 36659,
- 36913, 37198, 37202, 37956, 39376, [12149, 31481], 31909, 20426, 20737,
- 20934, 22472, 23535, 23803, 26201, 27197, 27994, 28310, 28652, 28940,
- 30063, 31459, 34850, 36897, 36981, 38603, 39423, 33537, 20013, 20210,
- 34886, 37325, 21373, 27355, 26987, 27713, 33914, 22686, 24974, 26366,
- 25327, 28893, 29969, 30151, 32338, 33976, 35657, 36104, 20043, 21482,
- 21675, 22320, 22336, 24535, 25345, 25351, 25711, [12096, 25903], 26088,
- 26234, 26525, 26547, [12108, 27490], 27744, 27802, 28460, 30693, 30757,
- 31049, 31063, 32025, 32930, 33026, [12164, 33267], 33437, 33463, 34584,
- 35468, 36100, 36286, 36978, 30452, 31257, 31287, 32340, 32887, 21767,
- 21972, 22645, 25391, 25634, 26185, 26187, 26733, 27035, 27524, 27941,
- 28337, 29645, 29800, 29857, 30043, 30137, 30433, 30494, 30603, 31206,
- 32265, 32285, 33275, 34095, 34967, 35386, 36049, 36587,
- [12192, 36784, 63857], 36914, 37805, 38499, 38515, 38663, 20356, 21489,
- 23018, 23241, 24089, 26702, 29894, 30142, 31209, 31378, 33187, 34541,
- 36074, 36300, 36845, 26015, 26389, 22519, 28503, 32221, 36655, 37878,
- 38598, 24501, 25074, 28548, 19988, 20376, 20511, 21449, 21983, 23919,
- 24046, 27425, 27492, 30923, 31642, 36425, [12190, 36554, 63746], 36974,
- 25417, 25662, 30528, 31364, 37679, 38015, 40810, 25776, 28591, 29158,
- 29864, 29914, 31428, 31762, 32386, 31922, 32408, 35738, 36106, 38013,
- 39184, 39244, 21049, 23519, 25830, 26413, 32046, 20717, [21443, 63851],
- 22649, {f: 2, c: 24920}, 25082, 26028, 31449, 35730, 35734, 20489, 20513,
- 21109, 21809, 23100, 24288, 24432, 24884, 25950, 26124, 26166, 26274,
- 27085, 28356, 28466, 29462, 30241, 31379, 33081, 33369, 33750, 33980,
- 20661, 22512, 23488, 23528, 24425, 25505, 30758, 32181, 33756, 34081,
- 37319, 37365, 20874, 26613, 31574, 36012, 20932, 22971, 24765, 34389,
- 20508, 21076, 23610, 24957, 25114, [25299, 64002], 25842, 26021, 28364,
- 30240, 33034, 36448, 38495, 38587, 20191, 21315, 21912, 22825, 24029,
- 25797, 27849, 28154, 29588, 31359, [12167, 33307], 34214, 36068, 36368,
- 36983, 37351, 38369, 38433, 38854, 20984, 21746, 21894, 24505, 25764,
- 28552, 32180, 36639, 36685, 37941, 20681, 23574, 27838, 28155, 29979,
- 30651, 31805, 31844, 35449, 35522, 22558, 22974, 24086, 25463, 29266,
- 30090, 30571, 35548, 36028, 36626, 24307, 26228, 28152, 32893, 33729,
- 35531, [12205, 38737], 39894, 21059, 26367, 28053, 28399, 32224, 35558,
- 36910, 36958, 39636, 21021, 21119, 21736, 24980, 25220, 25307, 26786,
- 26898, 26970, 27189, 28818, 28966, 30813, 30977, 30990, 31186, 31245,
- 32918, [12171, 33400], 33493, 33609, 34121, 35970, 36229, 37218, 37259,
- 37294, 20419, 22225, 29165, 30679, 34560, 35320, [12072, 23544], 24534,
- 26449, 37032, 21474, 22618, 23541, 24740, 24961, 25696, 32317, 32880,
- 34085, 37507, 25774, 20652, 23828, 26368, 22684, 25277, 25512, 26894,
- 27000, 27166, 28267, 30394, 31179, 33467, 33833, 35535, 36264, 36861,
- 37138, 37195, 37276, 37648, 37656, 37786, 38619, 39478, 39949, 19985,
- 30044, 31069, 31482, 31569, 31689, 32302, 33988, 36441, 36468, 36600,
- 36880, 26149, 26943, 29763, 20986, 26414, 40668, 20805, 24544, 27798,
- 34802, 34909, 34935, 24756, 33205, 33795, 36101, 21462, 21561, 22068,
- 23094, 23601, 28810, 32736, 32858, 33030, 33261, 36259, 37257, 39519,
- 40434, 20596, 20164, 21408, 24827, 28204, 23652, 20360, 20516, 21988,
- 23769, 24159, 24677, 26772, 27835, 28100, 29118, 30164, 30196, 30305,
- 31258, 31305, 32199, 32251, 32622, 33268, 34473, 36636, 38601, 39347,
- [12242, 40786], 21063, 21189, 39149, 35242, 19971, 26578, 28422, 20405,
- 23522, 26517, [27784, 63858], 28024, 29723, 30759, 37341, 37756, 34756,
- 31204, 31281, 24555, 20182, 21668, 21822, 22702, 22949, 24816, 25171,
- 25302, 26422, 26965, 33333, 38464, 39345, 39389, 20524, 21331, 21828,
- 22396, 25176, 25826, 26219, 26589, 28609, 28655, 29730, 29752, 35351,
- 37944, 21585, 22022, 22374, 24392, 24986, 27470, 28760, 28845, 32187,
- 35477, 22890, 33067, 25506, 30472, 32829, 36010, 22612, 25645, 27067,
- 23445, 24081, 28271, 34153, 20812, 21488, 22826, 24608, 24907, 27526,
- 27760, 27888, 31518, 32974, 33492, 36294, 37040, 39089, 25799, 28580,
- 25745, 25860, 20814, 21520, [12063, 22303], 35342, 24927, 26742, 30171,
- 31570, 32113, 36890, 22534, 27084, 33151, 35114, 36864, 38969, 20600,
- 22871, 22956, 25237, 36879, 39722, 24925, 29305, 38358, 22369, 23110,
- 24052, 25226, 25773, 25850, 26487, 27874, 27966, 29228, 29750, 30772,
- 32631, 33453, 36315, 38935, 21028, 22338, 26495, 29256, 29923, 36009,
- 36774, 37393, 38442, [12043, 20843], 21485, 25420, 20329, 21764, 24726,
- 25943, 27803, 28031, 29260, 29437, 31255, 35207, [12185, 35997], 24429,
- 28558, 28921, 33192, 24846, [20415, 63845], 20559, 25153, [12122, 29255],
- 31687, 32232, 32745, 36941, 38829, 39449, 36022, 22378, 24179, 26544,
- 33805, 35413, 21536, 23318, 24163, 24290, 24330, 25987, 32954, 34109,
- 38281, 38491, 20296, 21253, 21261, 21263, 21638, 21754, 22275, 24067,
- 24598, 25243, 25265, 25429, 27873, 28006, 30129, 30770, 32990, 33071,
- 33502, 33889, 33970, 34957, 35090, 36875, 37610, 39165, 39825, 24133,
- [26292, 64006], 26333, 28689, 29190, 20469, 21117, 24426, 24915, 26451,
- 27161, 28418, 29922, 31080, 34920, 35961, 39111, 39108, 39491, 21697,
- 31263, 26963, 35575, 35914, [12213, 39080], 39342, 24444, 25259, 30130,
- [12138, 30382], 34987, 36991, 38466, 21305, 24380, 24517, [27852, 63848],
- 29644, 30050, [12134, 30091], 31558, 33534, 39325, 20047, 36924, 19979,
- 20309, 21414, 22799, 24264, 26160, 27827, 29781, 33655, 34662, 36032,
- 36944, 38686, 39957, 22737, 23416, 34384, 35604, 40372, 23506, 24680,
- 24717, 26097, 27735, 28450, 28579, 28698, 32597, 32752, {f: 2, c: 38289},
- 38480, 38867, 21106, 36676, 20989, 21547, 21688, 21859, 21898, 27323,
- 28085, 32216, 33382, 37532, 38519, 40569, 21512, 21704, 30418, 34532,
- 38308, 38356, 38492, 20130, 20233, 23022, 23270, 24055, 24658, 25239,
- 26477, 26689, 27782, 28207, 32568, 32923, 33322, 38917, 20133, 20565,
- 21683, 22419, 22874, 23401, 23475, 25032, 26999, 28023, 28707, 34809,
- 35299, 35442, 35559, 36994, 39405, 39608, 21182, 26680, 20502, 24184,
- 26447, 33607, [12175, 34892, 64008], 20139, 21521, 22190, 29670, 37141,
- 38911, 39177, 39255, [12217, 39321], 22099, 22687, 34395, 35377, 25010,
- 27382, 29563, 36562, 27463, 38570, 39511, 22869, 29184, 36203,
- [12208, 38761], 20436, 23796, 24358, 25080, 26203, 27883, 28843,
- [12126, 29572], 29625, 29694, 30505, 30541, 32067, 32098, 32291, 33335,
- 34898, 36066, 37449, 39023, 23377, [12147, 31348], [12174, 34880],
- [12212, 38913], 23244, 20448, 21332, 22846, 23805, 25406, 28025, 29433,
- 33029, 33031, 33698, 37583, 38960, 20136, 20804, 21009, 22411, 24418,
- 27842, 28366, 28677, 28752, 28847, 29074, 29673, [29801, 63918], 33610,
- 34722, 34913, 36872, 37026, 37795, 39336, 20846, 24407, 24800, 24935,
- 26291, 34137, 36426, 37295, 38795, 20046, 20114, 21628, 22741, 22778,
- 22909, 23733, 24359, [12094, 25142], 25160, 26122, 26215, 27627, 28009,
- 28111, 28246, 28408, 28564, 28640, 28649, 28765, 29392, 29733, 29786,
- 29920, 30355, 31068, 31946, 32286, 32993, 33446, 33899, 33983, 34382,
- 34399, 34676, 35703, 35946, 37804, 38912, 39013, 24785, 25110, 37239,
- 23130, 26127, 28151, 28222, 29759, 39746, 24573, 24794, 31503, 21700,
- 24344, 27742, 27859, 27946, 28888, 32005, 34425, 35340, 40251, 21270,
- 21644, 23301, 27194, [12117, 28779], 30069, 31117, [12146, 31166], 33457,
- 33775, 35441, 35649, 36008, 38772, 25844, 25899, {f: 2, c: 30906}, 31339,
- 20024, 21914, 22864, 23462, 24187, 24739, 25563, 27489, 26213, 26707,
- 28185, 29029, 29872, 32008, 36996, 39529, 39973, 27963, [28369, 63748],
- 29502, 35905, 38346, 20976, 24140, 24488, 24653, 24822, 24880, 24908,
- {f: 2, c: 26179}, 27045, 27841, 28255, 28361, 28514, 29004, 29852, 30343,
- 31681, 31783, 33618, 34647, 36945, 38541, [12232, 40643], 21295, 22238,
- 24315, 24458, 24674, 24724, 25079, 26214, 26371, 27292, 28142, 28590,
- 28784, 29546, 32362, 33214, 33588, 34516, 35496, 36036, 21123, 29554,
- 23446, 27243, 37892, 21742, 22150, 23389, 25928, 25989, 26313, 26783,
- 28045, 28102, [12120, 29243], 32948, 37237, 39501, 20399, 20505, 21402,
- 21518, 21564, 21897, 21957, 24127, 24460, 26429, 29030, 29661, 36869,
- 21211, 21235, 22628, 22734, 28932, 29071, 29179, 34224, 35347,
- [26248, 63941], 34216, 21927, 26244, 29002, 33841, 21321, 21913, 27585,
- 24409, 24509, 25582, 26249, 28999, 35569, 36637, 40638, 20241, 25658,
- 28875, 30054, 34407, 24676, 35662, 40440, 20807, 20982, 21256, 27958,
- 33016, [12234, 40657], 26133, 27427, 28824, 30165, 21507, 23673, 32007,
- 35350, [12107, 27424], 27453, 27462, 21560, 24688, 27965, 32725, 33288,
- 20694, 20958, 21916, 22123, 22221, 23020, 23305, 24076, 24985, 24984,
- 25137, 26206, 26342, 29081, {f: 2, c: 29113}, 29351, 31143, 31232, 32690,
- 35440, {s: 163}, {f: 4, c: 12310}, {s: 14}, 8223, 8219, {f: 2, c: 8314},
- {s: 7}, 8316, 0, {f: 2, c: 8317}, {s: 23}, 700, {s: 44}, 8942, 8759,
- {s: 20}, {f: 10, c: 10122}, {s: 36}, {f: 26, c: 9398}, {s: 61},
- {f: 2, c: 8826}, {f: 2, c: 8910}, {f: 2, c: 8832}, {f: 4, c: 8816}, 0,
- 8842, 0, 8843, {f: 2, c: 8822}, 8825, {f: 2, c: 8922}, {s: 5}, 8773, 8771,
- 8776, 0, 8868, {s: 78}, 8244, {s: 11}, 9839, {s: 4}, 8258, {s: 4}, 10045,
- 0, 0, 8226, {s: 4}, {f: 2, c: 8249}, {s: 16}, 10010, 10006, 0, 9711,
- {s: 3}, 10070, 0, 9676, {s: 24}, 9775, {s: 6}, 12320, 0, {f: 10, c: 10102},
- {s: 17}, 12306, 12342, {s: 13}, 8710, 0, 8735, 0, {f: 2, c: 8741}, 0, 8787,
- 8785, {f: 2, c: 8806}, 8723, {f: 3, c: 8853}, 0, 8980, 0, 0, 8802, 0, 9649,
- 0, 8738, 8784, 0, 0, 8867, 0, 0, {f: 2, c: 8814}, 8837, 8836, 8713, 8716,
- {f: 2, c: 8891}, 8794, 8966, {s: 6}, 12958, 0, 8252, {s: 11}, 9702, {s: 3},
- 9663, 9653, 9657, 9667, {s: 4}, 9674, 12849, 12857, 13259, {f: 5, c: 9327},
- {s: 18}, 8656, 8655, 8653, {s: 37}, 8657, 8659, {s: 8}, 8626, 8625, 0,
- 8628, 8624, 8627, {s: 14}, 8636, 8640, {s: 10}, {f: 2, c: 8644}, {s: 144},
- {f: 5, c: 9347}, {s: 33}, 12948, {s: 15}, 12965, {s: 93}, 8672, 8674, 8673,
- 8675, {s: 4}, 8678, 8680, 8679, 8681, {s: 20}, 9757, 9759, {s: 76}, 12944,
- {f: 6, c: 12938}, {s: 15}, {f: 2, c: 12318}, 8246, 0, 8245, {s: 3}, 12540,
- 0, 0, {f: 2, c: 44034}, {f: 2, c: 44037}, {f: 5, c: 44043}, 44056,
- {f: 2, c: 44062}, {f: 3, c: 44065}, {f: 7, c: 44069}, 44078,
- {f: 6, c: 44082}, {f: 2, c: 44090}, {f: 3, c: 44093}, {f: 10, c: 44097},
- 44108, {f: 6, c: 44110}, {f: 3, c: 44117}, {f: 3, c: 44121},
- {f: 19, c: 44125}, {f: 2, c: 44146}, {f: 2, c: 44149}, 44153,
- {f: 5, c: 44155}, 44162, {f: 2, c: 44167}, {f: 3, c: 44173},
- {f: 3, c: 44177}, {f: 7, c: 44181}, 44190, {f: 6, c: 44194}, 44203,
- {f: 2, c: 44205}, {f: 7, c: 44209}, 44218, {f: 3, c: 44222},
- {f: 2, c: 44226}, {f: 3, c: 44229}, {f: 3, c: 44233}, {f: 8, c: 44237},
- 44246, {f: 8, c: 44248}, {f: 2, c: 44258}, {f: 2, c: 44261}, 44265, 44267,
- {f: 2, c: 44269}, 44274, 44276, {f: 5, c: 44279}, {f: 2, c: 44286},
- {f: 3, c: 44289}, 44293, {f: 5, c: 44295}, 44302, 44304, {f: 6, c: 44306},
- {f: 3, c: 44313}, {f: 3, c: 44317}, {f: 8, c: 44321}, {f: 2, c: 44330},
- {f: 6, c: 44334}, {f: 2, c: 44342}, {f: 3, c: 44345}, {f: 7, c: 44349},
- 44358, 44360, {f: 6, c: 44362}, {f: 3, c: 44369}, {f: 3, c: 44373},
- {f: 8, c: 44377}, 44386, {f: 8, c: 44388}, {f: 2, c: 44398},
- {f: 2, c: 44401}, {f: 4, c: 44407}, 44414, 44416, {f: 5, c: 44419},
- {f: 2, c: 44426}, {f: 3, c: 44429}, {f: 11, c: 44433}, {f: 6, c: 44446},
- {f: 18, c: 44453}, {f: 8, c: 44472}, {f: 2, c: 44482}, {f: 3, c: 44485},
- {f: 7, c: 44489}, 44498, {f: 8, c: 44500}, {f: 3, c: 44509},
- {f: 3, c: 44513}, {f: 19, c: 44517}, {f: 2, c: 44538}, {f: 2, c: 44541},
- {f: 6, c: 44546}, 44554, 44556, {f: 6, c: 44558}, {f: 27, c: 44565},
- {f: 2, c: 44594}, {f: 2, c: 44597}, 44601, {f: 5, c: 44603}, 44610, 44612,
- {f: 3, c: 44615}, 44619, 44623, {f: 3, c: 44625}, 44629, {f: 5, c: 44631},
- 44638, {f: 3, c: 44642}, {f: 2, c: 44646}, {f: 2, c: 44650},
- {f: 3, c: 44653}, {f: 7, c: 44657}, 44666, {f: 6, c: 44670},
- {f: 6, c: 44678}, {f: 47, c: 44685}, 44735, {f: 3, c: 44737},
- {f: 7, c: 44741}, 44750, {f: 6, c: 44754}, {f: 2, c: 44762},
- {f: 11, c: 44765}, {f: 2, c: 44777}, 44780, {f: 6, c: 44782},
- {f: 3, c: 44789}, {f: 3, c: 44793}, {f: 10, c: 44797}, {f: 4, c: 44809},
- {f: 2, c: 44814}, {f: 27, c: 44817}, {f: 2, c: 44846}, 44849, 44851,
- {f: 7, c: 44853}, 44862, 44864, {f: 4, c: 44868}, {f: 6, c: 44874},
- {f: 11, c: 44881}, {f: 6, c: 44894}, {f: 19, c: 44902}, {f: 6, c: 44922},
- {f: 3, c: 44929}, {f: 3, c: 44933}, {f: 7, c: 44937}, {f: 3, c: 44946},
- {f: 6, c: 44950}, {f: 27, c: 44957}, {f: 2, c: 44986}, {f: 3, c: 44989},
- {f: 6, c: 44993}, 45002, 45004, {f: 5, c: 45007}, {f: 7, c: 45013},
- {f: 11, c: 45021}, {f: 6, c: 45034}, {f: 2, c: 45042}, {f: 3, c: 45045},
- {f: 7, c: 45049}, {f: 2, c: 45058}, {f: 7, c: 45061}, {f: 3, c: 45069},
- {f: 3, c: 45073}, {f: 7, c: 45077}, {f: 10, c: 45086}, {f: 27, c: 45097},
- {f: 2, c: 45126}, 45129, 45131, 45133, {f: 4, c: 45135}, 45142, 45144,
- {f: 3, c: 45146}, {f: 30, c: 45150}, {f: 2, c: 45182}, {f: 3, c: 45185},
- {f: 7, c: 45189}, 45198, 45200, {f: 6, c: 45202}, 45211, {f: 2, c: 45213},
- {f: 5, c: 45219}, 45226, 45232, 45234, {f: 2, c: 45238}, {f: 3, c: 45241},
- {f: 7, c: 45245}, 45254, {f: 6, c: 45258}, {f: 2, c: 45266},
- {f: 3, c: 45269}, {f: 7, c: 45273}, {f: 4, c: 45281}, {f: 34, c: 45286},
- 45322, {f: 3, c: 45325}, 45329, {f: 4, c: 45332}, 45338, {f: 5, c: 45342},
- {f: 2, c: 45350}, {f: 3, c: 45353}, {f: 7, c: 45357}, 45366,
- {f: 6, c: 45370}, {f: 2, c: 45378}, {f: 3, c: 45381}, {f: 7, c: 45385},
- {f: 2, c: 45394}, {f: 2, c: 45398}, {f: 3, c: 45401}, {f: 3, c: 45405},
- {f: 23, c: 45409}, {f: 2, c: 45434}, {f: 3, c: 45437}, 45441,
- {f: 5, c: 45443}, 45450, 45452, {f: 4, c: 45454}, {f: 3, c: 45461},
- {f: 3, c: 45465}, {f: 11, c: 45469}, {f: 35, c: 45481}, {f: 3, c: 45517},
- {f: 3, c: 45521}, {f: 7, c: 45525}, 45534, {f: 8, c: 45536},
- {f: 2, c: 45546}, {f: 3, c: 45549}, {f: 8, c: 45553}, 45562, 45564,
- {f: 6, c: 45566}, {f: 2, c: 45574}, {f: 2, c: 45577}, {f: 7, c: 45581},
- 45590, 45592, {f: 6, c: 45594}, {f: 19, c: 45601}, {f: 7, c: 45621},
- {f: 27, c: 45629}, {f: 3, c: 45657}, {f: 3, c: 45661}, {f: 7, c: 45665},
- {f: 10, c: 45674}, {f: 6, c: 45686}, {f: 7, c: 45693}, {f: 3, c: 45702},
- {f: 6, c: 45706}, {f: 2, c: 45714}, {f: 3, c: 45717}, {f: 5, c: 45723},
- 45730, 45732, {f: 3, c: 45735}, 45739, {f: 3, c: 45741}, {f: 3, c: 45745},
- {f: 19, c: 45749}, {f: 2, c: 45770}, {f: 3, c: 45773}, 45777,
- {f: 5, c: 45779}, 45786, 45788, {f: 4, c: 45790}, 45795, 45799,
- {f: 2, c: 45801}, {f: 3, c: 45808}, 45814, {f: 3, c: 45820},
- {f: 2, c: 45826}, {f: 3, c: 45829}, {f: 7, c: 45833}, 45842,
- {f: 6, c: 45846}, {f: 55, c: 45853}, 45911, {f: 2, c: 45913}, 45917,
- {f: 4, c: 45920}, 45926, 45928, 45930, {f: 2, c: 45932}, 45935,
- {f: 2, c: 45938}, {f: 3, c: 45941}, {f: 7, c: 45945}, 45954,
- {f: 6, c: 45958}, {f: 3, c: 45965}, {f: 3, c: 45969}, {f: 11, c: 45973},
- {f: 6, c: 45986}, {f: 3, c: 45993}, {f: 23, c: 45997}, {f: 2, c: 46022},
- {f: 2, c: 46025}, 46029, 46031, {f: 3, c: 46033}, 46038, 46040, 46042,
- 46044, {f: 2, c: 46046}, {f: 3, c: 46049}, {f: 3, c: 46053},
- {f: 19, c: 46057}, {f: 19, c: 46077}, {f: 7, c: 46097}, {f: 3, c: 46105},
- {f: 3, c: 46109}, {f: 7, c: 46113}, 46122, {f: 8, c: 46124},
- {f: 27, c: 46133}, {f: 2, c: 46162}, {f: 3, c: 46165}, {f: 7, c: 46169},
- 46178, 46180, {f: 6, c: 46182}, {f: 19, c: 46189}, {f: 7, c: 46209},
- {f: 20, c: 46217}, {f: 6, c: 46238}, {f: 3, c: 46245}, {f: 3, c: 46249},
- {f: 8, c: 46253}, 46262, 46264, {f: 6, c: 46266}, {f: 3, c: 46273},
- {f: 3, c: 46277}, {f: 7, c: 46281}, {f: 4, c: 46289}, {f: 6, c: 46294},
- {f: 2, c: 46302}, {f: 2, c: 46305}, 46309, {f: 5, c: 46311}, 46318, 46320,
- {f: 6, c: 46322}, {f: 27, c: 46329}, {f: 2, c: 46358}, {f: 2, c: 46361},
- {f: 7, c: 46365}, 46374, {f: 5, c: 46379}, {f: 2, c: 46386},
- {f: 3, c: 46389}, {f: 7, c: 46393}, 46402, {f: 5, c: 46406},
- {f: 2, c: 46414}, {f: 3, c: 46417}, {f: 7, c: 46421}, 46430,
- {f: 62, c: 46434}, {f: 2, c: 46498}, {f: 3, c: 46501}, 46505,
- {f: 4, c: 46508}, 46514, {f: 5, c: 46518}, {f: 2, c: 46526},
- {f: 3, c: 46529}, {f: 7, c: 46533}, 46542, {f: 6, c: 46546},
- {f: 19, c: 46553}, {f: 35, c: 46573}, {f: 2, c: 46610}, {f: 3, c: 46613},
- {f: 12, c: 46617}, {f: 6, c: 46630}, {f: 7, c: 46637}, {f: 19, c: 46645},
- {f: 27, c: 46665}, {f: 3, c: 46693}, {f: 51, c: 46697}, {f: 2, c: 46750},
- {f: 3, c: 46753}, {f: 6, c: 46757}, {f: 4, c: 46765}, {f: 34, c: 46770},
- {f: 27, c: 46805}, {f: 3, c: 46833}, {f: 3, c: 46837}, {f: 7, c: 46841},
- {f: 3, c: 46850}, {f: 34, c: 46854}, {f: 2, c: 46890}, {f: 2, c: 46893},
- {f: 7, c: 46897}, 46906, {f: 8, c: 46908}, {f: 3, c: 46917},
- {f: 3, c: 46921}, {f: 7, c: 46925}, {f: 10, c: 46934}, {f: 3, c: 46945},
- {f: 3, c: 46949}, {f: 7, c: 46953}, 46962, 46964, {f: 6, c: 46966},
- {f: 2, c: 46974}, {f: 3, c: 46977}, {f: 7, c: 46981}, 46990,
- {f: 3, c: 46995}, {f: 2, c: 47002}, {f: 3, c: 47005}, {f: 7, c: 47009},
- 47018, {f: 6, c: 47022}, {f: 2, c: 47030}, {f: 14, c: 47033}, 47048,
- {f: 34, c: 47050}, {f: 2, c: 47086}, {f: 3, c: 47089}, {f: 7, c: 47093},
- 47102, {f: 5, c: 47106}, {f: 2, c: 47114}, {f: 3, c: 47117},
- {f: 7, c: 47121}, 47130, 47132, {f: 6, c: 47134}, {f: 2, c: 47142},
- {f: 3, c: 47145}, {f: 7, c: 47149}, 47158, {f: 6, c: 47162},
- {f: 3, c: 47169}, {f: 12, c: 47173}, 47186, {f: 8, c: 47188},
- {f: 2, c: 47198}, {f: 3, c: 47201}, {f: 7, c: 47205}, 47214, 47216,
- {f: 6, c: 47218}, {f: 3, c: 47225}, {f: 16, c: 47229}, {f: 26, c: 47246},
- {f: 7, c: 47273}, {f: 3, c: 47281}, {f: 3, c: 47285}, {f: 7, c: 47289},
- 47298, 47300, {f: 6, c: 47302}, {f: 3, c: 47309}, {f: 3, c: 47313},
- {f: 8, c: 47317}, 47326, 47328, {f: 6, c: 47330}, {f: 2, c: 47338},
- {f: 3, c: 47341}, {f: 7, c: 47345}, 47354, 47356, {f: 6, c: 47358},
- {f: 19, c: 47365}, {f: 7, c: 47385}, {f: 27, c: 47393}, {f: 2, c: 47422},
- {f: 3, c: 47425}, {f: 7, c: 47429}, {f: 2, c: 47437}, 47440,
- {f: 6, c: 47442}, {f: 2, c: 47450}, {f: 3, c: 47453}, {f: 7, c: 47457},
- 47466, 47468, {f: 6, c: 47470}, {f: 2, c: 47478}, {f: 3, c: 47481},
- {f: 7, c: 47485}, 47494, 47496, {f: 2, c: 47499}, {f: 29, c: 47503},
- {f: 2, c: 47534}, {f: 3, c: 47537}, {f: 7, c: 47541}, 47550, 47552,
- {f: 6, c: 47554}, {f: 2, c: 47562}, 47565, {f: 5, c: 47571}, 47578, 47580,
- {f: 2, c: 47583}, 47586, {f: 2, c: 47590}, {f: 3, c: 47593},
- {f: 7, c: 47597}, 47606, {f: 5, c: 47611}, {f: 6, c: 47618},
- {f: 12, c: 47625}, {f: 34, c: 47638}, {f: 2, c: 47674}, {f: 3, c: 47677},
- 47681, {f: 5, c: 47683}, 47690, 47692, {f: 4, c: 47695}, {f: 2, c: 47702},
- {f: 3, c: 47705}, {f: 7, c: 47709}, 47718, {f: 6, c: 47722},
- {f: 2, c: 47730}, {f: 3, c: 47733}, {f: 10, c: 47737}, 47750,
- {f: 4, c: 47752}, {f: 27, c: 47757}, 47786, {f: 3, c: 47789}, 47793,
- {f: 5, c: 47795}, 47802, 47804, {f: 6, c: 47806}, {f: 3, c: 47813},
- {f: 15, c: 47817}, {f: 34, c: 47834}, {f: 3, c: 47869}, {f: 3, c: 47873},
- {f: 8, c: 47877}, 47886, 47888, {f: 6, c: 47890}, {f: 3, c: 47897},
- {f: 3, c: 47901}, {f: 8, c: 47905}, 47914, {f: 8, c: 47916}, 47927,
- {f: 2, c: 47929}, {f: 5, c: 47935}, 47942, 47944, {f: 3, c: 47946}, 47950,
- {f: 3, c: 47953}, {f: 3, c: 47957}, {f: 8, c: 47961}, 47970,
- {f: 8, c: 47972}, {f: 27, c: 47981}, {f: 3, c: 48009}, {f: 3, c: 48013},
- {f: 19, c: 48017}, {f: 3, c: 48037}, {f: 3, c: 48041}, {f: 7, c: 48045},
- {f: 2, c: 48053}, {f: 8, c: 48056}, {f: 3, c: 48065}, {f: 3, c: 48069},
- {f: 7, c: 48073}, {f: 2, c: 48081}, {f: 36, c: 48084}, {f: 2, c: 48122},
- {f: 2, c: 48125}, 48129, {f: 5, c: 48131}, 48138, 48142, 48144,
- {f: 2, c: 48146}, {f: 2, c: 48153}, {f: 4, c: 48160}, 48166, 48168,
- {f: 3, c: 48170}, {f: 2, c: 48174}, {f: 2, c: 48178}, {f: 3, c: 48181},
- {f: 7, c: 48185}, 48194, {f: 3, c: 48198}, {f: 2, c: 48202},
- {f: 2, c: 48206}, {f: 12, c: 48209}, {f: 38, c: 48222}, {f: 2, c: 48262},
- {f: 2, c: 48265}, 48269, {f: 5, c: 48271}, 48278, 48280, {f: 5, c: 48283},
- {f: 2, c: 48290}, {f: 2, c: 48293}, {f: 7, c: 48297}, 48306,
- {f: 6, c: 48310}, {f: 2, c: 48318}, {f: 3, c: 48321}, {f: 8, c: 48325},
- 48334, {f: 3, c: 48338}, {f: 2, c: 48342}, {f: 3, c: 48345},
- {f: 23, c: 48349}, 48375, {f: 3, c: 48377}, {f: 7, c: 48381}, 48390, 48392,
- {f: 6, c: 48394}, {f: 3, c: 48401}, {f: 15, c: 48405}, {f: 7, c: 48421},
- {f: 19, c: 48429}, {f: 7, c: 48449}, {f: 2, c: 48458}, {f: 3, c: 48461},
- {f: 7, c: 48465}, {f: 10, c: 48474}, {f: 3, c: 48485}, {f: 23, c: 48489},
- {f: 2, c: 48514}, {f: 2, c: 48517}, {f: 5, c: 48523}, 48530, 48532,
- {f: 3, c: 48534}, 48539, {f: 7, c: 48541}, {f: 11, c: 48549},
- {f: 7, c: 48561}, {f: 27, c: 48569}, {f: 2, c: 48598}, {f: 3, c: 48601},
- {f: 12, c: 48605}, {f: 6, c: 48618}, {f: 3, c: 48625}, {f: 3, c: 48629},
- {f: 7, c: 48633}, {f: 2, c: 48641}, 48644, {f: 6, c: 48646},
- {f: 2, c: 48654}, {f: 3, c: 48657}, {f: 7, c: 48661}, 48670,
- {f: 36, c: 48672}, {f: 2, c: 48710}, {f: 3, c: 48713}, 48717,
- {f: 5, c: 48719}, 48726, 48728, {f: 4, c: 48732}, {f: 2, c: 48738},
- {f: 3, c: 48741}, 48745, {f: 5, c: 48747}, 48754, {f: 5, c: 48758},
- {f: 2, c: 48766}, {f: 3, c: 48769}, {f: 7, c: 48773}, 48782,
- {f: 6, c: 48786}, {f: 14, c: 48794}, {f: 39, c: 48809}, {f: 2, c: 48850},
- {f: 2, c: 48853}, {f: 7, c: 48857}, {f: 2, c: 48865}, {f: 6, c: 48870},
- {f: 20, c: 48877}, {f: 6, c: 48898}, {f: 14, c: 48906}, 48922,
- {f: 34, c: 48926}, {f: 2, c: 48962}, {f: 3, c: 48965}, {f: 7, c: 48969},
- {f: 3, c: 48978}, {f: 62, c: 48982}, {f: 27, c: 49045}, {f: 20, c: 49073},
- {f: 6, c: 49094}, {f: 2, c: 49102}, {f: 3, c: 49105}, {f: 7, c: 49109},
- {f: 2, c: 49117}, 49120, {f: 90, c: 49122}, {f: 20, c: 49213},
- {f: 6, c: 49234}, {f: 3, c: 49241}, {f: 3, c: 49245}, {f: 7, c: 49249},
- {f: 38, c: 49258}, {f: 2, c: 49298}, {f: 3, c: 49301}, {f: 7, c: 49305},
- 49314, 49316, {f: 6, c: 49318}, 49326, {f: 2, c: 49329}, {f: 5, c: 49335},
- 49342, {f: 3, c: 49346}, {f: 2, c: 49350}, {f: 2, c: 49354},
- {f: 3, c: 49357}, {f: 7, c: 49361}, 49370, {f: 6, c: 49374},
- {f: 2, c: 49382}, {f: 3, c: 49385}, {f: 7, c: 49389}, 49398, 49400,
- {f: 6, c: 49402}, {f: 3, c: 49409}, {f: 3, c: 49413}, {f: 7, c: 49417},
- {f: 4, c: 49425}, {f: 6, c: 49430}, {f: 2, c: 49441}, 49445,
- {f: 4, c: 49448}, 49454, {f: 4, c: 49458}, 49463, {f: 2, c: 49466},
- {f: 3, c: 49469}, {f: 7, c: 49473}, 49482, {f: 6, c: 49486},
- {f: 2, c: 49494}, {f: 3, c: 49497}, {f: 7, c: 49501}, 49510,
- {f: 6, c: 49514}, {f: 3, c: 49521}, {f: 3, c: 49525}, {f: 12, c: 49529},
- {f: 6, c: 49542}, 49551, {f: 3, c: 49553}, 49557, {f: 5, c: 49559}, 49566,
- 49568, {f: 3, c: 49570}, {f: 2, c: 49574}, {f: 2, c: 49578},
- {f: 3, c: 49581}, {f: 12, c: 49585}, {f: 6, c: 49598}, {f: 3, c: 49605},
- {f: 3, c: 49609}, {f: 7, c: 49613}, {f: 2, c: 49621}, {f: 7, c: 49625},
- {f: 3, c: 49633}, {f: 3, c: 49637}, {f: 7, c: 49641}, 49650,
- {f: 8, c: 49652}, {f: 2, c: 49662}, {f: 3, c: 49665}, {f: 7, c: 49669},
- 49678, 49680, {f: 6, c: 49682}, {f: 2, c: 49690}, {f: 2, c: 49693},
- {f: 7, c: 49697}, 49706, 49708, 49710, 49712, 49715, {f: 19, c: 49717},
- {f: 7, c: 49737}, {f: 2, c: 49746}, {f: 3, c: 49749}, {f: 7, c: 49753},
- {f: 4, c: 49761}, {f: 6, c: 49766}, {f: 2, c: 49774}, {f: 3, c: 49777},
- {f: 7, c: 49781}, 49790, 49792, {f: 6, c: 49794}, {f: 6, c: 49802},
- {f: 7, c: 49809}, {f: 2, c: 49817}, 49820, {f: 6, c: 49822},
- {f: 2, c: 49830}, {f: 3, c: 49833}, {f: 6, c: 49838}, 49846, 49848,
- {f: 34, c: 49850}, {f: 2, c: 49886}, {f: 2, c: 49889}, {f: 6, c: 49893},
- 49902, 49904, {f: 4, c: 49906}, 49911, 49914, {f: 3, c: 49917},
- {f: 7, c: 49921}, {f: 2, c: 49930}, {f: 5, c: 49934}, {f: 2, c: 49942},
- {f: 3, c: 49945}, {f: 7, c: 49949}, {f: 2, c: 49958}, {f: 27, c: 49962},
- {f: 34, c: 49990}, {f: 2, c: 50026}, {f: 3, c: 50029}, 50033,
- {f: 5, c: 50035}, {f: 2, c: 50042}, {f: 6, c: 50046}, {f: 3, c: 50053},
- {f: 3, c: 50057}, {f: 51, c: 50061}, {f: 23, c: 50113}, {f: 2, c: 50138},
- {f: 2, c: 50141}, 50145, {f: 5, c: 50147}, {f: 3, c: 50154},
- {f: 6, c: 50158}, {f: 2, c: 50166}, {f: 15, c: 50169}, {f: 7, c: 50185},
- {f: 19, c: 50193}, {f: 7, c: 50213}, {f: 3, c: 50221}, {f: 3, c: 50225},
- {f: 7, c: 50229}, {f: 10, c: 50238}, {f: 27, c: 50249}, {f: 2, c: 50278},
- {f: 3, c: 50281}, {f: 7, c: 50285}, {f: 3, c: 50294}, {f: 6, c: 50298},
- {f: 19, c: 50305}, {f: 7, c: 50325}, {f: 27, c: 50333}, {f: 3, c: 50361},
- {f: 44, c: 50365}, {f: 6, c: 50410}, {f: 2, c: 50418}, {f: 3, c: 50421},
- 50425, {f: 4, c: 50427}, {f: 10, c: 50434}, {f: 3, c: 50445},
- {f: 3, c: 50449}, {f: 7, c: 50453}, {f: 11, c: 50461}, {f: 2, c: 50474},
- {f: 3, c: 50477}, {f: 7, c: 50481}, 50490, 50492, {f: 6, c: 50494},
- {f: 2, c: 50502}, 50507, {f: 4, c: 50511}, 50518, {f: 3, c: 50522}, 50527,
- {f: 2, c: 50530}, {f: 3, c: 50533}, {f: 7, c: 50537}, 50546,
- {f: 6, c: 50550}, {f: 2, c: 50558}, {f: 3, c: 50561}, {f: 2, c: 50565},
- {f: 4, c: 50568}, 50574, 50576, {f: 3, c: 50578}, 50582, {f: 3, c: 50585},
- {f: 3, c: 50589}, {f: 8, c: 50593}, {f: 10, c: 50602}, {f: 2, c: 50614},
- 50618, {f: 5, c: 50623}, 50635, 50637, 50639, {f: 2, c: 50642},
- {f: 3, c: 50645}, {f: 7, c: 50649}, 50658, 50660, {f: 6, c: 50662}, 50671,
- {f: 3, c: 50673}, 50677, {f: 4, c: 50680}, {f: 3, c: 50690},
- {f: 3, c: 50697}, {f: 3, c: 50701}, {f: 7, c: 50705}, 50714,
- {f: 7, c: 50717}, {f: 2, c: 50726}, {f: 3, c: 50729}, 50735,
- {f: 2, c: 50737}, 50742, 50744, 50746, {f: 4, c: 50748}, {f: 2, c: 50754},
- {f: 3, c: 50757}, {f: 7, c: 50761}, 50770, {f: 6, c: 50774},
- {f: 2, c: 50782}, {f: 11, c: 50785}, {f: 2, c: 50797}, 50800,
- {f: 6, c: 50802}, {f: 2, c: 50810}, {f: 3, c: 50813}, {f: 7, c: 50817},
- 50826, 50828, {f: 6, c: 50830}, {f: 2, c: 50838}, {f: 3, c: 50841},
- {f: 7, c: 50845}, 50854, 50856, {f: 6, c: 50858}, {f: 2, c: 50866},
- {f: 3, c: 50869}, {f: 5, c: 50875}, 50882, 50884, {f: 6, c: 50886},
- {f: 2, c: 50894}, {f: 3, c: 50897}, {f: 7, c: 50901}, {f: 2, c: 50910},
- {f: 6, c: 50914}, {f: 2, c: 50922}, {f: 3, c: 50925}, {f: 7, c: 50929},
- {f: 3, c: 50938}, {f: 6, c: 50942}, {f: 2, c: 50950}, {f: 3, c: 50953},
- {f: 7, c: 50957}, 50966, 50968, {f: 6, c: 50970}, {f: 2, c: 50978},
- {f: 3, c: 50981}, {f: 7, c: 50985}, 50994, 50996, 50998, {f: 4, c: 51000},
- {f: 2, c: 51006}, {f: 3, c: 51009}, {f: 5, c: 51013}, 51019, 51022, 51024,
- {f: 3, c: 51033}, {f: 3, c: 51037}, {f: 7, c: 51041}, {f: 2, c: 51049},
- {f: 8, c: 51052}, {f: 2, c: 51062}, {f: 3, c: 51065}, {f: 4, c: 51071},
- 51078, {f: 3, c: 51083}, 51087, {f: 2, c: 51090}, 51093, 51097,
- {f: 5, c: 51099}, 51106, {f: 5, c: 51111}, {f: 2, c: 51118},
- {f: 3, c: 51121}, {f: 7, c: 51125}, 51134, {f: 6, c: 51138},
- {f: 2, c: 51146}, 51149, 51151, {f: 7, c: 51153}, {f: 4, c: 51161},
- {f: 6, c: 51166}, {f: 3, c: 51173}, {f: 3, c: 51177}, {f: 19, c: 51181},
- {f: 2, c: 51202}, {f: 3, c: 51205}, 51209, {f: 5, c: 51211}, 51218, 51220,
- {f: 5, c: 51223}, {f: 2, c: 51230}, {f: 3, c: 51233}, {f: 7, c: 51237},
- 51246, 51248, {f: 6, c: 51250}, {f: 3, c: 51257}, {f: 3, c: 51261},
- {f: 7, c: 51265}, {f: 2, c: 51274}, {f: 6, c: 51278}, {f: 27, c: 51285},
- {f: 2, c: 51314}, {f: 3, c: 51317}, 51321, {f: 5, c: 51323}, 51330, 51332,
- {f: 3, c: 51336}, {f: 6, c: 51342}, {f: 8, c: 51349}, 51358, 51360,
- {f: 6, c: 51362}, {f: 19, c: 51369}, {f: 6, c: 51390}, {f: 3, c: 51397},
- {f: 3, c: 51401}, {f: 7, c: 51405}, 51414, 51416, {f: 6, c: 51418},
- {f: 2, c: 51426}, {f: 16, c: 51429}, {f: 6, c: 51446}, {f: 2, c: 51454},
- {f: 3, c: 51457}, {f: 5, c: 51463}, 51470, 51472, {f: 6, c: 51474},
- {f: 19, c: 51481}, {f: 7, c: 51501}, {f: 27, c: 51509}, {f: 2, c: 51538},
- {f: 3, c: 51541}, {f: 7, c: 51545}, 51554, {f: 8, c: 51556},
- {f: 3, c: 51565}, {f: 3, c: 51569}, {f: 7, c: 51573}, {f: 11, c: 51581},
- {f: 2, c: 51594}, {f: 3, c: 51597}, {f: 7, c: 51601}, 51610, 51612,
- {f: 34, c: 51614}, {f: 2, c: 51650}, {f: 2, c: 51653}, 51657,
- {f: 5, c: 51659}, 51666, 51668, {f: 2, c: 51671}, 51675, {f: 2, c: 51678},
- 51681, 51683, {f: 2, c: 51685}, {f: 4, c: 51688}, 51694, {f: 6, c: 51698},
- {f: 2, c: 51706}, {f: 3, c: 51709}, {f: 7, c: 51713}, 51722,
- {f: 6, c: 51726}, {f: 3, c: 51733}, {f: 16, c: 51737}, {f: 34, c: 51754},
- {f: 2, c: 51790}, {f: 3, c: 51793}, {f: 7, c: 51797}, 51806,
- {f: 6, c: 51810}, {f: 20, c: 51817}, {f: 6, c: 51838}, {f: 19, c: 51845},
- {f: 35, c: 51865}, {f: 2, c: 51902}, {f: 3, c: 51905}, {f: 7, c: 51909},
- 51918, 51920, 51922, {f: 4, c: 51924}, {f: 6, c: 51930}, {f: 11, c: 51937},
- {f: 7, c: 51949}, {f: 19, c: 51957}, {f: 7, c: 51977}, {f: 3, c: 51985},
- {f: 3, c: 51989}, {f: 7, c: 51993}, {f: 31, c: 52002}, {f: 6, c: 52034},
- {f: 2, c: 52042}, {f: 3, c: 52045}, {f: 7, c: 52049}, {f: 3, c: 52058},
- {f: 6, c: 52062}, {f: 19, c: 52069}, {f: 34, c: 52090}, {f: 27, c: 52125},
- {f: 27, c: 52153}, {f: 15, c: 52181}, {f: 2, c: 52197}, 52200,
- {f: 34, c: 52202}, {f: 2, c: 52238}, {f: 3, c: 52241}, {f: 7, c: 52245},
- {f: 3, c: 52254}, {f: 4, c: 52259}, {f: 2, c: 52266}, 52269, 52271,
- {f: 7, c: 52273}, 52282, {f: 5, c: 52287}, {f: 2, c: 52294},
- {f: 3, c: 52297}, {f: 7, c: 52301}, 52310, {f: 6, c: 52314},
- {f: 3, c: 52321}, 52325, 52327, {f: 7, c: 52329}, {f: 4, c: 52337},
- {f: 34, c: 52342}, {f: 2, c: 52378}, {f: 3, c: 52381}, {f: 7, c: 52385},
- 52394, {f: 6, c: 52398}, {f: 2, c: 52406}, {f: 3, c: 52409},
- {f: 7, c: 52413}, 52422, 52424, {f: 6, c: 52426}, {f: 3, c: 52433},
- {f: 15, c: 52437}, {f: 7, c: 52453}, {f: 3, c: 52461}, {f: 16, c: 52465},
- {f: 6, c: 52482}, {f: 2, c: 52490}, {f: 3, c: 52493}, {f: 7, c: 52497},
- 52506, 52508, {f: 6, c: 52510}, {f: 3, c: 52517}, {f: 3, c: 52521},
- {f: 12, c: 52525}, {f: 34, c: 52538}, {f: 3, c: 52573}, {f: 3, c: 52577},
- {f: 7, c: 52581}, 52590, 52592, {f: 6, c: 52594}, {f: 15, c: 52601},
- {f: 11, c: 52617}, {f: 2, c: 52630}, {f: 3, c: 52633}, {f: 7, c: 52637},
- 52646, 52648, {f: 6, c: 52650}, {f: 19, c: 52657}, {f: 7, c: 52677},
- {f: 3, c: 52685}, {f: 23, c: 52689}, {f: 3, c: 52713}, {f: 3, c: 52717},
- {f: 7, c: 52721}, 52730, 52732, {f: 6, c: 52734}, {f: 3, c: 52741},
- {f: 3, c: 52745}, {f: 7, c: 52749}, {f: 4, c: 52757}, {f: 6, c: 52762},
- {f: 2, c: 52770}, {f: 3, c: 52773}, {f: 7, c: 52777}, 52786, 52788,
- {f: 34, c: 52790}, {f: 2, c: 52826}, {f: 2, c: 52829}, {f: 6, c: 52834},
- 52842, 52844, {f: 6, c: 52846}, {f: 2, c: 52854}, {f: 3, c: 52857},
- {f: 7, c: 52861}, 52870, 52872, {f: 6, c: 52874}, {f: 2, c: 52882},
- {f: 3, c: 52885}, {f: 7, c: 52889}, 52898, {f: 6, c: 52902},
- {f: 19, c: 52910}, {f: 34, c: 52930}, {f: 2, c: 52966}, {f: 2, c: 52969},
- {f: 7, c: 52973}, 52982, {f: 6, c: 52986}, {f: 2, c: 52994},
- {f: 3, c: 52997}, {f: 7, c: 53001}, 53010, 53012, {f: 6, c: 53014},
- {f: 3, c: 53021}, {f: 3, c: 53025}, {f: 7, c: 53029}, 53038,
- {f: 6, c: 53042}, {f: 27, c: 53049}, {f: 2, c: 53078}, {f: 3, c: 53081},
- {f: 7, c: 53085}, 53094, 53096, {f: 6, c: 53098}, {f: 2, c: 53106},
- {f: 3, c: 53109}, {f: 7, c: 53113}, {f: 4, c: 53121}, {f: 6, c: 53126},
- {f: 20, c: 53133}, {f: 6, c: 53154}, {f: 7, c: 53161}, {f: 19, c: 53169},
- {f: 27, c: 53189}, {f: 2, c: 53218}, {f: 3, c: 53221}, {f: 7, c: 53225},
- 53234, 53236, {f: 6, c: 53238}, {f: 3, c: 53245}, {f: 3, c: 53249},
- {f: 12, c: 53253}, {f: 6, c: 53266}, {f: 20, c: 53273}, {f: 6, c: 53294},
- {f: 2, c: 53302}, {f: 3, c: 53305}, {f: 7, c: 53309}, 53318, 53320,
- {f: 6, c: 53322}, {f: 3, c: 53329}, {f: 3, c: 53333}, {f: 7, c: 53337},
- {f: 11, c: 53345}, {f: 2, c: 53358}, {f: 3, c: 53361}, {f: 7, c: 53365},
- {f: 3, c: 53374}, {f: 34, c: 53378}, {f: 2, c: 53414}, {f: 3, c: 53417},
- {f: 7, c: 53421}, 53430, 53432, {f: 6, c: 53434}, {f: 2, c: 53442},
- {f: 3, c: 53445}, {f: 6, c: 53450}, 53458, {f: 6, c: 53462},
- {f: 2, c: 53470}, {f: 3, c: 53473}, {f: 7, c: 53477}, 53486,
- {f: 6, c: 53490}, {f: 20, c: 53497}, {f: 34, c: 53518}, {f: 2, c: 53554},
- {f: 3, c: 53557}, 53561, {f: 5, c: 53563}, 53570, {f: 6, c: 53574},
- {f: 2, c: 53582}, {f: 3, c: 53585}, {f: 7, c: 53589}, 53598, 53600,
- {f: 6, c: 53602}, {f: 3, c: 53609}, {f: 15, c: 53613}, {f: 7, c: 53629},
- {f: 3, c: 53637}, {f: 23, c: 53641}, {f: 2, c: 53666}, {f: 3, c: 53669},
- {f: 7, c: 53673}, 53682, 53684, {f: 4, c: 53686}, 53691, {f: 3, c: 53693},
- {f: 23, c: 53697}, {f: 27, c: 53721}, {f: 3, c: 53749}, {f: 14, c: 53753},
- 53768, {f: 6, c: 53770}, {f: 27, c: 53777}, {f: 2, c: 53806},
- {f: 3, c: 53809}, {f: 7, c: 53813}, 53822, 53824, {f: 6, c: 53826},
- {f: 19, c: 53833}, {f: 7, c: 53853}, {f: 27, c: 53861}, {f: 2, c: 53890},
- {f: 3, c: 53893}, {f: 7, c: 53897}, {f: 3, c: 53906}, {f: 6, c: 53910},
- {f: 3, c: 53917}, {f: 3, c: 53921}, {f: 7, c: 53925}, {f: 4, c: 53933},
- {f: 6, c: 53938}, {f: 2, c: 53946}, {f: 2, c: 53949}, 53953,
- {f: 5, c: 53955}, 53962, {f: 8, c: 53964}, {f: 3, c: 53973},
- {f: 3, c: 53977}, {f: 7, c: 53981}, {f: 10, c: 53990}, {f: 2, c: 54002},
- {f: 3, c: 54005}, {f: 7, c: 54009}, 54018, 54020, {f: 6, c: 54022}, 54031,
- {f: 3, c: 54033}, 54037, {f: 5, c: 54039}, 54046, {f: 3, c: 54050},
- {f: 2, c: 54054}, {f: 2, c: 54058}, {f: 3, c: 54061}, {f: 7, c: 54065},
- 54074, {f: 6, c: 54078}, {f: 54, c: 54086}, {f: 2, c: 54142},
- {f: 3, c: 54145}, {f: 7, c: 54149}, 54158, {f: 6, c: 54162},
- {f: 2, c: 54170}, {f: 3, c: 54173}, {f: 7, c: 54177}, 54186, 54188,
- {f: 6, c: 54190}, {f: 3, c: 54197}, {f: 3, c: 54201}, {f: 7, c: 54205},
- {f: 2, c: 54214}, {f: 6, c: 54218}, {f: 7, c: 54225}, {f: 8, c: 54233},
- 54242, {f: 8, c: 54244}, {f: 2, c: 54254}, {f: 3, c: 54257},
- {f: 7, c: 54261}, 54270, 54272, {f: 6, c: 54274}, {f: 20, c: 54281},
- {f: 34, c: 54302}, {f: 3, c: 54337}, {f: 23, c: 54341}, {f: 3, c: 54365},
- {f: 3, c: 54369}, {f: 8, c: 54373}, 54382, {f: 8, c: 54384},
- {f: 2, c: 54394}, {f: 2, c: 54397}, 54401, {f: 5, c: 54403}, 54410, 54412,
- {f: 6, c: 54414}, {f: 20, c: 54421}, {f: 34, c: 54442}, {f: 3, c: 54477},
- {f: 3, c: 54481}, {f: 7, c: 54485}, {f: 2, c: 54493}, {f: 8, c: 54496},
- {f: 3, c: 54505}, {f: 3, c: 54509}, {f: 7, c: 54513}, {f: 2, c: 54521},
- 54524, {f: 6, c: 54526}, {f: 3, c: 54533}, {f: 3, c: 54537},
- {f: 7, c: 54541}, 54550, {f: 36, c: 54552}, {f: 2, c: 54590},
- {f: 3, c: 54593}, {f: 7, c: 54597}, 54606, 54608, {f: 6, c: 54610},
- {f: 2, c: 54618}, {f: 3, c: 54621}, {f: 4, c: 54625}, {f: 2, c: 54630},
- 54634, 54636, {f: 6, c: 54638}, {f: 2, c: 54646}, {f: 3, c: 54649},
- {f: 7, c: 54653}, 54662, {f: 6, c: 54666}, {f: 20, c: 54673},
- {f: 34, c: 54694}, {f: 2, c: 54730}, {f: 3, c: 54733}, 54737,
- {f: 5, c: 54739}, 54746, 54748, {f: 6, c: 54750}, {f: 2, c: 54758},
- {f: 3, c: 54761}, {f: 7, c: 54765}, 54774, 54776, {f: 6, c: 54778},
- {f: 2, c: 54786}, {f: 3, c: 54789}, {f: 7, c: 54793}, 54802,
- {f: 6, c: 54806}, {f: 3, c: 54813}, {f: 3, c: 54817}, {f: 8, c: 54821},
- {f: 10, c: 54830}, {f: 2, c: 54842}, {f: 3, c: 54845}, {f: 4, c: 54849},
- {f: 2, c: 54854}, 54858, 54860, {f: 3, c: 54862}, {f: 2, c: 54866},
- {f: 2, c: 54870}, {f: 3, c: 54873}, {f: 10, c: 54877}, 54888,
- {f: 6, c: 54890}, {f: 2, c: 54898}, {f: 14, c: 54901}, 54916,
- {f: 6, c: 54918}, {f: 2, c: 54926}, {f: 3, c: 54929}, {f: 8, c: 54933},
- 54942, 54944, {f: 6, c: 54946}, {f: 3, c: 54953}, {f: 3, c: 54957},
- {f: 8, c: 54961}, 54970, {f: 8, c: 54972}, {f: 2, c: 54982},
- {f: 3, c: 54985}, {f: 4, c: 54989}, {f: 2, c: 54994}, {f: 2, c: 54997},
- 55000, {f: 6, c: 55002}, {f: 3, c: 55009}, {f: 3, c: 55013},
- {f: 7, c: 55017}, {f: 4, c: 55025}, {f: 6, c: 55030}, {f: 2, c: 55038},
- {f: 3, c: 55041}, {f: 12, c: 55045}, {f: 6, c: 55058}, {f: 2, c: 55066},
- {f: 3, c: 55069}, {f: 7, c: 55073}, 55082, 55084, {f: 6, c: 55086},
- {f: 2, c: 55094}, {f: 3, c: 55097}, {f: 7, c: 55101}, {f: 2, c: 55109},
- 55112, {f: 6, c: 55114}, {f: 2, c: 55122}, 55125, {f: 6, c: 55130}, 55138,
- 55140, {f: 3, c: 55142}, {f: 2, c: 55146}, {f: 3, c: 55149},
- {f: 3, c: 55153}, {f: 7, c: 55157}, {f: 3, c: 55166}, {f: 6, c: 55170},
- {f: 2, c: 55178}, {f: 3, c: 55181}, {f: 7, c: 55185}, 55194, 55196,
- {f: 6, c: 55198}],
- 'Adobe-CNS1': [{f: 95, c: 32}, {s: 3}, 12288, 65292, {f: 2, c: 12289}, 65294,
- 8226, 65307, 65306, 65311, 65281, 65072, 8230, 8229, 65104, 65380, 65106,
- 183, {f: 4, c: 65108}, 65372, 8211, 65073, 8212, {s: 4}, {f: 2, c: 65288},
- {f: 2, c: 65077}, 65371, 65373, {f: 2, c: 65079}, {f: 2, c: 12308},
- {f: 2, c: 65081}, {f: 2, c: 12304}, {f: 2, c: 65083}, {f: 2, c: 12298},
- {f: 2, c: 65085}, {f: 2, c: 12296}, {f: 2, c: 65087}, {f: 2, c: 12300},
- {f: 2, c: 65089}, {f: 2, c: 12302}, {f: 2, c: 65091}, {f: 6, c: 65113},
- {f: 2, c: 8216}, {f: 2, c: 8220}, {f: 2, c: 12317}, 8245, 8242, 65283,
- 65286, 65290, 8251, 167, 12291, 9675, 9679, 9651, 9650, 9678, 9734, 9733,
- 9671, 9670, 9633, 9632, 9661, 9660, 12963, 8453, 8254, 0, 65343, 0,
- {f: 2, c: 65097}, {f: 2, c: 65101}, {f: 2, c: 65099}, {f: 3, c: 65119},
- 65291, 65293, 215, 247, 177, 8730, 65308, 65310, 65309, {f: 2, c: 8806},
- 8800, 8734, 8786, 8801, {f: 5, c: 65122}, 8764, {f: 2, c: 8745}, 8869,
- 8736, 8735, 8895, 13266, 13265, 8747, 8750, 8757, 8756, 9792, 9794, 9793,
- 9737, 8593, 8595, 8594, 8592, {f: 2, c: 8598}, 8601, 8600, 8741, 8739, 0,
- 0, 65295, 65340, 65284, 165, 12306, {f: 2, c: 162}, 65285, 65312, 8451,
- 8457, {f: 3, c: 65129}, 13269, {f: 3, c: 13212}, 13262, 13217,
- {f: 2, c: 13198}, 13252, 176, [20825, 58834], [20827, 58835],
- [20830, 58837], [20829, 58836], 20833, 20835, 21991, [29929, 58044],
- [31950, 58191], {f: 8, c: 9601}, 9615, 9614, 9613, 9612, 9611, 9610, 9609,
- 9532, 9524, 9516, 9508, 9500, 9620, 9472, 9474, 9621, 9484, 9488, 9492,
- 9496, {f: 2, c: 9581}, 9584, 9583, 9552, 9566, 9578, 9569, {f: 2, c: 9698},
- 9701, 9700, {f: 3, c: 9585}, {f: 10, c: 65296}, {f: 10, c: 8544},
- {f: 9, c: 12321}, 0, [21316, 57443], 0, {f: 26, c: 65313},
- {f: 26, c: 65345}, {f: 17, c: 913}, {f: 7, c: 931}, {f: 17, c: 945},
- {f: 7, c: 963}, {f: 37, c: 12549}, 729, 714, 711, 715, [9312, 63153],
- [9313, 63154], [9314, 63155], [9315, 63156], [9316, 63157], [9317, 63158],
- [9318, 63159], [9319, 63160], [9320, 63161], [9321, 63162], [9332, 63163],
- [9333, 63164], [9334, 63165], [9335, 63166], [9336, 63167], [9337, 63168],
- [9338, 63169], [9339, 63170], [9340, 63171], [9341, 63172], [8560, 63173],
- [8561, 63174], [8562, 63175], [8563, 63176], [8564, 63177], [8565, 63178],
- [8566, 63179], [8567, 63180], [8568, 63181], [8569, 63182], [12033, 20008],
- [12034, 20022, 63183], [12035, 20031, 63184], [12037, 20101, 63185],
- [12039, 20128, 63186], [12044, 20866, 63187], [12045, 20886, 63188],
- [12046, 20907, 63189], [12051, 21241, 63190], [12054, 21304, 63191],
- [12057, 21353, 63192], [12059, 21430, 63193],
- [12065, 12066, 22786, 22794, 63194], [12071, 23424, 63195],
- [12078, 24027, 63196], [12083, 24186, 63197], [12084, 24191, 63198],
- [12085, 24308], [12089, 24400, 63200], [12090, 24417, 63201],
- [12097, 25908, 63202], [12102, 26080], [12135, 30098, 63204],
- [12136, 30326], [12193, 36789, 63206], [12202, 38582], {f: 32, c: 9216},
- 9249, [12032, 19968], [12036, 20057], 19969, 19971, 20035, 20061, 20102,
- [12038, 20108], [12040, 20154], [12041, 20799], [12042, 20837],
- [12043, 20843], [12047, 20960], [12049, 20992], 20993, [12050, 21147],
- [12052, 21269], [12055, 21313], [12056, 21340], [12060, 21448], 19977,
- 19979, 19976, 19978, 20011, 20024, 20961, 20037, 20040, 20063, 20062,
- 20110, 20129, [20800, 64012], 20995, 21242, 21315, 21449, [12061, 21475],
- [12063, 22303], [12064, 22763], [12067, 22805], [12068, 22823],
- [12069, 22899], [12070, 23376], 23377, 23379, [12072, 23544],
- [12073, 23567], [12074, 23586], [12075, 23608], [12077, 23665], 24029,
- [12079, 24037], [12080, 24049], {f: 2, c: 24050}, [12081, 24062],
- [12082, 24178], [12086, 24318], [12087, 24331], [12088, 24339], 25165,
- 19985, 19984, 19981, 20013, 20016, 20025, 20043, 23609, 20104, 20113,
- 20117, 20114, 20116, 20130, 20161, 20160, 20163, {f: 2, c: 20166}, 20173,
- {f: 2, c: 20170}, 20164, 20803, 20801, 20839, {f: 2, c: 20845}, 20844,
- 20887, 20982, {f: 3, c: 20998}, 21243, {f: 2, c: 21246}, 21270, 21305,
- 21320, 21319, 21317, 21342, 21380, 21451, 21450, 21453, 22764, 22825,
- 22827, 22826, 22829, 23380, 23569, 23588, 23610, 23663, 24052, 24187,
- 24319, {f: 2, c: 24340}, [12092, 24515], [12093, 25096], [12094, 25142],
- [12095, 25163], 25166, [12096, 25903], [12098, 25991], [12099, 26007],
- [12100, 26020], [12101, 26041], [12103, 26085], [12104, 26352],
- [12105, 26376], [12106, 26408], [12107, 27424], [12108, 27490],
- [12109, 27513], [12111, 27595], [12112, 27604], [12113, 27611],
- [12114, 27663], [12116, 27700], [12117, 28779], [12118, 29226],
- [12119, 29238], [12120, 29243], [12122, 29255], [12123, 29273],
- [12124, 29275], [12125, 29356], 29579, 19993, 19990, 19989, 19988, 19992,
- 20027, 20045, 20047, 20046, 20197, 20184, {f: 4, c: 20180},
- {f: 2, c: 20195}, 20185, 20190, 20805, 20804, {f: 2, c: 20873}, 20908,
- {f: 2, c: 20985}, 20984, 21002, 21152, 21151, [21253, 57435], 21254, 21271,
- 21277, 20191, 21322, 21321, 21345, 21344, 21359, 21358, 21435, 21487,
- 21476, 21491, 21484, 21486, 21481, 21480, 21500, 21496, 21493, 21483,
- 21478, 21482, 21490, 21489, 21488, 21477, 21485, 21499, 22235, 22234,
- 22806, 22830, 22833, 22900, 22902, 23381, 23427, 23612, 24040, 24039,
- 24038, {f: 2, c: 24066}, 24179, 24188, 24321, 24344, 24343, 24517, 25098,
- {f: 2, c: 25171}, 25170, 25169, 26021, 26086, 26414, 26412,
- {f: 2, c: 26410}, 26413, 27491, 27597, 27665, 27664, 27704, 27713, 27712,
- 27710, 29359, [12126, 29572], [12127, 29577], [12128, 29916],
- [12129, 29926], [12130, 29976], [12131, 29983], [12132, 29992], 29993,
- [12133, 30000], {f: 3, c: 30001}, [12134, 30091], [12137, 30333],
- [12138, 30382], [12139, 30399], [12140, 30446], [12141, 30683],
- [12142, 30690], [12143, 30707], [12144, 31034], [12146, 31166],
- [12147, 31348], [12148, 31435], {f: 2, c: 19998}, {f: 2, c: 20050}, 20073,
- 20121, 20132, 20134, 20133, 20223, 20233, 20249, 20234, 20245, 20237,
- {f: 2, c: 20240}, 20239, 20210, 20214, 20219, 20208, 20211, 20221, 20225,
- 20235, 20809, 20807, 20806, 20808, 20840, 20849, 20877, 20912, 21015,
- {f: 2, c: 21009}, 21006, 21014, 21155, 21256, 21281, 21280,
- {f: 2, c: 21360}, 21513, 21519, 21516, 21514, 21520, 21505, 21515, 21508,
- 21521, 21517, 21512, 21507, 21518, 21510, 21522, 22240, 22238, 22237,
- 22323, 22320, 22312, 22317, 22316, 22319, 22313, {f: 2, c: 22809},
- {f: 2, c: 22839}, 22916, 22904, 22915, 22909, 22905, 22914, 22913,
- {f: 2, c: 23383}, {f: 2, c: 23431}, 23429, 23433, 23546, 23574, 23673,
- 24030, 24070, 24182, 24180, 24335, 24347, 24537, 24534, 25102,
- {f: 2, c: 25100}, 25104, 25187, 25179, 25176, 25910, 26089, 26088,
- {f: 2, c: 26092}, {f: 2, c: 26354}, 26377, 26429, 26420, 26417, 26421,
- 27425, 27492, 27515, 27670, 27741, 27735, 27737, {f: 2, c: 27743}, 27728,
- 27733, 27745, 27739, {f: 2, c: 27725}, 28784, 29279, 29277, 30334,
- [12149, 31481], [12150, 31859], [12151, 31992], [12152, 32566],
- [12154, 32650], [12155, 32701], [12156, 32769], 32771, [12157, 32780],
- [12158, 32786], [12159, 32819], [12160, 32895], [12161, 32905],
- {f: 2, c: 32907}, [12162, 33251], [12163, 33258], [12164, 33267],
- [12165, 33276], [12166, 33292], [12167, 33307], [12168, 33311],
- [12169, 33390], [12170, 33394], 33406, [12173, 34411], [12174, 34880],
- [12175, 34892], [12176, 34915], 35199, 38433, 20018, 20136, 20301, 20303,
- 20295, 20311, 20318, 20276, 20315, 20309, 20272, {f: 2, c: 20304}, 20285,
- 20282, 20280, 20291, 20308, 20284, 20294, 20323, 20316, 20320, 20271,
- 20302, 20278, 20313, 20317, 20296, 20314, 20812, 20811, 20813, 20853,
- {f: 2, c: 20918}, 21029, 21028, {f: 2, c: 21033}, 21032, 21163,
- {f: 2, c: 21161}, 21164, 21283, 21363, 21365, 21533, 21549, 21534, 21566,
- 21542, 21582, 21543, 21574, 21571, 21555, 21576, 21570, 21531, 21545,
- 21578, 21561, 21563, 21560, 21550, {f: 2, c: 21557}, 21536, 21564, 21568,
- 21553, 21547, 21535, 21548, 22250, 22256, 22244, 22251, 22346, 22353,
- 22336, 22349, 22343, 22350, 22334, 22352, 22351, 22331, 22767, 22846,
- 22941, 22930, 22952, 22942, 22947, 22937, 22934, 22925, 22948, 22931,
- 22922, 22949, 23389, 23388, {f: 2, c: 23386}, 23436, 23435, 23439, 23596,
- {f: 2, c: 23616}, 23615, 23614, {f: 2, c: 23696}, 23700, 23692, 24043,
- 24076, 24207, 24199, 24202, 24311, 24324, 24351, 24420, 24418, 24439,
- 24441, 24536, 24524, 24535, 24525, 24561, 24555, 24568, 24554, 25106,
- 25105, 25220, 25239, 25238, 25216, 25206, 25225, 25197, 25226, 25212,
- 25214, 25209, 25203, 25234, 25199, 25240, 25198, 25237, 25235, 25233,
- 25222, 25913, 25915, 25912, 26097, 26356, 26463, {f: 4, c: 26446}, 26460,
- 26454, [26462, 57801], 26441, 26438, 26464, 26451, 26455, 27493, 27599,
- 27714, 27742, 27801, 27777, {f: 2, c: 27784}, 27781, 27803, 27754, 27770,
- 27792, 27760, 27788, 27752, 27798, 27794, 27773, 27779, 27762, 27774,
- 27764, 27782, 27766, 27789, 27796, 27800, 27778, 28790, {f: 2, c: 28796},
- 28792, 29282, 29281, 29280, 29380, 29378, 29590, 29996, 29995,
- {f: 2, c: 30007}, 30338, 30447, 30691, 31169, 31168, 31167, 31350, 31995,
- 32597, 32918, 32915, 32925, 32920, 32923, 32922, 32946, 33391, 33426,
- 33419, 33421, [12178, 35211], [12179, 35282], [12180, 35328],
- [12181, 35895], [12182, 35910], [12183, 35925], [12185, 35997],
- [12186, 36196], [12187, 36208], [12188, 36275], [12189, 36523],
- [12190, 36554], [12191, 36763], [12192, 36784], 36802, 36806, 36805, 36804,
- 24033, [12194, 37009], 37026, 37034, 37030, 37027, [12195, 37193],
- [12196, 37318], [12197, 37324], 38450, 38446, 38449, 38442, 38444, 20006,
- 20054, 20083, 20107, 20123, 20126, {f: 2, c: 20139}, 20335, 20381, 20365,
- 20339, 20351, 20332, 20379, 20363, 20358, 20355, 20336, 20341, 20360,
- 20329, 20347, 20374, 20350, 20367, 20369, 20346, 20820, 20818, 20821,
- 20841, 20855, 20854, 20856, 20925, 20989, 21051, 21048, 21047, 21050,
- 21040, 21038, 21046, 21057, 21182, 21179, 21330, 21332, 21331, 21329,
- 21350, {f: 3, c: 21367}, 21462, 21460, 21463, 21619, 21621, 21654, 21624,
- 21653, 21632, 21627, 21623, 21636, 21650, 21638, 21628, 21648, 21617,
- 21622, 21644, 21658, 21602, 21608, 21643, 21629, 21646, 22266, 22403,
- 22391, 22378, 22377, 22369, 22374, 22372, 22396, 22812, 22857,
- {f: 2, c: 22855}, 22852, 22868, 22974, 22971, 22996, 22969, 22958, 22993,
- 22982, 22992, 22989, 22987, 22995, 22986, 22959, 22963, 22994, 22981,
- 23391, 23396, 23395, 23447, 23450, 23448, 23452, 23449, 23451, 23578,
- 23624, {f: 2, c: 23621}, 23735, 23713, 23736, 23721, 23723, 23729, 23731,
- 24088, 24090, 24086, 24085, 24091, 24081, 24184, 24218, 24215, 24220,
- {f: 2, c: 24213}, 24310, {f: 2, c: 24358}, 24361, {f: 2, c: 24448}, 24447,
- 24444, 24541, 24544, 24573, 24565, 24575, 24591, 24596, 24623, 24629,
- 24598, 24618, 24597, 24609, 24615, 24617, 24619, 24603, 25110, 25109,
- 25151, 25150, 25152, 25215, 25289, 25292, 25284, 25279, 25282, 25273,
- 25298, 25307, 25259, {f: 2, c: 25299}, 25291, 25288, 25256, 25277, 25276,
- [25296, 60582], 25305, 25287, 25293, 25269, 25306, 25265, 25304,
- {f: 2, c: 25302}, 25286, 25260, [25294, 61010], 25918, 26023, 26044, 26106,
- 26132, 26131, 26124, 26118, 26114, 26126, 26112, 26127, 26133, 26122,
- 26119, 26381, 26379, 26477, 26507, 26517, 26481, 26524, 26483, 26487,
- 26503, 26525, 26519, {f: 2, c: 26479}, 26495, 26505, 26494, 26512, 26485,
- 26522, 26515, 26492, 26474, 26482, 27427, {f: 2, c: 27494}, 27519, 27667,
- 27675, 27875, 27880, 27891, 27825, 27852, 27877, 27827, {f: 2, c: 27837},
- 27836, 27874, 27819, 27861, 27859, 27832, 27844, 27833, 27841, 27822,
- 27863, 27845, 27889, 27839, 27835, 27873, 27867, 27850, 27820, 27887,
- 27868, 27862, 27872, 28821, 28814, 28818, 28810, 28825, {f: 2, c: 29228},
- 29240, 29256, 29287, 29289, 29376, 29390, 29401, 29399, 29392, 29609,
- 29608, 29599, 29611, 29605, 30013, 30109, {f: 2, c: 30105}, 30340, 30402,
- 30450, 30452, 30693, 30717, 31038, {f: 2, c: 31040}, 31177, 31176, 31354,
- 31353, 31482, 31998, 32596, 32652, 32651, [32773, 58236], 32954, 32933,
- 32930, 32945, 32929, 32939, 32937, 32948, 32938, 32943, 33253, 33278,
- 33293, 33459, 33437, 33433, 33453, 33469, 33439, 33465, 33457, 33452,
- 33445, 33455, 33464, 33443, 33456, 33470, 33463, 34382, 34417, 21021,
- 34920, 36555, 36814, 36820, 36817, 37045, 37048, 37041, 37046, 37319,
- [12198, 37329], [12199, 38263], [12200, 38272], [12201, 38428], 38464,
- 38463, 38459, 38468, 38466, [12203, 38585], [12204, 38632], 38738,
- [12206, 38750], 20127, {f: 2, c: 20141}, 20449, 20405, 20399, 20415, 20448,
- 20433, 20431, 20445, 20419, 20406, 20440, 20447, 20426, 20439, 20398,
- 20432, 20420, 20418, 20442, 20430, 20446, 20407, 20823, 20882, 20881,
- 20896, 21070, 21059, 21066, 21069, 21068, 21067, 21063, 21191, 21193,
- 21187, 21185, 21261, 21335, 21371, 21402, 21467, 21676, 21696, 21672,
- 21710, 21705, 21688, 21670, 21683, 21703, 21698, 21693, 21674, 21697,
- 21700, 21704, 21679, 21675, 21681, 21691, 21673, 21671, 21695, 22271,
- 22402, 22411, 22432, 22435, 22434, 22478, 22446, 22419, 22869, 22865,
- 22863, 22862, 22864, 23004, 23000, 23039, 23011, 23016, 23043, 23013,
- 23018, 23002, 23014, 23041, 23035, 23401, 23459, 23462, 23460, 23458,
- 23461, 23553, {f: 2, c: 23630}, 23629, 23627, 23769, 23762, 24055, 24093,
- 24101, 24095, 24189, 24224, 24230, 24314, 24328, 24365, 24421, 24456,
- 24453, {f: 2, c: 24458}, 24455, 24460, 24457, 24594, 24605, 24608, 24613,
- 24590, 24616, 24653, 24688, 24680, [24674, 60712], 24646, 24643, 24684,
- 24683, 24682, 24676, 25153, 25308, 25366, 25353, 25340, 25325, 25345,
- 25326, 25341, 25351, 25329, 25335, 25327, 25324, 25342, 25332, 25361,
- 25346, 25919, 25925, 26027, 26045, 26082, 26149, 26157, 26144, 26151,
- 26159, 26143, 26152, 26161, 26148, 26359, 26623, 26579, 26609, 26580,
- 26576, 26604, 26550, 26543, 26613, 26601, 26607, 26564, 26577, 26548,
- 26586, 26597, 26552, 26575, 26590, 26611, 26544, 26585, 26594, 26589,
- 26578, 27498, 27523, 27526, 27573, 27602, 27607, 27679, 27849, 27915,
- 27954, 27946, 27969, 27941, 27916, 27953, 27934, 27927, 27963,
- {f: 2, c: 27965}, 27958, 27931, 27893, 27961, 27943, 27960, 27945, 27950,
- 27957, 27918, 27947, 28843, 28858, 28851, 28844, 28847, 28845, 28856,
- 28846, 28836, 29232, 29298, 29295, 29300, 29417, {f: 2, c: 29408}, 29623,
- 29642, 29627, 29618, 29645, 29632, 29619, 29978, 29997, 30031, 30028,
- 30030, 30027, 30123, {f: 2, c: 30116}, {f: 2, c: 30114}, 30328,
- {f: 3, c: 30342}, 30408, 30406, 30403, 30405, 30465, 30457, 30456, 30473,
- 30475, 30462, 30460, 30471, 30684, 30722, 30740, {f: 2, c: 30732}, 31046,
- 31049, 31048, 31047, {f: 2, c: 31161}, {f: 2, c: 31185}, 31179, 31359,
- 31361, 31487, 31485, 31869, 32002, 32005, 32000, 32009, 32007, 32004,
- 32006, 32568, 32654, 32703, 32784, 32781, 32785, 32822, 32982, 32997,
- 32986, {f: 2, c: 32963}, 32972, 32993, 32987, 32974, 32990, 32996, 32989,
- 33268, 33314, 33511, 33539, 33541, 33507, 33499, 33510, 33540, 33509,
- 33538, 33545, 33490, 33495, 33521, 33537, 33500, 33492, 33489, 33502,
- 33491, 33503, 33519, 33542, 34384, 34425, 34427, 34426, 34893, 34923,
- 35201, 35284, 35336, {f: 2, c: 35330}, 35998, 36000, 36212, 36211, 36276,
- 36557, 36556, 36848, 36838, 36834, 36842, 36837, 36845, 36843, 36836,
- 36840, 37066, 37070, 37057, 37059, 37195, 37194, 37325, 38274, 38480,
- {f: 3, c: 38475}, [12207, 38754], [12208, 38761], [12209, 38859],
- [12210, 38893], [12211, 38899], [12212, 38913], [12213, 39080],
- [12214, 39131], [12215, 39135], [12216, 39318], [12217, 39321], 20056,
- 20147, {f: 2, c: 20492}, 20515, 20463, 20518, 20517, 20472, [20521, 57375],
- 20502, 20486, 20540, 20511, 20506, 20498, 20497, 20474, 20480, 20500,
- 20520, 20465, 20513, 20491, 20505, 20504, 20467, 20462, 20525, 20522,
- 20478, 20523, 20489, 20860, {f: 2, c: 20900}, 20898, 20941, 20940, 20934,
- 20939, 21078, 21084, 21076, 21083, 21085, 21290, [21375, 57459], 21407,
- 21405, 21471, 21736, 21776, 21761, 21815, 21756, 21733, 21746, 21766,
- 21754, 21780, 21737, 21741, 21729, 21769, 21742, 21738, 21734, 21799,
- 21767, 21757, 21775, {f: 2, c: 22275}, 22466, 22484, 22475, 22467, 22537,
- 22799, {f: 2, c: 22871}, 22874, 23057, 23064, 23068, 23071, 23067, 23059,
- 23020, 23072, 23075, 23081, 23077, 23052, 23049, 23403, 23640, 23472,
- 23475, 23478, 23476, 23470, 23477, 23481, 23480, 23556, 23633, 23637,
- 23632, 23789, 23805, 23803, 23786, 23784, 23792, 23798, 23809, 23796,
- 24046, 24109, 24107, 24235, 24237, 24231, 24369, 24466, 24465, 24464,
- 24665, 24675, 24677, 24656, 24661, 24685, 24681, 24687, 24708, 24735,
- 24730, 24717, 24724, 24716, 24709, 24726, 25159, 25331, 25352, 25343,
- 25422, 25406, 25391, 25429, 25410, 25414, 25423, 25417, 25402, 25424,
- 25405, {f: 2, c: 25386}, 25384, 25421, 25420, {f: 2, c: 25928}, 26009,
- 26049, 26053, 26178, 26185, 26191, 26179, 26194, 26188, 26181, 26177,
- 26360, {f: 2, c: 26388}, 26391, 26657, 26680, 26696, 26694, 26707, 26681,
- 26690, 26708, 26665, 26803, 26647, 26700, 26705, 26685, 26612, 26704,
- 26688, 26684, 26691, 26666, 26693, 26643, 26648, 26689, 27530, 27529,
- 27575, 27683, {f: 2, c: 27687}, 27686, 27684, 27888, 28010, 28053, 28040,
- 28039, 28006, 28024, 28023, 27993, 28051, 28012, 28041, 28014, 27994,
- 28020, 28009, 28044, 28042, 28025, 28037, 28005, 28052, 28874, 28888,
- 28900, 28889, 28872, 28879, 29241, 29305, 29436, 29433, 29437, 29432,
- 29431, 29574, 29677, 29705, 29678, 29664, 29674, 29662, 30036, 30045,
- 30044, 30042, 30041, 30142, 30149, 30151, {f: 2, c: 30130}, 30141, 30140,
- 30137, 30146, 30136, 30347, 30384, 30410, {f: 2, c: 30413}, 30505,
- {f: 2, c: 30495}, 30504, 30697, 30768, 30759, 30776, 30749, 30772, 30775,
- 30757, 30765, 30752, 30751, 30770, 31061, 31056, 31072, 31071, 31062,
- 31070, 31069, 31063, 31066, 31204, [31203, 60418], 31207, 31199, 31206,
- 31209, 31192, 31364, 31368, 31449, 31494, 31505, 31881, 32033, 32023,
- 32011, 32010, 32032, 32034, 32020, 32016, 32021, 32026, 32028, 32013,
- 32025, 32027, 32570, 32607, 32660, 32709, 32705, 32774, 32772, 32792,
- 32789, 32793, 32791, 32829, 32831, 33009, 33026, 33008, 33029, 33005,
- 33012, 33030, 33016, 33011, 33032, 33021, 33034, 33020, 33007, 33261,
- 33260, 33280, 33296, {f: 2, c: 33322}, 33320, 33324, 33467, 33579, 33618,
- 33620, 33610, 33592, 33616, 33609, 33589, 33588, 33615, 33586, 33593,
- 33590, 33559, 33600, 33585, 33576, 33603, 34388, 34442, 34474, 34451,
- 34468, 34473, 34444, 34467, 34460, 34928, 34935, {f: 2, c: 34945}, 34941,
- 34937, 35352, 35344, 35342, 35340, 35349, 35338, 35351, 35347, 35350,
- 35343, 35345, 35912, 35962, 35961, {f: 2, c: 36001}, [36215, 58442], 36524,
- 36562, 36564, 36559, 36785, 36865, 36870, 36855, 36864, 36858, 36852,
- 36867, 36861, 36869, 36856, 37013, 37089, 37085, 37090, 37202, 37197,
- 37196, 37336, 37341, 37335, 37340, 37337, 38275, {f: 2, c: 38498}, 38497,
- 38491, 38493, 38500, 38488, 38494, 38587, 39138, [12218, 39340],
- [12219, 39592], [12220, 39640], [12222, 39717], [12224, 39730],
- [12225, 39740], 20094, 20602, [20605, 57382], 20572, 20551, 20547, 20556,
- 20570, 20553, 20581, 20598, 20558, 20565, 20597, 20596, 20599, 20559,
- 20495, 20591, 20589, 20828, 20885, 20976, 21098, 21103, 21202, 21209,
- 21208, 21205, 21264, 21263, 21273, {f: 2, c: 21311}, 21310, 21443, 26364,
- 21830, 21866, 21862, 21828, 21854, 21857, 21827, 21834, 21809, 21846,
- 21839, 21845, 21807, 21860, 21816, 21806, 21852, 21804, 21859, 21811,
- 21825, 21847, 22280, 22283, 22281, 22495, 22533, 22538, 22534, 22496,
- 22500, 22522, 22530, 22581, 22519, 22521, 22816, 22882, 23094, 23105,
- 23113, 23142, 23146, 23104, 23100, 23138, 23130, 23110, 23114, 23408,
- 23495, 23493, 23492, 23490, 23487, 23494, 23561, 23560, 23559, 23648,
- {f: 2, c: 23644}, 23815, 23814, 23822, 23835, 23830, 23842, 23825, 23849,
- 23828, 23833, 23844, 23847, 23831, 24034, 24120, 24118, 24115, 24119,
- {f: 2, c: 24247}, 24246, 24245, 24254, 24373, 24375, 24407, 24428, 24425,
- 24427, 24471, 24473, 24478, 24472, 24481, 24480, 24476, 24703, 24739,
- 24713, 24736, 24744, 24779, 24756, 24806, 24765, 24773, 24763, 24757,
- 24796, 24764, 24792, 24789, 24774, 24799, 24760, 24794, 24775,
- {f: 2, c: 25114}, 25160, 25504, 25511, 25458, 25494, 25506, 25509, 25463,
- 25447, 25496, 25514, 25457, 25513, 25481, 25475, 25499, 25451, 25512,
- 25476, 25480, 25497, 25505, 25516, 25490, 25487, 25472, 25467, 25449,
- 25448, 25466, 25949, 25942, 25937, 25945, 25943, 21855, 25935, 25944,
- 25941, 25940, 26012, 26011, 26028, 26063, {f: 2, c: 26059}, 26062, 26205,
- 26202, 26212, 26216, 26214, 26206, 26361, 21207, 26395, 26753, 26799,
- 26786, 26771, 26805, 26751, 26742, 26801, 26791, 26775, 26800, 26755,
- 26820, 26797, 26758, 26757, 26772, 26781, 26792, 26783, 26785, 26754,
- 27442, 27578, {f: 2, c: 27627}, 27691, 28046, 28092, 28147, 28121, 28082,
- 28129, 28108, 28132, 28155, 28154, 28165, 28103, 28107, 28079, 28113,
- 28078, 28126, 28153, 28088, 28151, 28149, 28101, 28114, 28186, 28085,
- 28122, 28139, 28120, 28138, 28145, 28142, 28136, 28102, 28100, 28074,
- 28140, 28095, 28134, 28921, {f: 2, c: 28937}, 28925, 28911, 29245, 29309,
- 29313, 29468, 29467, 29462, 29459, 29465, 29575, 29701, 29706, 29699,
- 29702, 29694, 29709, 29920, {f: 2, c: 29942}, 29980, 29986,
- {f: 2, c: 30053}, 30050, 30064, 30095, {f: 2, c: 30164}, 30133, 30154,
- 30157, 30350, 30420, 30418, 30427, 30519, 30526, 30524, 30518, 30520,
- 30522, 30827, 30787, 30798, 31077, 31080, 31085, 31227, 31378, 31381,
- 31520, 31528, 31515, 31532, 31526, 31513, 31518, 31534, 31890, 31895,
- 31893, 32070, 32067, 32113, 32046, 32057, 32060, 32064, 32048, 32051,
- 32068, 32047, 32066, 32050, 32049, 32573, 32670, 32666, 32716, 32718,
- 32722, 32796, 32842, 32838, 33071, 33046, 33059, 33067, 33065, 33072,
- 33060, 33282, 33333, 33335, 33334, 33337, 33678, 33694, 33688, 33656,
- 33698, 33686, 33725, 33707, 33682, 33674, 33683, 33673, 33696, 33655,
- {f: 2, c: 33659}, 33670, 33703, 34389, 24426, 34503, 34496, 34486, 34500,
- 34485, 34502, 34507, 34481, 34479, 34505, 34899, 34974, 34952, 34987,
- 34962, 34966, 34957, 34955, 35219, 35215, 35370, 35357, 35363, 35365,
- 35377, 35373, 35359, 35355, 35362, 35913, 35930, 36009, 36012, 36011,
- 36008, 36010, 36007, 36199, 36198, 36286, 36282, 36571, 36575, 36889,
- 36877, 36890, 36887, 36899, 36895, 36893, 36880, 36885, 36894, 36896,
- 36879, 36898, 36886, 36891, 36884, 37096, 37101, [37117, 58488], 37207,
- 37326, 37365, 37350, 37347, 37351, 37357, 37353, 38281, 38506, 38517,
- 38515, 38520, 38512, 38516, {f: 2, c: 38518}, 38508, 38592, 38634, 38633,
- 31456, 31455, {f: 2, c: 38914}, [12226, 39770], [12227, 40165],
- [12228, 40565], [12229, 40575], [12230, 40613], [12231, 40635], 20642,
- 20621, 20613, 20633, 20625, 20608, 20630, 20632, 20634, 26368, 20977,
- 21106, {f: 2, c: 21108}, 21097, 21214, 21213, 21211, 21338, 21413, 21883,
- 21888, 21927, 21884, 21898, 21917, 21912, 21890, 21916, 21930, 21908,
- 21895, 21899, 21891, 21939, 21934, 21919, 21822, 21938, 21914, 21947,
- 21932, 21937, 21886, 21897, 21931, 21913, 22285, 22575, 22570, 22580,
- 22564, {f: 2, c: 22576}, 22561, 22557, 22560, {f: 2, c: 22777}, 22880,
- [23159, 57587], 23194, 23167, 23186, 23195, 23207, 23411, 23409, 23506,
- 23500, 23507, 23504, {f: 2, c: 23562}, 23601, 23884, 23888, 23860, 23879,
- 24061, 24133, 24125, 24128, 24131, 24190, 24266, {f: 2, c: 24257}, 24260,
- 24380, 24429, {f: 2, c: 24489}, 24488, 24785, 24801, 24754, 24758, 24800,
- 24860, 24867, 24826, 24853, 24816, 24827, 24820, 24936, 24817, 24846,
- 24822, 24841, 24832, 24850, 25119, 25161, 25507, 25484, 25551, 25536,
- 25577, 25545, 25542, 25549, 25554, 25571, 25552, 25569, 25558,
- {f: 2, c: 25581}, 25462, 25588, 25578, 25563, 25682, 25562, 25593, 25950,
- 25958, {f: 2, c: 25954}, 26001, 26000, 26031, 26222, 26224, [26228, 57786],
- 26230, 26223, 26257, 26234, 26238, 26231, {f: 2, c: 26366}, 26399, 26397,
- 26874, 26837, 26848, 26840, 26839, 26885, 26847, 26869, 26862, 26855,
- 26873, 26834, 26866, 26851, 26827, 26829, 26893, 26898, 26894, 26825,
- 26842, 26990, 26875, 27454, 27450, 27453, 27544, 27542, 27580, 27631,
- {f: 2, c: 27694}, 27692, [28207, 57904], 28216, 28244, 28193, 28210, 28263,
- 28234, 28192, 28197, 28195, 28187, 28251, 28248, 28196, 28246, 28270,
- 28205, 28198, 28271, 28212, 28237, 28218, 28204, 28227, [28189, 57901],
- 28222, 28363, 28297, 28185, 28238, 28259, 28228, 28274, 28265, 28255,
- {f: 2, c: 28953}, 28966, 28976, 28961, 28982, [29038, 57958], 28956, 29260,
- 29316, 29312, 29494, 29477, 29492, 29481, 29754, 29738, 29747, 29730,
- 29733, {f: 2, c: 29749}, 29748, 29743, 29723, 29734, 29736,
- {f: 2, c: 29989}, 30059, 30058, 30178, 30171, 30179, 30169, 30168, 30174,
- 30176, {f: 2, c: 30331}, 30358, 30355, 30388, 30428, 30543, 30701, 30813,
- 30828, 30831, 31245, 31240, 31243, 31237, 31232, 31384, 31383, 31382,
- 31461, 31459, 31561, 31574, 31558, 31568, 31570, 31572, 31565, 31563,
- 31567, [31569, 60510], 31903, 31909, 32094, 32080, 32104, 32085, 32043,
- 32110, 32114, 32097, 32102, 32098, 32112, 32115, 21892, {f: 2, c: 32724},
- 32779, 32850, 32901, 33109, 33108, 33099, 33105, 33102, 33081, 33094,
- 33086, 33100, 33107, 33140, 33298, 33308, 33769, 33795, 33784, 33805,
- 33760, 33733, 33803, [33729, 58309], 33775, 33777, 33780, 33879, 33802,
- 33776, 33804, 33740, 33789, 33778, 33738, 33848, 33806, 33796, 33756,
- 33799, 33748, 33759, 34395, 34527, 34521, 34541, 34516, 34523, 34532,
- 34512, 34526, 34903, {f: 2, c: 35009}, 34993, 35203, 35222, 35387, 35424,
- 35413, 35422, 35388, 35393, 35412, 35419, 35408, 35398, 35380, 35386,
- 35382, 35414, 35937, 35970, 36015, 36028, 36019, 36029, 36033, 36027,
- 36032, 36020, 36023, 36022, 36031, 36024, 36234, 36229, 36225, 36302,
- 36317, 36299, 36314, 36305, 36300, 36315, 36294, 36603, 36600, 36604,
- 36764, 36910, 36917, 36913, 36920, 36914, 36918, 37122, 37109, 37129,
- 37118, 37219, 37221, 37327, {f: 2, c: 37396}, 37411, 37385, 37406, 37389,
- 37392, 37383, 37393, 38292, 38287, 38283, 38289, 38291, 38290, 38286,
- 38538, 38542, 38539, 38525, {f: 2, c: 38533}, 38541, 38514, 38532, 38593,
- 38597, 38596, {f: 2, c: 38598}, 38639, 38642, 38860, {f: 2, c: 38917},
- 38920, 39143, 39146, 39151, 39145, 39154, 39149, 39342, 39341,
- [12232, 40643], [12233, 40653], [12234, 40657], 20098, 20653, 20661,
- {f: 2, c: 20658}, 20677, 20670, 20652, 20663, 20667, 20655, 20679, 21119,
- 21111, 21117, 21215, 21222, 21220, {f: 2, c: 21218}, 21295, 21983, 21992,
- 21971, 21990, 21966, 21980, 21959, 21969, {f: 2, c: 21987}, 21999, 21978,
- 21985, {f: 2, c: 21957}, 21989, 21961, {f: 2, c: 22290}, 22622, 22609,
- 22616, 22615, 22618, 22612, 22635, 22604, 22637, 22602, 22626, 22610,
- 22603, 22887, 23233, 23241, 23244, 23230, 23229, 23228, 23219, 23234,
- 23218, 23913, 23919, 24140, 24185, 24265, 24264, 24338, 24409, 24492,
- 24494, 24858, 24847, 24904, 24863, 24819, 24859, 24825, 24833, 24840,
- 24910, 24908, 24900, 24909, 24894, 24884, 24871, 24845, 24838, 24887,
- {f: 2, c: 25121}, 25619, 25662, 25630, 25642, 25645, 25661, 25644, 25615,
- 25628, 25620, 25613, 25654, {f: 2, c: 25622}, 25606, 25964, 26015, 26032,
- 26263, 26249, {f: 2, c: 26247}, 26262, 26244, 26264, 26253, 26371, 27028,
- 26989, 26970, 26999, 26976, 26964, 26997, 26928, 27010, 26954, 26984,
- 26987, 26974, 26963, 27001, 27014, 26973, 26979, 26971, 27463, 27506,
- 27584, 27583, 27603, 27645, 28322, 28335, 28371, 28342, 28354, 28304,
- 28317, 28359, 28357, 28325, 28312, 28348, 28346, 28331, 28369, 28310,
- 28316, 28356, 28372, 28330, 28327, 28340, 29006, 29017, 29033, 29028,
- 29001, 29031, 29020, 29036, 29030, 29004, 29029, 29022, 28998, 29032,
- 29014, 29242, 29266, 29495, 29509, 29503, 29502, 29807, 29786, 29781,
- 29791, 29790, 29761, 29759, 29785, 29787, [29788, 58019], 30070, 30072,
- 30208, 30192, 30209, 30194, 30193, 30202, 30207, 30196, 30195,
- {f: 2, c: 30430}, 30555, 30571, 30566, 30558, 30563, 30585, 30570, 30572,
- 30556, 30565, 30568, 30562, 30702, 30862, 30896, {f: 2, c: 30871}, 30860,
- 30857, 30844, 30865, 30867, 30847, 31098, 31103, 31105, 33836, 31165,
- 31260, 31258, 31264, 31252, 31263, 31262, {f: 2, c: 31391}, 31607, 31680,
- 31584, 31598, 31591, 31921, 31923, 31925, 32147, 32121, 32145, 32129,
- 32143, 32091, 32622, {f: 2, c: 32617}, 32626, 32681, 32680, 32676, 32854,
- 32856, 32902, 32900, 33137, 33136, 33144, 33125, 33134, 33139, 33131,
- {f: 2, c: 33145}, 33126, 33285, 33351, 33922, 33911, 33853, 33841, 33909,
- 33894, 33899, 33865, 33900, 33883, 33852, 33845, 33889, 33891, 33897,
- 33901, 33862, 34398, 34396, 34399, 34553, 34579, 34568, 34567, 34560,
- 34558, 34555, {f: 2, c: 34562}, 34566, 34570, 34905, 35039, 35028, 35033,
- 35036, 35032, 35037, 35041, 35018, 35029, 35026, 35228, 35299, 35435,
- {f: 2, c: 35442}, 35430, 35433, 35440, 35463, 35452, 35427, 35488, 35441,
- 35461, 35437, 35426, 35438, 35436, 35449, 35451, 35390, 35432, 35938,
- 35978, 35977, 36042, {f: 2, c: 36039}, 36036, 36018, 36035, 36034, 36037,
- 36321, 36319, 36328, 36335, 36339, 36346, 36330, 36324, 36326, 36530,
- 36611, 36617, 36606, 36618, 36767, 36786, 36939, 36938, 36947, 36930,
- 36948, 36924, 36949, 36944, 36935, 36943, 36942, 36941, 36945, 36926,
- 36929, 37138, 37143, 37228, 37226, 37225, 37321, 37431, 37463, 37432,
- 37437, 37440, 37438, 37467, 37451, 37476, 37457, 37428, 37449, 37453,
- 37445, 37433, 37439, 37466, 38296, 38552, {f: 2, c: 38548}, 38605, 38603,
- {f: 2, c: 38601}, 38647, 38651, 38649, 38646, 38742, 38772, 38774,
- {f: 2, c: 38928}, 38931, 38922, 38930, 38924, 39164, 39156,
- {f: 2, c: 39165}, 39347, 39345, 39348, 39649, 40169, 40578, [12237, 40718],
- [12238, 40723], [12239, 40736], 20711, 20718, 20709, 20694, [20717, 60903],
- 20698, 20693, 20687, 20689, 20721, 20686, 20713, 20834, 20979, 21123,
- 21122, 21297, 21421, 22014, 22016, 22043, 22039, 22013, 22036, 22022,
- 22025, {f: 2, c: 22029}, 22007, 22038, 22047, 22024, 22032, 22006, 22296,
- 22294, 22645, 22654, 22659, 22675, 22666, 22649, 22661, 22653, 22781,
- 22821, 22818, 22820, 22890, 22889, 23265, 23270, 23273, 23255, 23254,
- 23256, 23267, 23413, 23518, 23527, 23521, {f: 2, c: 23525}, 23528, 23522,
- 23524, 23519, 23565, 23650, 23940, 23943, 24155, 24163, 24149, 24151,
- 24148, 24275, 24278, 24330, 24390, 24432, 24505, 24903, 24895, 24907,
- 24951, {f: 2, c: 24930}, 24927, 24922, 24920, 24949, 25130, 25735, 25688,
- 25684, 25764, 25720, 25695, 25722, 25681, 25703, 25652, 25709, 25723,
- 25970, 26017, 26071, 26070, 26274, 26280, 26269, 27036, 27048, 27029,
- 27073, 27054, 27091, 27083, 27035, 27063, 27067, 27051, 27060, 27088,
- 27085, 27053, 27084, 27046, 27075, 27043, 27465, 27468, 27699, 28467,
- 28436, 28414, 28435, 28404, 28457, 28478, 28448, 28460, 28431, 28418,
- 28450, 28415, 28399, 28422, 28465, 28472, 28466, 28451, 28437, 28459,
- 28463, 28552, 28458, 28396, 28417, 28402, 28364, 28407, 29076, 29081,
- 29053, 29066, 29060, 29074, 29246, 29330, 29334, 29508, 29520, 29796,
- 29795, 29802, 29808, 29805, 29956, 30097, 30247, 30221, 30219, 30217,
- 30227, 30433, 30435, 30596, 30589, 30591, 30561, 30913, 30879, 30887,
- 30899, 30889, 30883, {f: 2, c: 31118}, 31117, 31278, 31281, 31402, 31401,
- 31469, 31471, 31649, 31637, 31627, 31605, 31639, 31645, 31636, 31631,
- [31672, 58170], 31623, 31620, 31929, {f: 2, c: 31933}, 32187, 32176, 32156,
- {f: 2, c: 32189}, 32160, 32202, 32180, 32178, 32177, 32186, 32162, 32191,
- 32181, 32184, 32173, [32210, 58202], 32199, 32172, 32624, {f: 2, c: 32736},
- 32735, 32862, 32858, 32903, 33104, 33152, 33167, 33160, 33162, 33151,
- 33154, 33255, 33274, 33287, 33300, 33310, 33355, 33993, 33983, 33990,
- 33988, 33945, 33950, 33970, 33948, 33995, 33976, 33984, 34003, 33936,
- 33980, 34001, 33994, 34623, 34588, 34619, 34594, 34597, 34612, 34584,
- 34645, 34615, 34601, 35059, 35074, 35060, 35065, 35064, 35069, 35048,
- 35098, 35055, 35494, 35468, 35486, 35491, 35469, 35489, 35475, 35492,
- 35498, 35493, 35496, 35480, 35473, 35482, 35495, 35946, 35981, 35980,
- 36051, {f: 2, c: 36049}, 36203, 36249, 36245, 36348, 36628, 36626, 36629,
- 36627, 36771, 36960, 36952, 36956, 36963, 36953, 36958, 36962, 36957,
- 36955, 37145, 37144, 37150, 37237, 37240, 37239, 37236, 37496, 37548,
- 37504, 37509, 37528, 37526, 37499, 37523, 37532, 37544, 37500, 37521,
- 38305, {f: 2, c: 38312}, 38307, 38309, 38308, 38553, 38556, 38555, 38604,
- 38610, 38656, 38780, 38789, 38902, {f: 2, c: 38935}, 39087, 39089, 39171,
- 39173, 39180, 39177, 39361, {f: 2, c: 39599}, 39654, {f: 2, c: 39745},
- 40180, 40182, 40179, 40636, [12240, 40763], [12241, 40778], 20740, 20736,
- 20731, 20725, 20729, 20738, {f: 2, c: 20744}, 20741, 20956,
- {f: 3, c: 21127}, 21133, 21130, 21232, 21426, 22062, 22075, 22073, 22066,
- 22079, 22068, 22057, 22099, 22094, 22103, 22132, 22070, {f: 2, c: 22063},
- 22656, 22687, 22686, 22707, 22684, 22702, 22697, 22694, 22893, 23305,
- 23291, 23307, 23285, 23308, 23304, 23534, 23532, 23529, 23531,
- {f: 2, c: 23652}, 23965, 23956, 24162, 24159, 24161, 24290, 24282, 24287,
- 24285, 24291, 24288, 24392, 24433, 24503, 24501, 24950, 24935, 24942,
- 24925, 24917, 24962, 24956, 24944, 24939, 24958, 24999, 24976, 25003,
- 24974, 25004, 24986, 24996, 24980, 25006, 25134, 25705, 25711, 25721,
- 25758, 25778, 25736, [25744, 57745], 25776, 25765, 25747, 25749, 25769,
- 25746, 25774, 25773, 25771, 25754, 25772, 25753, 25762, 25779, 25973,
- {f: 2, c: 25975}, 26286, 26283, 26292, 26289, 27171, 27167, 27112, 27137,
- 27166, 27161, 27133, 27169, 27155, 27146, 27123, 27138, 27141, 27117,
- 27153, 27472, 27470, 27556, {f: 2, c: 27589}, 28479, 28540, 28548, 28497,
- 28518, 28500, 28550, 28525, 28507, 28536, 28526, 28558, 28538, 28528,
- 28516, 28567, 28504, 28373, 28527, 28512, 28511, 29087, 29100, 29105,
- 29096, 29270, 29339, 29518, 29527, 29801, 29835, 29827, 29822, 29824,
- 30079, 30240, 30249, 30239, 30244, 30246, {f: 2, c: 30241}, 30362, 30394,
- 30436, 30606, 30599, 30604, 30609, 30603, 30923, 30917, 30906, 30922,
- 30910, 30933, 30908, 30928, 31295, 31292, 31296, 31293, 31287, 31291,
- 31407, 31406, 31661, 31665, 31684, 31668, {f: 2, c: 31686}, 31681, 31648,
- 31692, 31946, 32224, 32244, 32239, 32251, 32216, 32236, 32221, 32232,
- 32227, 32218, 32222, 32233, 32158, 32217, 32242, 32249, 32629, 32631,
- 32687, 32745, 32806, {f: 3, c: 33179}, 33184, 33178, 33176, 34071, 34109,
- 34074, 34030, {f: 2, c: 34092}, 34067, 34065, 34083, 34081, 34068, 34028,
- 34085, 34047, 34054, 34690, 34676, 34678, 34656, 34662, 34680, 34664,
- 34649, 34647, 34636, 34643, 34907, 34909, 35088, 35079, {f: 2, c: 35090},
- 35093, 35082, 35516, 35538, 35527, 35524, 35477, 35531, 35576, 35506,
- 35529, 35522, 35519, 35504, 35542, 35533, 35510, 35513, 35547, 35916,
- 35918, 35948, 36064, 36062, 36070, 36068, {f: 2, c: 36076},
- {f: 2, c: 36066}, 36060, 36074, 36065, 36205, 36255, 36259, 36395, 36368,
- 36381, 36386, 36367, 36393, 36383, 36385, 36382, 36538, 36637, 36635,
- 36639, 36649, 36646, 36650, 36636, 36638, 36645, 36969, 36974, 36968,
- 36973, 36983, 37168, 37165, 37159, 37169, 37255, 37257, 37259, 37251,
- 37573, 37563, 37559, 37610, 37604, 37569, 37555, 37564, 37586, 37575,
- 37616, 37554, 38317, 38321, 38660, {f: 2, c: 38662}, 38665, 38752, 38797,
- 38795, 38799, 38945, 38955, 38940, 39091, 39178, 39187, 39186, 39192,
- 39389, 39376, 39391, 39387, 39377, 39381, 39378, 39385, 39607,
- {f: 2, c: 39662}, 39719, 39749, 39748, 39799, 39791, 40198, 40201, 40195,
- 40617, 40638, 40654, 22696, [12242, 40786], 20754, 20760, 20756, 20752,
- 20757, 20864, 20906, 20957, 21137, 21139, 21235, 22105, 22123, 22137,
- 22121, 22116, 22136, 22122, 22120, 22117, 22129, 22127, 22124, 22114,
- 22134, 22721, 22718, 22727, 22725, 22894, 23325, 23348, 23416, 23536,
- 23566, 24394, 25010, 24977, 25001, 24970, 25037, 25014, 25022, 25034,
- 25032, 25136, 25797, 25793, 25803, {f: 2, c: 25787}, 25818, 25796, 25799,
- 25794, 25805, 25791, 25810, 25812, 25790, 25972, 26310, 26313, 26297,
- 26308, 26311, 26296, 27197, 27192, 27194, 27225, 27243, 27224, 27193,
- 27204, 27234, 27233, 27211, 27207, 27189, 27231, 27208, 27481, 27511,
- 27653, 28610, 28593, 28577, 28611, 28580, 28609, 28583, 28595, 28608,
- 28601, [28598, 60318], 28582, 28576, 28596, 29118, 29129, 29136, 29138,
- 29128, 29141, 29113, 29134, 29145, 29148, {f: 2, c: 29123}, 29544, 29852,
- 29859, 29848, 29855, 29854, 29922, {f: 2, c: 29964}, 30260, 30264, 30266,
- 30439, 30437, 30624, {f: 2, c: 30622}, 30629, 30952, 30938, 30956, 30951,
- 31142, {f: 2, c: 31309}, 31302, 31308, 31307, 31418, 31705, 31761, 31689,
- 31716, 31707, 31713, 31721, 31718, {f: 2, c: 31957}, 32266, 32273, 32264,
- 32283, 32291, 32286, [32285, 58211], 32265, 32272, 32633, 32690,
- {f: 2, c: 32752}, 32750, [32808, 58239], 33203, 33193, 33192, 33275, 33288,
- {f: 2, c: 33368}, 34122, 34137, 34120, {f: 2, c: 34152}, 34115, 34121,
- 34157, 34154, 34142, 34691, 34719, 34718, 34722, 34701, 34913, 35114,
- 35122, 35109, 35115, 35105, 35242, [35238, 58391], 35558, 35578, 35563,
- 35569, 35584, 35548, 35559, 35566, 35582, {f: 2, c: 35585}, 35575, 35565,
- 35571, 35574, 35580, 35947, 35949, 35987, 36084, 36420, 36401, 36404,
- 36418, 36409, 36405, 36667, 36655, 36664, 36659, 36776, 36774, 36981,
- 36980, 36984, 36978, 36988, 36986, 37172, 37266, 37664, 37686, 37624,
- 37683, 37679, 37666, 37628, 37675, 37636, 37658, 37648, 37670, 37665,
- 37653, 37678, 37657, 38331, {f: 2, c: 38567}, 38570, 38613, 38670, 38673,
- 38678, 38669, 38675, 38671, 38747, [38748, 58565], 38758, 38808, 38960,
- 38968, 38971, 38967, 38957, 38969, 38948, 39184, 39208, 39198, 39195,
- 39201, 39194, 39405, 39394, 39409, 39608, 39612, 39675, 39661, 39720,
- 39825, 40213, 40227, 40230, 40232, 40210, 40219, 40664, 40660,
- [12243, 40845], [12244, 40860], 20778, 20767, 20769, 20786, 21237, 22158,
- 22144, 22160, 22149, 22151, 22159, 22741, 22739, 22737, 22734, 23344,
- 23338, 23332, 23418, 23607, 23656, 23996, 23994, 23997, 23992, 24171,
- 24396, 24509, 25033, 25026, 25031, 25062, 25035, 25138, 25140, 25806,
- 25802, 25816, 25824, 25840, 25830, 25836, 25841, 25826, 25837,
- {f: 2, c: 25986}, 26329, 26326, 27264, 27284, 27268, 27298, 27292, 27355,
- 27299, 27262, 27287, 27280, 27296, 27484, 27566, 27610, 27656, 28632,
- 28657, {f: 2, c: 28639}, 28635, 28644, 28651, 28655, 28544, 28652, 28641,
- 28649, 28629, 28654, 28656, 29159, [29151, 60361], 29166, 29158, 29157,
- 29165, 29164, 29172, 29152, 29237, 29254, 29552, 29554, 29865, 29872,
- 29862, 29864, 30278, 30274, 30284, 30442, 30643, 30634, 30640, 30636,
- 30631, 30637, 30703, 30967, 30970, 30964, 30959, 30977, 31143, 31146,
- 31319, 31423, 31751, 31757, 31742, 31735, 31756, 31712, 31968, 31964,
- 31966, 31970, 31967, 31961, 31965, 32302, 32318, 32326, 32311, 32306,
- 32323, 32299, 32317, 32305, 32325, 32321, 32308, 32313, 32328, 32309,
- 32319, 32303, 32580, 32755, 32764, {f: 2, c: 32881}, 32880, 32879, 32883,
- 33222, 33219, 33210, 33218, 33216, 33215, 33213, 33225, 33214, 33256,
- 33289, 33393, 34218, 34180, 34174, 34204, 34193, 34196, 34223, 34203,
- 34183, 34216, 34186, 34214, 34407, 34752, 34769, 34739, 34770, 34758,
- 34731, 34747, 34746, 34760, 34763, 35131, 35126, 35140, 35128, 35133,
- 35244, 35598, 35607, 35609, 35611, 35594, 35616, 35613, 35588, 35600,
- 35905, 35903, 35955, 36090, 36093, 36092, 36088, 36091, 36264, 36425,
- 36427, 36424, 36426, 36676, 36670, 36674, 36677, 36671, 36991, 36989,
- 36996, {f: 2, c: 36993}, 36992, 37177, 37283, 37278, 37276, 37709, 37762,
- 37672, 37749, 37706, 37733, 37707, 37656, 37758, 37740, 37723, 37744,
- 37722, 37716, {f: 3, c: 38346}, 38344, 38342, 38577, 38584, 38614, 38684,
- 38686, 38816, 38867, 38982, 39094, 39221, 39425, 39423, 39854, 39851,
- 39850, 39853, 40251, 40255, 40587, 40655, 40670, {f: 2, c: 40668}, 40667,
- 40766, 40779, 21474, 22165, 22190, 22745, 22744, 23352, 24413, 25059,
- 25139, 25844, 25842, 25854, 25862, {f: 2, c: 25850}, 25847, 26039, 26332,
- 26406, 27315, 27308, 27331, 27323, 27320, 27330, {f: 2, c: 27310}, 27487,
- 27512, 27567, 28681, 28683, 28670, 28678, 28666, 28689, 28687,
- {f: 2, c: 29179}, 29182, 29176, 29559, 29557, 29863, 29887, 29973, 30294,
- 30296, 30290, 30653, 30655, {f: 2, c: 30651}, 30990, 31150,
- {f: 2, c: 31329}, 31328, {f: 2, c: 31428}, 31787, 31783, 31786, 31774,
- 31779, 31777, 31975, {f: 2, c: 32340}, 32350, 32346, 32353, 32338, 32345,
- 32584, 32761, 32763, 32887, 32886, 33229, 33231, 33290, 34255, 34217,
- 34253, 34256, 34249, 34224, 34234, 34233, 34799, 34796, 34802, 34784,
- 35206, 35250, 35316, 35624, 35641, 35628, 35627, 35920, 36101, 36441,
- 36451, 36454, 36452, 36447, 36437, 36544, 36681, 36685, 36999, 36995,
- 37000, {f: 2, c: 37291}, 37328, 37780, 37770, 37782, 37794, 37811, 37806,
- 37804, 37808, 37784, 37786, 37783, 38356, 38358, 38352, 38357, 38626,
- 38620, 38617, 38619, 38622, 38692, 38819, 38822, 38829, 38905, 38989,
- 38991, 38988, 38990, 38995, 39098, {f: 2, c: 39230}, 39229, 39214, 39333,
- 39438, 39617, 39683, 39686, 39759, 39758, 39757, 39882, 39881, 39933,
- 39880, 39872, 40273, 40285, 40288, 40672, 40725, 40748, 20787, 22181,
- 22184, {f: 2, c: 22750}, 22754, 23541, 40848, 24300, 25074, 25079, 25078,
- 25077, 25856, 25871, 26336, 26333, 27365, 27357, 27354, 27347, 28699,
- 28703, 28712, 28698, 28701, 28693, 28696, 29190, 29197, 29272, 29346,
- 29560, 29562, 29885, 29898, 29923, 30087, 30086, 30303, 30305, 30663,
- 31001, 31153, 31339, 31337, {f: 2, c: 31806}, 31800, 31805, 31799, 31808,
- 32363, 32365, 32377, {f: 2, c: 32361}, 32371, 32645, 32694, 32697, 32696,
- 33240, 34281, 34269, 34282, 34261, {f: 2, c: 34276}, 34295, 34811, 34821,
- 34829, 34809, 34814, 35168, 35167, 35158, 35166, 35649, 35676, 35672,
- 35657, 35674, {f: 2, c: 35662}, 35654, 35673, 36104, 36106, 36476, 36466,
- 36487, 36470, 36460, 36474, 36468, 36692, 36686, 36781, {f: 2, c: 37002},
- 37297, 37294, 37857, 37841, 37855, 37827, 37832, {f: 2, c: 37852}, 37846,
- 37858, 37837, 37848, 37860, 37847, 37864, 38364, 38580, 38627, 38698,
- 38695, 38753, 38876, 38907, 39006, 39000, 39003, 39100, 39237, 39241,
- 39446, 39449, 39693, 39912, 39911, 39894, 39899, 40329, 40289, 40306,
- 40298, 40300, 40594, 40599, 40595, 40628, 21240, 22199, 22198, 22196,
- 22204, 22756, 23360, 23363, 23421, 23542, 24009, 25080, 25082, 25880,
- 25876, 25881, 26342, 26407, 27372, 28734, 28720, 28722, 29200, 29563,
- 29903, 30306, 30309, 31014, 31018, 31020, 31019, 31431, 31478, 31820,
- 31811, 31821, {f: 2, c: 31983}, 36782, 32381, 32380, 32386, 32588, 32768,
- 33242, 33382, 34299, 34297, 34321, 34298, 34310, 34315, 34311, 34314,
- {f: 2, c: 34836}, 35172, 35258, 35320, 35696, 35692, 35686, 35695, 35679,
- 35691, 36111, 36109, 36489, 36481, 36485, 36482, 37300, 37323, 37912,
- 37891, 37885, 38369, 38704, 39108, 39250, 39249, 39336, 39467, 39472,
- 39479, 39477, 39955, 39949, 40569, 40629, 40680, 40751, 40799, 40803,
- 40801, {f: 2, c: 20791}, 22209, 22208, 22210, 22804, 23660, 24013, 25084,
- 25086, 25885, 25884, 26005, 26345, 27387, 27396, 27386, 27570, 28748,
- 29211, 29351, 29910, 29908, 30313, 30675, 31824, 32399, 32396, 32700,
- 34327, 34349, 34330, 34851, 34850, 34849, 34847, 35178, 35180, 35261,
- 35700, 35703, 35709, 36115, 36490, 36493, 36491, 36703, 36783, 37306,
- 37934, 37939, 37941, 37946, 37944, 37938, 37931, 38370, {f: 2, c: 38712},
- 38706, [38911, 58586], 39015, 39013, 39255, 39493, 39491, 39488, 39486,
- 39631, 39764, 39761, 39981, 39973, 40367, 40372, 40386, 40376, 40605,
- 40687, 40729, 40796, {f: 2, c: 40806}, 20796, 20795, 22216, 22218, 22217,
- 23423, 24020, 24018, 24398, 25087, 25892, 27402, 27489, 28753, 28760,
- 29568, 29924, 30090, 30318, 30316, 31155, 31840, 31839, 32894, 32893,
- 33247, 35186, 35183, 35324, 35712, {f: 2, c: 36118}, 36497, 36499, 36705,
- 37192, 37956, {f: 2, c: 37969}, {f: 2, c: 38717}, 38851, 38849, 39019,
- 39253, 39509, 39501, 39634, 39706, 40009, 39985, 39998, 39995, 40403,
- 40407, 40756, 40812, 40810, 40852, 22220, 24022, 25088, 25891, 25899,
- 25898, 26348, 27408, 29914, 31434, 31844, 31843, 31845, 32403, 32406,
- 32404, 33250, 34360, 34367, 34865, 35722, 37008, 37007, 37987, 37984,
- 37988, 38760, 39023, 39260, {f: 2, c: 39514}, 39511, {f: 2, c: 39635},
- 39633, 40020, 40023, 40022, 40421, 40607, 40692, 22225, 22761, 25900,
- 28766, {f: 2, c: 30321}, [30679, 60226], 32592, 32648, 34870, 34873, 34914,
- 35731, 35730, 35734, 33399, 36123, 37312, 37994, 38722, 38728, 38724,
- 38854, 39024, 39519, 39714, 39768, 40031, {f: 2, c: 40441},
- {f: 2, c: 40572}, 40711, 40823, 40818, 24307, 27414, 28771, 31852, 31854,
- 34875, 35264, 36513, 37313, 38002, 38000, 39025, 39262, 39638, 39715,
- 40652, 28772, 30682, 35738, 38007, 38857, 39522, 39525, 32412, 35740,
- 36522, 37317, {f: 2, c: 38013}, 38012, {f: 2, c: 40055}, 40695, 35924,
- 38015, 40474, 29224, 39530, 39729, 40475, 40478, 31858, 20034, 20060,
- [12048, 20981], [12053, 21274], [12058, 21378], 19975, 19980, 20039, 20109,
- [12062, 22231], [12076, 23662], [12091, 24435], 19983, 20871, 19982, 20014,
- 20115, 20162, 20169, 20168, 20888, 21244, 21356, 21433, 22304, 22787,
- 22828, [23568, 60417], 24063, 26081, [12110, 27571], 27596, [12115, 27668],
- [12121, 29247], 20017, 20028, 20200, 20188, 20201, 20193, 20189, 20186,
- 21004, 21001, 21276, 21324, {f: 2, c: 22306}, 22807, 22831, 23425, 23428,
- 23570, 23611, 23668, 23667, 24068, 24192, 24194, 24521, 25097, 25168,
- 27669, 27702, 27715, 27711, 27707, 29358, 29360, 29578, [12145, 31160],
- 32906, 38430, 20238, 20248, 20268, 20213, 20244, 20209, 20224, 20215,
- 20232, 20253, 20226, 20229, 20258, 20243, 20228, 20212, 20242, 20913,
- 21011, 21008, 21158, 21282, 21279, 21325, 21386, 21511, 22241, 22239,
- 22318, 22314, 22324, 22844, 22912, 22908, 22917, 22907, 22910, 22903,
- 22911, 23382, 23573, 23589, 23676, {f: 2, c: 23674}, 23678, 24031,
- [24181, 57646], 24196, 24322, 24346, 24436, 24533, 24532, 24527, 25180,
- 25182, 25188, 25185, 25190, 25186, 25177, 25184, 25178, 25189, 25911,
- 26095, 26094, 26430, 26425, 26424, 26427, 26426, 26431, 26428, 26419,
- 27672, 27718, 27730, 27740, 27727, [27722, 60796], 27732, {f: 2, c: 27723},
- 28785, 29278, {f: 2, c: 29364}, 29582, 29994, 30335, 31349, [12153, 32593],
- [12171, 33400], 33404, 33408, 33405, 33407, [12172, 34381], [12177, 35198],
- 37017, [37015, 59347], 37016, 37019, 37012, 38434, 38436, 38432, 38435,
- 20310, 20283, 20322, 20297, 20307, 20324, 20286, 20327, 20306, 20319,
- 20289, 20312, 20269, 20275, 20287, 20321, 20879, 20921, 21020, 21022,
- 21025, {f: 2, c: 21165}, 21257, 21347, 21362, {f: 2, c: 21390}, 21552,
- 21559, 21546, 21588, 21573, 21529, 21532, 21541, 21528, 21565, 21583,
- 21569, 21544, 21540, 21575, 22254, 22247, 22245, 22337, 22341, 22348,
- 22345, 22347, 22354, 22790, 22848, 22950, 22936, 22944, 22935, 22926,
- 22946, 22928, 22927, 22951, 22945, 23438, 23442, 23592, 23594, 23693,
- 23695, 23688, 23691, 23689, 23698, 23690, 23686, 23699, 23701, 24032,
- 24074, 24078, 24203, 24201, 24204, 24200, 24205, 24325, 24349, 24440,
- 24438, 24530, 24529, 24528, 24557, 24552, 24558, 24563, 24545, 24548,
- 24547, 24570, 24559, 24567, 24571, 24576, 24564, 25146, 25219, 25228,
- {f: 2, c: 25230}, 25236, 25223, 25201, 25211, 25210, 25200, 25217, 25224,
- 25207, 25213, 25202, 25204, 26096, 26100, 26099, 26098, 26101, 26437,
- 26439, 26457, 26453, 26444, 26440, 26461, 26445, 26458, 26443, 27600,
- {f: 2, c: 27673}, 27768, 27751, 27755, 27780, 27787, 27791, 27761, 27759,
- 27753, 27802, 27757, 27783, 27797, [27804, 57900], 27750, 27763, 27749,
- 27771, 27790, 28788, 28794, 29283, 29375, 29373, 29379, 29382, 29377,
- 29370, 29381, 29589, 29591, {f: 2, c: 29587}, 29586, 30010, 30009,
- {f: 2, c: 30100}, 30337, 31037, 32820, 32917, 32921, 32912, 32914, 32924,
- 33424, 33423, 33413, 33422, 33425, 33427, 33418, {f: 2, c: 33411},
- [12184, 35960], 36809, 36799, 37023, 37025, 37029, 37022, 37031, 37024,
- 38448, 38440, 38447, 38445, 20019, 20376, 20348, 20357, 20349, 20352,
- 20359, 20342, 20340, 20361, 20356, 20343, 20300, 20375, 20330, 20378,
- 20345, 20353, 20344, 20368, 20380, 20372, 20382, 20370, 20354, 20373,
- 20331, 20334, 20894, 20924, 20926, 21045, {f: 2, c: 21042}, 21062, 21041,
- 21180, {f: 2, c: 21258}, 21308, 21394, 21396, 21639, 21631, 21633, 21649,
- 21634, 21640, 21611, 21626, 21630, 21605, 21612, 21620, 21606, 21645,
- 21615, 21601, 21600, 21656, 21603, 21607, 21604, 22263, 22265, 22383,
- 22386, 22381, 22379, 22385, 22384, 22390, 22400, 22389, 22395,
- {f: 2, c: 22387}, 22370, 22376, 22397, 22796, 22853, 22965, 22970, 22991,
- 22990, 22962, 22988, 22977, 22966, 22972, 22979, 22998, 22961, 22973,
- 22976, 22984, 22964, 22983, 23394, 23397, 23443, 23445, 23620, 23623,
- 23726, 23716, 23712, 23733, 23727, 23720, 23724, 23711, 23715, 23725,
- 23714, 23722, 23719, 23709, 23717, 23734, 23728, 23718, 24087, 24084,
- 24089, 24360, {f: 3, c: 24354}, 24404, 24450, 24446, 24445, 24542, 24549,
- 24621, 24614, 24601, 24626, 24587, 24628, 24586, 24599, 24627, 24602,
- 24606, 24620, 24610, 24589, 24592, 24622, 24595, 24593, 24588, 24585,
- 24604, 25108, 25149, 25261, 25268, 25297, 25278, 25258, 25270, 25290,
- 25262, 25267, 25263, 25275, 25257, 25264, 25272, 25917, 26024, 26043,
- 26121, 26108, 26116, 26130, 26120, 26107, 26115, 26123, 26125, 26117,
- 26109, 26129, 26128, 26358, 26378, 26501, 26476, 26510, 26514, 26486,
- 26491, 26520, 26502, 26500, 26484, 26509, 26508, 26490, 26527, 26513,
- 26521, 26499, 26493, 26497, {f: 2, c: 26488}, 26516, 27429, 27520, 27518,
- 27614, 27677, 27795, 27884, 27883, 27886, 27865, 27830, 27860, 27821,
- 27879, 27831, 27856, 27842, 27834, 27843, 27846, 27885, 27890, 27858,
- 27869, 27828, 27786, 27805, 27776, 27870, 27840, 27952, 27853, 27847,
- 27824, 27897, 27855, 27881, 27857, 28820, 28824, 28805, 28819, 28806,
- 28804, 28817, 28822, 28802, 28826, 28803, 29290, 29398, 29387, 29400,
- 29385, 29404, 29394, 29396, 29402, 29388, 29393, 29604, 29601, 29613,
- 29606, 29602, 29600, 29612, 29597, 29917, 29928, {f: 2, c: 30015}, 30014,
- 30092, 30104, 30383, 30451, 30449, 30448, 30453, 30712, 30716, 30713,
- 30715, 30714, 30711, 31042, 31039, 31173, 31352, 31355, 31483, 31861,
- 31997, 32821, 32911, 32942, 32931, 32952, 32949, 32941, 33312, 33440,
- 33472, 33451, 33434, 33432, 33435, 33461, 33447, 33454, 33468, 33438,
- 33466, 33460, 33448, 33441, 33449, 33474, 33444, 33475, 33462, 33442,
- 34416, 34415, {f: 2, c: 34413}, 35926, 36818, 36811, 36819, 36813, 36822,
- 36821, 36823, 37042, 37044, 37039, 37043, 37040, 38457, 38461, 38460,
- 38458, 38467, 20429, 20421, 20435, 20402, 20425, 20427, 20417, 20436,
- 20444, 20441, [20411, 60346], 20403, 20443, 20423, 20438, 20410, 20416,
- 20409, 20460, 21060, 21065, 21184, 21186, 21309, 21372, 21399, 21398,
- 21401, 21400, 21690, 21665, 21677, 21669, 21711, 21699, 33549, 21687,
- 21678, 21718, 21686, {f: 2, c: 21701}, 21664, 21616, 21692, 21666, 21694,
- 21618, 21726, 21680, 22453, {f: 2, c: 22430}, 22436, 22412, 22423, 22429,
- 22427, 22420, 22424, 22415, 22425, 22437, 22426, 22421, 22772, 22797,
- 22867, 23009, 23006, 23022, 23040, 23025, 23005, 23034, 23037, 23036,
- 23030, 23012, 23026, 23031, 23003, 23017, 23027, 23029, 23008, 23038,
- 23028, 23021, 23464, 23628, 23760, 23768, 23756, 23767, 23755, 23771,
- 23774, 23770, 23753, 23751, 23754, 23766, {f: 2, c: 23763}, 23759, 23752,
- 23750, 23758, 23775, 23800, 24057, {f: 3, c: 24097}, 24096, 24100, 24240,
- 24228, 24226, 24219, 24227, 24229, 24327, 24366, 24406, 24454, 24631,
- 24633, 24660, 24690, 24670, 24645, 24659, 24647, 24649, 24667, 24652,
- 24640, 24642, 24671, 24612, 24644, 24664, 24678, 24686, {f: 2, c: 25154},
- 25295, 25357, 25355, 25333, 25358, 25347, 25323, 25337, 25359, 25356,
- 25336, 25334, 25344, {f: 2, c: 25363}, 25338, 25365, 25339, 25328, 25921,
- 25923, 26026, 26047, 26166, 26145, 26162, 26165, 26140, 26150, 26146,
- 26163, 26155, 26170, 26141, 26164, 26169, 26158, {f: 2, c: 26383}, 26561,
- 26610, 26568, 26554, 26588, 26555, 26616, 26584, 26560, 26551, 26565,
- 26603, 26596, 26591, 26549, 26573, 26547, 26615, 26614, 26606, 26595,
- 26562, 26553, 26574, 26599, 26608, 26546, 26620, 26566, 26605, 26572,
- 26542, 26598, 26587, 26618, {f: 2, c: 26569}, 26563, 26602, 26571, 27432,
- 27522, 27524, 27574, 27606, 27608, 27616, {f: 2, c: 27680}, 27944, 27956,
- 27949, 27935, 27964, 27967, 27922, 27914, 27866, 27955, 27908, 27929,
- 27962, 27930, 27921, 27904, 27933, 27970, 27905, 27928, 27959, 27907,
- 27919, 27968, 27911, 27936, 27948, 27912, 27938, 27913, 27920, 28855,
- 28831, 28862, 28849, 28848, 28833, {f: 2, c: 28852}, 28841, 29249,
- {f: 2, c: 29257}, 29292, 29296, 29299, 29294, 29386, 29412, 29416, 29419,
- 29407, 29418, 29414, 29411, 29573, 29644, 29634, 29640, 29637, 29625,
- 29622, 29621, 29620, 29675, 29631, 29639, 29630, 29635, 29638, 29624,
- 29643, 29932, 29934, 29998, {f: 2, c: 30023}, 30119, 30122, 30329, 30404,
- 30472, {f: 3, c: 30467}, 30474, 30455, 30459, 30458, {f: 2, c: 30695},
- 30726, {f: 2, c: 30737}, 30725, 30736, 30735, 30734, [30729, 58095], 30723,
- 30739, 31050, 31052, 31051, 31045, 31044, 31189, 31181, 31183, 31190,
- 31182, 31360, 31358, 31441, {f: 2, c: 31488}, 31866, {f: 2, c: 31864},
- {f: 3, c: 31871}, 32003, 32008, 32001, 32600, 32657, 32653, 32702, 32775,
- {f: 2, c: 32782}, 32788, 32823, 32984, 32967, 32992, 32977, 32968, 32962,
- 32976, 32965, 32995, 32985, 32988, 32970, 32981, 32969, 32975, 32983,
- 32998, 32973, 33279, 33313, 33428, 33497, 33534, 33529, 33543, 33512,
- 33536, 33493, 33594, 33515, 33494, 33524, 33516, 33505, 33522, 33525,
- 33548, 33531, 33526, 33520, 33514, 33508, 33504, 33530, 33523, 33517,
- 34423, 34420, 34428, 34419, 34881, 34894, 34919, 34922, 34921, 35283,
- 35332, 35335, 36210, 36835, 36833, 36846, 36832, 37105, 37053, 37055,
- 37077, 37061, 37054, 37063, 37067, 37064, [37332, 60294], 37331, 38484,
- 38479, 38481, 38483, 38474, 38478, 20510, 20485, 20487, 20499, 20514,
- 20528, 20507, 20469, 20468, 20531, 20535, 20524, {f: 2, c: 20470}, 20503,
- 20508, 20512, 20519, 20533, 20527, 20529, 20494, 20826, 20884, 20883,
- 20938, {f: 2, c: 20932}, 20936, 20942, 21089, 21082, 21074,
- {f: 2, c: 21086}, 21077, 21090, 21197, 21262, 21406, 21798, 21730, 21783,
- 21778, 21735, 21747, 21732, 21786, 21759, 21764, 21768, 21739, 21777,
- 21765, 21745, 21770, 21755, {f: 2, c: 21751}, 21728, 21774, 21763, 21771,
- {f: 2, c: 22273}, 22476, 22578, 22485, 22482, 22458, 22470, 22461, 22460,
- 22456, 22454, 22463, 22471, 22480, 22457, 22465, 22798, 22858, 23065,
- 23062, {f: 2, c: 23085}, 23061, 23055, 23063, 23050, 23070, 23091, 23404,
- 23463, 23469, 23468, 23555, 23638, 23636, 23788, 23807, 23790, 23793,
- 23799, 23808, 23801, 24105, 24104, 24232, 24238, 24234, 24236, 24371,
- 24368, 24423, 24669, 24666, 24679, 24641, 24738, 24712, 24704, 24722,
- 24705, 24733, 24707, 24725, 24731, 24727, 24711, 24732, 24718, 25113,
- 25158, 25330, 25360, 25430, 25388, {f: 2, c: 25412}, 25398, 25411, 25572,
- 25401, 25419, 25418, 25404, 25385, 25409, 25396, 25432, 25428, 25433,
- 25389, 25415, 25395, 25434, 25425, 25400, 25431, 25408, 25416, 25930,
- 25926, 26054, {f: 2, c: 26051}, 26050, 26186, 26207, 26183, 26193,
- {f: 2, c: 26386}, 26655, 26650, 26697, {f: 2, c: 26674}, 26683, 26699,
- 26703, 26646, 26673, 26652, 26677, 26667, 26669, 26671, 26702, 26692,
- 26676, 26653, 26642, 26644, 26662, 26664, 26670, 26701, 26682, 26661,
- 26656, 27436, 27439, 27437, 27441, 27444, 27501, 32898, 27528, 27622,
- 27620, 27624, 27619, 27618, 27623, 27685, 28026, {f: 2, c: 28003}, 28022,
- 27917, 28001, 28050, 27992, 28002, 28013, 28015, 28049, 28045, 28143,
- 28031, 28038, 27998, [28007, 59078], 28000, 28055, 28016, 28028, 27999,
- 28034, 28056, 27951, 28008, 28043, 28030, 28032, 28036, 27926, 28035,
- 28027, 28029, 28021, 28048, 28892, 28883, 28881, 28893, 28875, 32569,
- 28898, 28887, 28882, 28894, 28896, 28884, 28877, {f: 3, c: 28869}, 28890,
- 28878, 28897, 29250, 29304, 29303, 29302, 29440, 29434, 29428, 29438,
- 29430, 29427, 29435, 29441, 29651, 29657, 29669, 29654, 29628, 29671,
- 29667, 29673, 29660, 29650, 29659, 29652, 29661, 29658, {f: 2, c: 29655},
- 29672, {f: 2, c: 29918}, {f: 2, c: 29940}, 29985, 30043, 30047, 30128,
- 30145, 30139, 30148, 30144, 30143, 30134, 30138, 30346, 30409, 30493,
- 30491, 30480, 30483, 30482, 30499, 30481, 30485, {f: 2, c: 30489}, 30498,
- 30503, 30755, 30764, 30754, 30773, 30767, 30760, 30766, 30763, 30753,
- 30761, 30771, 30762, 30769, 31060, 31067, 31055, 31068, 31059, 31058,
- 31057, {f: 2, c: 31211}, 31200, 31214, 31213, 31210, 31196, 31198, 31197,
- 31366, 31369, 31365, {f: 2, c: 31371}, 31370, 31367, 31448, 31504, 31492,
- 31507, 31493, 31503, 31496, 31498, 31502, 31497, 31506, 31876, 31889,
- 31882, 31884, 31880, 31885, 31877, 32030, 32029, 32017, 32014, 32024,
- 32022, 32019, 32031, 32018, 32015, 32012, 32604, 32609, 32606, 32608,
- 32605, 32603, 32662, 32658, 32707, 32706, 32704, 32790, 32830, 32825,
- 33018, 33010, 33017, 33013, 33025, 33019, 33024, 33281, 33327, 33317,
- 33587, 33581, 33604, 33561, 33617, 33573, 33622, 33599, 33601, 33574,
- 33564, 33570, 33602, 33614, 33563, 33578, 33544, 33596, 33613, 33558,
- 33572, 33568, 33591, 33583, 33577, 33607, 33605, 33612, 33619, 33566,
- 33580, 33611, 33575, 33608, 34387, 34386, 34466, 34472, 34454, 34445,
- 34449, 34462, 34439, 34455, 34438, 34443, 34458, 34437, 34469, 34457,
- 34465, 34471, 34453, 34456, 34446, 34461, 34448, 34452, {f: 2, c: 34883},
- 34925, {f: 2, c: 34933}, 34930, 34944, 34929, 34943, 34927, 34947, 34942,
- 34932, 34940, 35346, 35911, 35927, 35963, 36004, 36003, 36214, 36216,
- 36277, 36279, 36278, 36561, 36563, 36862, 36853, 36866, 36863, 36859,
- 36868, 36860, 36854, 37078, 37088, {f: 2, c: 37081}, 37091, 37087, 37093,
- 37080, 37083, 37079, 37084, 37092, 37200, {f: 2, c: 37198}, 37333, 37346,
- 37338, 38492, 38495, 38588, 39139, [12221, 39647], [12223, 39727], 20095,
- 20592, 20586, 20577, 20574, 20576, 20563, 20555, 20573, 20594, 20552,
- 20557, 20545, 20571, 20554, 20578, 20501, 20549, 20575, 20585, 20587,
- {f: 2, c: 20579}, 20550, 20544, 20590, 20595, 20567, 20561, 20944, 21099,
- 21101, 21100, 21102, 21206, 21203, 21293, 21404, {f: 2, c: 21877}, 21820,
- 21837, 21840, 21812, 21802, 21841, 21858, 21814, 21813, 21808, 21842,
- 21829, 21772, 21810, 21861, 21838, 21817, 21832, 21805, 21819, 21824,
- 21835, 22282, 22279, 22523, 22548, 22498, 22518, 22492, 22516, 22528,
- 22509, 22525, 22536, 22520, 22539, 22515, 22479, 22535, 22510, 22499,
- 22514, 22501, 22508, 22497, 22542, 22524, 22544, 22503, 22529, 22540,
- 22513, 22505, 22512, 22541, 22532, 22876, 23136, 23128, 23125,
- [23143, 60437], 23134, 23096, 23093, 23149, 23120, 23135, 23141, 23148,
- 23123, 23140, 23127, 23107, 23133, 23122, 23108, 23131, 23112, 23182,
- 23102, 23117, 23097, 23116, 23152, 23145, 23111, 23121, 23126, 23106,
- 23132, 23410, 23406, 23489, 23488, 23641, 23838, 23819, 23837, 23834,
- 23840, 23820, 23848, 23821, 23846, 23845, 23823, 23856, 23826, 23843,
- 23839, 23854, 24126, 24116, 24241, 24244, 24249, {f: 2, c: 24242}, 24374,
- 24376, 24475, 24470, 24479, 24714, 24720, 24710, 24766, 24752, 24762,
- {f: 2, c: 24787}, 24783, 24804, 24793, 24797, 24776, 24753, 24795, 24759,
- 24778, 24767, 24771, 24781, 24768, 25394, 25445, 25482, 25474, 25469,
- 25533, 25502, 25517, 25501, 25495, 25515, 25486, 25455, 25479, 25488,
- 25454, 25519, 25461, 25500, 25453, 25518, 25468, 25508, 25403, 25503,
- 25464, 25477, 25473, 25489, 25485, 25456, 25939, 26061, 26213, 26209,
- 26203, 26201, 26204, 26210, 26392, 26745, 26759, 26768, 26780,
- {f: 2, c: 26733}, 26798, 26795, 26966, 26735, 26787, 26796, 26793, 26741,
- 26740, 26802, 26767, 26743, 26770, 26748, 26731, 26738, 26794, 26752,
- 26737, 26750, 26779, 26774, 26763, 26784, 26761, 26788, 26744, 26747,
- 26769, 26764, 26762, 26749, 27446, 27443, {f: 2, c: 27447}, 27537, 27535,
- {f: 2, c: 27533}, 27532, 27690, 28096, 28075, 28084, 28083, 28276, 28076,
- 28137, 28130, 28087, 28150, 28116, 28160, 28104, 28128, 28127, 28118,
- 28094, 28133, {f: 2, c: 28124}, 28123, 28148, 28106, 28093, 28141, 28144,
- 28090, 28117, 28098, 28111, 28105, 28112, 28146, 28115, 28157, 28119,
- 28109, 28131, 28091, 28922, 28941, 28919, 28951, 28916, 28940, 28912,
- 28932, 28915, 28944, 28924, 28927, 28934, 28947, 28928, 28920, 28918,
- 28939, 28930, 28942, 29310, {f: 2, c: 29307}, 29311, 29469, 29463, 29447,
- 29457, 29464, 29450, 29448, 29439, 29455, 29470, 29576, 29686, 29688,
- 29685, 29700, 29697, 29693, 29703, 29696, 29690, 29692, 29695, 29708,
- 29707, 29684, 29704, 30052, 30051, 30158, 30162, 30159, {f: 2, c: 30155},
- 30161, 30160, 30351, 30345, 30419, 30521, 30511, 30509, {f: 2, c: 30513},
- 30516, 30515, 30525, 30501, 30523, 30517, 30792, 30802, 30793, 30797,
- 30794, 30796, 30758, 30789, 30800, 31076, 31079, {f: 2, c: 31081}, 31075,
- 31083, 31073, 31163, 31226, 31224, {f: 2, c: 31222}, 31375, 31380, 31376,
- 31541, 31547, 31540, 31525, 31536, 31522, 31524, 31539, 31512, 31530,
- 31517, 31537, 31531, 31533, 31535, 31538, 31544, 31514, 31523, 31892,
- 31896, 31894, 31907, 32053, 32061, 32056, 32054, 32058, 32069, 32044,
- 32041, 32065, 32071, {f: 2, c: 32062}, 32074, 32059, 32040, 32611, 32661,
- {f: 2, c: 32668}, 32667, {f: 2, c: 32714}, 32717, {f: 2, c: 32720}, 32711,
- 32719, 32713, 32799, 32798, 32795, 32839, 32835, 32840, 33048, 33061,
- 33049, 33051, 33069, 33055, 33068, 33054, 33057, 33045, 33063, 33053,
- 33058, 33297, 33336, 33331, 33338, 33332, 33330, 33396, 33680, 33699,
- 33704, 33677, 33658, 33651, 33700, 33652, 33679, 33665, 33685, 33689,
- 33653, 33684, 33705, 33661, 33667, 33676, 33693, 33691, 33706, 33675,
- 33662, 33701, 33711, 33672, 33687, 33712, 33663, 33702, 33671, 33710,
- 33654, 34393, 34390, 34495, 34487, 34498, 34497, 34501, 34490, 34480,
- 34504, 34489, 34483, 34488, 34508, 34484, {f: 2, c: 34491}, 34499,
- {f: 2, c: 34493}, 34898, 34953, 34965, 34984, 34978, 34986, 34970, 34961,
- 34977, 34975, 34968, 34983, 34969, 34971, 34967, 34980, 34988, 34956,
- 34963, 34958, 35202, 35286, 35289, 35285, 35376, 35367, 35372, 35358,
- 35897, 35899, {f: 2, c: 35932}, 35965, 36005, 36221, 36219, 36217, 36284,
- 36290, 36281, 36287, 36289, 36568, 36574, 36573, 36572, 36567,
- {f: 2, c: 36576}, 36900, 36875, 36881, 36892, 36876, 36897, 37103, 37098,
- 37104, 37108, {f: 2, c: 37106}, 37076, {f: 2, c: 37099}, 37097, 37206,
- 37208, 37210, 37203, 37205, 37356, 37364, 37361, 37363, 37368, 37348,
- 37369, {f: 2, c: 37354}, 37367, 37352, 37358, 38266, 38278, 38280, 38524,
- 38509, 38507, 38513, 38511, 38591, 38762, 38916, 39141, 39319, 20635,
- 20629, 20628, 20638, 20619, 20643, 20611, 20620, 20622, 20637, 20584,
- 20636, 20626, 20610, 20615, 20831, 20948, 21266, 21265, 21412, 21415,
- 21905, 21928, 21925, 21933, 21879, 22085, 21922, 21907, 21896, 21903,
- 21941, 21889, 21923, 21906, 21924, 21885, 21900, 21926, 21887, 21909,
- 21921, 21902, 22284, 22569, 22583, 22553, 22558, 22567, 22563, 22568,
- 22517, 22600, 22565, 22556, 22555, 22579, 22591, 22582, 22574, 22585,
- 22584, 22573, 22572, 22587, 22881, 23215, 23188, 23199, 23162, 23202,
- 23198, 23160, 23206, 23164, 23205, 23212, 23189, 23214, 23095, 23172,
- 23178, 23191, 23171, 23179, 23209, 23163, 23165, 23180, 23196, 23183,
- 23187, 23197, 23530, 23501, 23499, 23508, 23505, 23498, 23502, 23564,
- 23600, 23863, 23875, 23915, 23873, 23883, 23871, 23861, 23889, 23886,
- 23893, 23859, 23866, 23890, 23869, 23857, 23897, 23874, 23865, 23881,
- 23864, 23868, 23858, 23862, 23872, 23877, 24132, 24129, [24408, 57673],
- 24486, 24485, 24491, 24777, 24761, 24780, 24802, 24782, 24772, 24852,
- 24818, 24842, 24854, 24837, 24821, 24851, 24824, 24828, 24830, 24769,
- 24835, 24856, 24861, 24848, 24831, 24836, 24843, 25162, 25492, 25521,
- 25520, 25550, 25573, 25576, 25583, 25539, 25757, 25587, 25546, 25568,
- 25590, 25557, 25586, 25589, 25697, 25567, 25534, 25565, 25564, 25540,
- 25560, 25555, 25538, 25543, 25548, 25547, 25544, 25584, 25559, 25561,
- 25906, 25959, 25962, 25956, 25948, 25960, 25957, 25996, {f: 2, c: 26013},
- 26030, 26064, 26066, 26236, 26220, 26235, 26240, 26225, 26233, 26218,
- 26226, 26369, 26892, 26835, 26884, 26844, 26922, 26860, 26858, 26865,
- 26895, 26838, 26871, 26859, 26852, 26870, 26899, 26896, 26867, 26849,
- 26887, 26828, 26888, 26992, 26804, 26897, 26863, 26822, 26900, 26872,
- 26832, 26877, 26876, 26856, 26891, 26890, 26903, 26830, 26824,
- {f: 2, c: 26845}, 26854, 26868, 26833, 26886, 26836, 26857, 26901, 26917,
- 26823, 27449, 27451, 27455, 27452, 27540, 27543, 27545, 27541, 27581,
- 27632, {f: 2, c: 27634}, 27696, 28156, {f: 2, c: 28230}, 28191, 28233,
- 28296, {f: 2, c: 28220}, 28229, 28258, 28203, 28223, 28225, 28253, 28275,
- 28188, 28211, 28235, 28224, 28241, 28219, 28163, 28206, 28254, 28264,
- 28252, 28257, 28209, 28200, 28256, 28273, 28267, 28217, 28194, 28208,
- 28243, 28261, 28199, 28280, 28260, 28279, 28245, 28281, 28242, 28262,
- {f: 2, c: 28213}, 28250, 28960, 28958, 28975, 28923, 28974, 28977, 28963,
- 28965, 28962, 28978, 28959, 28968, 28986, 28955, 29259, 29274,
- {f: 2, c: 29320}, 29318, 29317, 29323, 29458, 29451, 29488, 29474, 29489,
- 29491, 29479, 29490, 29485, 29478, 29475, 29493, 29452, 29742, 29740,
- 29744, 29739, 29718, 29722, 29729, 29741, 29745, 29732, 29731, 29725,
- 29737, 29728, 29746, 29947, 29999, 30063, 30060, 30183, 30170, 30177,
- 30182, 30173, 30175, 30180, 30167, 30357, 30354, 30426, {f: 2, c: 30534},
- 30532, 30541, 30533, 30538, 30542, {f: 2, c: 30539}, 30686, 30700, 30816,
- {f: 2, c: 30820}, 30812, 30829, 30833, 30826, 30830, 30832, 30825, 30824,
- 30814, 30818, 31092, 31091, 31090, 31088, 31234, 31242, 31235, 31244,
- 31236, 31385, 31462, 31460, 31562, 31559, 31556, 31560, 31564, 31566,
- 31552, 31576, 31557, 31906, 31902, 31912, 31905, 32088, 32111, 32099,
- 32083, 32086, 32103, 32106, 32079, 32109, 32092, 32107, 32082, 32084,
- 32105, 32081, 32095, 32078, {f: 2, c: 32574}, {f: 2, c: 32613}, 32674,
- {f: 2, c: 32672}, 32727, 32849, {f: 2, c: 32847}, 33022, 32980, 33091,
- 33098, 33106, 33103, 33095, 33085, 33101, 33082, 33254, 33262,
- {f: 3, c: 33271}, 33284, {f: 2, c: 33340}, 33343, 33397, 33595,
- [33743, 60382], 33785, 33827, 33728, 33768, 33810, 33767, 33764, 33788,
- 33782, 33808, 33734, 33736, 33771, 33763, 33727, 33793, 33757, 33765,
- 33752, 33791, 33761, 33739, 33742, 33750, 33781, 33737, 33801,
- [33807, 58332], 33758, 33809, 33798, 33730, 33779, 33749, 33786, 33735,
- 33745, 33770, 33811, 33690, 33731, 33772, 33774, 33732, 33787, 33751,
- 33762, 33819, 33755, 33790, 34520, 34530, 34534, 34515, 34531, 34522,
- 34538, 34525, 34539, 34524, 34540, 34537, 34519, 34536, 34513, 34888,
- 34902, 34901, 35002, 35031, 35001, 35000, 35008, 35006, 34998, 35004,
- 34999, 35005, 34994, 35073, 35017, 35221, 35224, 35223, 35293,
- {f: 2, c: 35290}, 35406, 35405, 35385, 35417, 35392, {f: 2, c: 35415},
- {f: 2, c: 35396}, 35410, 35400, 35409, 35402, 35404, 35407, 35935, 35969,
- 35968, 36026, 36030, 36016, 36025, 36021, 36228, 36224, 36233, 36312,
- 36307, 36301, 36295, 36310, 36316, 36303, 36309, 36313, 36296, 36311,
- 36293, 36591, 36599, 36602, 36601, 36582, 36590, 36581, 36597,
- {f: 2, c: 36583}, 36598, 36587, 36593, 36588, 36596, 36585, 36909, 36916,
- 36911, 37126, 37164, [37124, 60367], 37119, 37116, 37128, 37113, 37115,
- 37121, 37120, 37127, 37125, 37123, 37217, 37220, 37215, 37218, 37216,
- 37377, 37386, 37413, 37379, 37402, 37414, 37391, 37388, 37376, 37394,
- 37375, 37373, 37382, 37380, 37415, 37378, 37404, 37412, 37401, 37399,
- 37381, 37398, 38267, 38285, 38284, 38288, 38535, 38526, {f: 2, c: 38536},
- 38531, 38528, 38594, 38600, 38595, 38641, 38640, 38764, 38768, 38766,
- 38919, 39081, 39147, 40166, [12235, 40697], {f: 2, c: 20099}, 20150, 20669,
- 20671, 20678, 20654, 20676, 20682, 20660, 20680, 20674, 20656, 20673,
- 20666, 20657, 20683, 20681, 20662, 20664, 20951, 21114, 21112,
- {f: 2, c: 21115}, 21955, 21979, 21964, 21968, 21963, 21962, 21981,
- [21952, 64013], 21972, 21956, 21993, 21951, 21970, 21901, 21967, 21973,
- 21986, 21974, 21960, 22002, 21965, 21977, 21954, 22292, 22611, 22632,
- 22628, 22607, 22605, 22601, 22639, 22613, 22606, 22621, 22617, 22629,
- 22619, 22589, 22627, 22641, 22780, 23239, 23236, 23243, 23226, 23224,
- 23217, 23221, 23216, 23231, 23240, 23227, 23238, 23223, 23232, 23242,
- 23220, 23222, 23245, 23225, 23184, 23510, {f: 2, c: 23512}, 23583, 23603,
- 23921, 23907, 23882, 23909, 23922, 23916, 23902, 23912, 23911, 23906,
- 24048, 24143, 24142, 24138, 24141, 24139, 24261, 24268, 24262, 24267,
- 24263, 24384, 24495, 24493, 24823, {f: 2, c: 24905}, 24875, 24901, 24886,
- 24882, 24878, 24902, 24879, 24911, 24873, 24896, 25120, 37224, 25123,
- 25125, 25124, 25541, 25585, 25579, 25616, 25618, 25609, 25632, 25636,
- 25651, 25667, 25631, 25621, 25624, 25657, 25655, {f: 2, c: 25634}, 25612,
- 25638, 25648, 25640, 25665, 25653, 25647, 25610, 25626, 25664, 25637,
- 25639, 25611, 25575, 25627, 25646, 25633, 25614, 25967, 26002, 26067,
- 26246, 26252, 26261, 26256, 26251, 26250, 26265, 26260, 26232, 26400,
- 26982, 26975, 26936, 26958, 26978, 26993, 26943, 26949, 26986, 26937,
- 26946, 26967, 26969, 27002, {f: 2, c: 26952}, 26933, 26988, 26931, 26941,
- 26981, 26864, 27000, 26932, 26985, 26944, 26991, 26948, 26998, 26968,
- 26945, 26996, 26956, 26939, 26955, 26935, 26972, 26959, 26961, 26930,
- 26962, 26927, 27003, 26940, 27462, 27461, 27459, 27458, 27464, 27457,
- 27547, {f: 2, c: 27643}, 27641, {f: 2, c: 27639}, 28315, 28374, 28360,
- 28303, 28352, 28319, {f: 2, c: 28307}, 28320, 28337, 28345, 28358, 28370,
- 28349, 28353, 28318, 28361, 28343, 28336, 28365, 28326, 28367, 28338,
- 28350, 28355, 28380, 28376, 28313, 28306, 28302, 28301, 28324, 28321,
- 28351, 28339, 28368, 28362, 28311, 28334, 28323, 28999, 29012, 29010,
- 29027, 29024, 28993, 29021, [29026, 61080], 29042, 29048, 29034, 29025,
- 28994, 29016, 28995, 29003, 29040, 29023, 29008, 29011, 28996, 29005,
- 29018, 29263, 29325, 29324, 29329, 29328, 29326, 29500, 29506, 29499,
- 29498, 29504, 29514, 29513, 29764, {f: 2, c: 29770}, 29778, 29777, 29783,
- 29760, {f: 2, c: 29775}, 29774, 29762, 29766, 29773, 29780, 29921, 29951,
- 29950, 29949, 29981, 30073, 30071, 27011, 30191, 30223, 30211, 30199,
- 30206, 30204, [30201, 60782], 30200, 30224, 30203, 30198, 30189, 30197,
- 30205, 30361, 30389, 30429, 30549, {f: 2, c: 30559}, 30546, 30550, 30554,
- 30569, 30567, 30548, 30553, 30573, 30688, 30855, 30874, 30868, 30863,
- 30852, 30869, {f: 2, c: 30853}, 30881, 30851, 30841, 30873, 30848, 30870,
- 30843, 31100, 31106, 31101, 31097, 31249, {f: 2, c: 31256}, 31250, 31255,
- 31253, 31266, 31251, 31259, 31248, 31395, 31394, 31390, 31467, 31590,
- 31588, 31597, 31604, 31593, 31602, 31589, 31603, 31601, 31600, 31585,
- 31608, 31606, 31587, 31922, 31924, 31919, 32136, 32134, 32128, 32141,
- 32127, 32133, 32122, 32142, 32123, 32131, 32124, 32140, 32148, 32132,
- 32125, 32146, 32621, 32619, {f: 2, c: 32615}, 32620, 32678, 32677, 32679,
- {f: 2, c: 32731}, 32801, 33124, 33120, 33143, 33116, 33129, 33115, 33122,
- 33138, 26401, 33118, 33142, 33127, 33135, 33092, 33121, 33309, 33353,
- 33348, 33344, 33346, 33349, 34033, 33855, 33878, 33910, 33913, 33935,
- 33933, 33893, 33873, 33856, 33926, 33895, 33840, 33869, 33917, 33882,
- 33881, 33908, 33907, 33885, 34055, 33886, 33847, 33850, 33844, 33914,
- 33859, 33912, 33842, 33861, 33833, 33753, 33867, 33839, 33858, 33837,
- 33887, 33904, 33849, 33870, 33868, 33874, 33903, 33989, 33934, 33851,
- 33863, 33846, 33843, 33896, 33918, 33860, 33835, 33888, 33876, 33902,
- 33872, 34571, 34564, 34551, 34572, 34554, 34518, 34549, 34637, 34552,
- 34574, 34569, 34561, 34550, 34573, 34565, 35030, 35019, {f: 2, c: 35021},
- 35038, 35035, 35034, 35020, 35024, 35205, 35227, 35295, 35301, 35300,
- 35297, 35296, 35298, 35292, 35302, 35446, 35462, 35455, 35425, 35391,
- 35447, 35458, 35460, 35445, 35459, 35457, 35444, 35450, 35900, 35915,
- 35914, 35941, 35940, 35942, 35974, {f: 2, c: 35972}, 36044,
- {f: 2, c: 36200}, 36241, 36236, {f: 2, c: 36238}, 36237, {f: 2, c: 36243},
- 36240, 36242, 36336, 36320, 36332, 36337, 36334, 36304, 36329, 36323,
- 36322, 36327, 36338, 36331, 36340, 36614, 36607, 36609, 36608, 36613,
- {f: 2, c: 36615}, 36610, [36619, 60507], 36946, 36927, 36932, 36937, 36925,
- 37136, 37133, 37135, 37137, 37142, 37140, 37131, 37134, {f: 2, c: 37230},
- 37448, 37458, 37424, 37434, 37478, 37427, 37477, 37470, 37507, 37422,
- 37450, 37446, 37485, 37484, 37455, 37472, 37479, 37487, 37430, 37473,
- 37488, 37425, 37460, 37475, 37456, 37490, 37454, 37459, 37452, 37462,
- 37426, 38303, 38300, 38302, 38299, {f: 2, c: 38546}, 38545, 38551, 38606,
- 38650, 38653, 38648, 38645, 38771, {f: 2, c: 38775}, 38770, 38927,
- {f: 2, c: 38925}, 39084, 39158, 39161, 39343, 39346, 39344, 39349, 39597,
- 39595, 39771, 40170, 40173, 40167, 40576, [12236, 40701], 20710, 20692,
- 20695, 20712, 20723, 20699, 20714, 20701, 20708, 20691, 20716, 20720,
- 20719, 20707, 20704, 20952, {f: 2, c: 21120}, 21225, 21227, 21296, 21420,
- 22055, 22037, 22028, 22034, 22012, 22031, 22044, 22017, 22035, 22018,
- 22010, 22045, 22020, 22015, 22009, 22665, 22652, 22672, 22680, 22662,
- 22657, 22655, 22644, 22667, 22650, 22663, 22673, 22670, 22646, 22658,
- 22664, 22651, 22676, 22671, 22782, 22891, 23260, 23278, 23269, 23253,
- 23274, 23258, 23277, 23275, 23283, 23266, 23264, 23259, 23276, 23262,
- 23261, 23257, 23272, 23263, 23415, 23520, 23523, 23651, 23938, 23936,
- 23933, 23942, 23930, 23937, 23927, 23946, 23945, 23944, 23934, 23932,
- 23949, 23929, 23935, {f: 2, c: 24152}, 24147, 24280, 24273, 24279, 24270,
- 24284, 24277, 24281, 24274, 24276, 24388, 24387, 24431, 24502, 24876,
- 24872, 24897, 24926, 24945, 24947, {f: 2, c: 24914}, 24946, 24940, 24960,
- 24948, 24916, 24954, 24923, 24933, 24891, 24938, 24929, 24918, 25129,
- 25127, 25131, 25643, 25677, 25691, 25693, 25716, 25718, {f: 2, c: 25714},
- 25725, 25717, 25702, 25766, 25678, 25730, 25694, 25692, 25675, 25683,
- 25696, 25680, 25727, 25663, 25708, 25707, 25689, 25701, 25719, 25971,
- 26016, 26273, 26272, 26271, 26373, 26372, 26402, 27057, 27062, 27081,
- 27040, 27086, 27030, 27056, 27052, 27068, 27025, 27033, 27022, 27047,
- 27021, 27049, 27070, 27055, 27071, 27076, 27069, 27044, 27092, 27065,
- 27082, 27034, 27087, 27059, 27027, 27050, 27041, 27038, 27097, 27031,
- 27024, 27074, 27061, 27045, 27078, 27466, 27469, 27467, {f: 3, c: 27550},
- {f: 2, c: 27587}, 27646, 28366, 28405, 28401, 28419, 28453, 28408, 28471,
- 28411, 28462, 28425, 28494, {f: 2, c: 28441}, 28455, 28440, 28475, 28434,
- 28397, 28426, 28470, 28531, 28409, 28398, 28461, 28480, 28464, 28476,
- 28469, 28395, 28423, 28430, 28483, 28421, 28413, 28406, 28473, 28444,
- 28412, 28474, 28447, 28429, 28446, 28424, 28449, 29063, 29072, 29065,
- 29056, 29061, 29058, 29071, 29051, 29062, 29057, 29079, 29252, 29267,
- 29335, 29333, 29331, 29507, 29517, 29521, 29516, 29794, 29811, 29809,
- 29813, 29810, 29799, 29806, 29952, {f: 2, c: 29954}, 30077, 30096, 30230,
- 30216, 30220, 30229, 30225, 30218, 30228, 30392, 30593, 30588, 30597,
- 30594, 30574, 30592, 30575, 30590, 30595, 30898, 30890, 30900, 30893,
- 30888, 30846, 30891, 30878, 30885, 30880, 30892, 30882, 30884, 31128,
- {f: 2, c: 31114}, 31126, 31125, 31124, 31123, 31127, 31112, 31122, 31120,
- 31275, 31306, 31280, 31279, 31272, 31270, 31400, {f: 2, c: 31403}, 31470,
- 31624, 31644, 31626, 31633, 31632, 31638, 31629, 31628, 31643, 31630,
- 31621, 31640, 21124, 31641, 31652, 31618, 31931, 31935, 31932, 31930,
- 32167, 32183, 32194, 32163, 32170, 32193, 32192, 32197, 32157, 32206,
- 32196, 32198, {f: 2, c: 32203}, 32175, 32185, 32150, 32188, 32159, 32166,
- 32174, 32169, 32161, 32201, 32627, {f: 2, c: 32738}, 32741, 32734, 32804,
- 32861, 32860, 33161, 33158, 33155, 33159, 33165, 33164, 33163, 33301,
- 33943, 33956, 33953, 33951, 33978, 33998, 33986, 33964, 33966, 33963,
- 33977, 33972, 33985, 33997, 33962, 33946, 33969, 34000, 33949, 33959,
- 33979, 33954, 33940, 33991, 33996, 33947, 33961, 33967, [33960, 58327],
- 34006, 33944, 33974, 33999, 33952, 34007, 34004, 34002, 34011, 33968,
- 33937, 34401, 34611, 34595, 34600, 34667, 34624, 34606, 34590, 34593,
- 34585, 34587, 34627, 34604, 34625, 34622, 34630, 34592, 34610, 34602,
- 34605, 34620, 34578, 34618, 34609, 34613, 34626, {f: 2, c: 34598}, 34616,
- 34596, 34586, 34608, 34577, 35063, 35047, {f: 2, c: 35057}, 35066, 35070,
- 35054, 35068, 35062, 35067, 35056, 35052, 35051, 35229, 35233, 35231,
- 35230, 35305, 35307, 35304, 35499, 35481, 35467, 35474, 35471, 35478,
- 35901, {f: 2, c: 35944}, 36053, 36047, 36055, 36246, 36361, 36354, 36351,
- 36365, 36349, 36362, 36355, 36359, 36358, 36357, 36350, 36352, 36356,
- {f: 2, c: 36624}, 36622, 36621, 37155, 37148, 37152, 37154, 37151, 37149,
- 37146, 37156, 37153, 37147, 37242, 37234, 37241, 37235, 37541, 37540,
- 37494, 37531, 37498, 37536, 37524, 37546, 37517, 37542, 37530, 37547,
- 37497, 37527, 37503, 37539, 37614, 37518, 37506, 37525, 37538, 37501,
- 37512, 37537, 37514, 37510, 37516, 37529, 37543, 37502, 37511, 37545,
- 37533, 37515, 37421, 38558, 38561, 38655, 38744, 38781, 38778, 38782,
- 38787, 38784, 38786, 38779, 38788, 38785, 38783, 38862, 38861, 38934,
- {f: 2, c: 39085}, 39170, 39168, 39175, 39325, 39324, 39363, 39353, 39355,
- 39354, 39362, 39357, 39367, 39601, 39651, 39655, {f: 2, c: 39742},
- {f: 2, c: 39776}, 39775, {f: 2, c: 40177}, 40181, 40615, 20735, 20739,
- 20784, 20728, {f: 2, c: 20742}, 20726, 20734, {f: 2, c: 20747}, 20733,
- 20746, {f: 2, c: 21131}, 21233, 21231, 22088, 22082, 22092, 22069, 22081,
- 22090, 22089, 22086, 22104, 22106, 22080, 22067, 22077, 22060, 22078,
- 22072, 22058, 22074, 22298, 22699, 22685, 22705, 22688, 22691, 22703,
- 22700, 22693, 22689, 22783, 23295, 23284, 23293, 23287, 23286, 23299,
- 23288, 23298, 23289, 23297, 23303, 23301, 23311, 23655, 23961, 23959,
- 23967, 23954, 23970, 23955, 23957, 23968, 23964, 23969, 23962, 23966,
- 24169, 24157, 24160, 24156, 32243, 24283, 24286, 24289, 24393, 24498,
- 24971, 24963, 24953, 25009, 25008, 24994, 24969, 24987, 24979, 25007,
- 25005, 24991, 24978, 25002, 24993, 24973, 24934, 25011, 25133, 25710,
- 25712, 25750, 25760, 25733, 25751, 25756, 25743, 25739, 25738, 25740,
- 25763, 25759, 25704, 25777, 25752, 25974, 25978, 25977, 25979,
- {f: 2, c: 26034}, 26293, 26288, 26281, 26290, 26295, 26282, 26287, 27136,
- 27142, 27159, 27109, 27128, 27157, 27121, 27108, 27168, 27135, 27116,
- 27106, 27163, 27165, 27134, 27175, 27122, 27118, 27156, 27127, 27111,
- 27200, 27144, 27110, 27131, 27149, 27132, 27115, 27145, 27140, 27160,
- 27173, 27151, 27126, 27174, 27143, 27124, 27158, 27473, 27557, 27555,
- 27554, 27558, 27649, 27648, 27647, 27650, 28481, 28454, 28542, 28551,
- 28614, 28562, 28557, 28553, 28556, 28514, 28495, 28549, 28506, 28566,
- 28534, 28524, 28546, 28501, 28530, 28498, 28496, 28503, 28564, 28563,
- 28509, 28416, 28513, 28523, 28541, 28519, 28560, 28499, 28555, 28521,
- 28543, 28565, 28515, 28535, 28522, 28539, 29106, 29103, 29083, 29104,
- 29088, 29082, 29097, 29109, 29085, 29093, 29086, 29092, 29089, 29098,
- 29084, 29095, 29107, 29336, 29338, 29528, 29522, {f: 3, c: 29534}, 29533,
- 29531, 29537, 29530, 29529, 29538, 29831, {f: 2, c: 29833}, 29830, 29825,
- 29821, 29829, 29832, 29820, [29817, 58868], 29960, 29959, 30078, 30245,
- 30238, 30233, 30237, 30236, 30243, 30234, 30248, 30235, {f: 3, c: 30364},
- 30363, 30605, 30607, 30601, 30600, 30925, 30907, 30927, 30924, 30929,
- 30926, 30932, 30920, {f: 2, c: 30915}, 30921, 31130, 31137, 31136, 31132,
- 31138, [31131, 59175], 27510, 31289, 31410, 31412, 31411, 31671, 31691,
- 31678, 31660, 31694, 31663, 31673, 31690, 31669, 31941, 31944, 31948,
- 31947, 32247, 32219, 32234, 32231, 32215, 32225, 32259, 32250, 32230,
- 32246, 32241, 32240, 32238, 32223, 32630, 32684, 32688, 32685, 32749,
- 32747, 32746, 32748, 32742, 32744, 32868, 32871, 33187, 33183, 33182,
- 33173, 33186, 33177, 33175, 33302, 33359, 33363, 33362, 33360, 33358,
- 33361, 34084, 34107, 34063, 34048, 34089, 34062, 34057, 34061, 34079,
- 34058, 34087, 34076, 34043, 34091, 34042, 34056, 34060, 34036, 34090,
- 34034, 34069, 34039, 34027, 34035, 34044, 34066, 34026, 34025, 34070,
- 34046, 34088, 34077, 34094, 34050, 34045, 34078, 34038, 34097, 34086,
- {f: 2, c: 34023}, 34032, 34031, 34041, 34072, 34080, 34096, 34059, 34073,
- 34095, 34402, 34646, {f: 2, c: 34659}, 34679, 34785, 34675, 34648, 34644,
- 34651, 34642, 34657, 34650, 34641, 34654, 34669, 34666, 34640, 34638,
- 34655, 34653, 34671, 34668, 34682, 34670, 34652, 34661, 34639, 34683,
- 34677, 34658, 34663, 34665, 34906, 35077, 35084, 35092, 35083,
- {f: 3, c: 35095}, 35078, 35094, 35089, 35086, 35081, 35234, 35236, 35235,
- 35309, 35312, 35308, 35535, 35526, 35512, 35539, 35537, {f: 2, c: 35540},
- 35515, 35543, 35518, 35520, 35525, 35544, 35523, 35514, 35517, 35545,
- 35902, 35917, 35983, 36069, 36063, 36057, 36072, 36058, 36061, 36071,
- 36256, 36252, 36257, 36251, 36384, 36387, 36389, 36388, 36398, 36373,
- 36379, 36374, 36369, 36377, {f: 2, c: 36390}, 36372, 36370, 36376, 36371,
- 36380, 36375, 36378, 36652, 36644, 36632, 36634, 36640, 36643,
- {f: 2, c: 36630}, 36979, 36976, 36975, 36967, 36971, 37167, 37163,
- {f: 2, c: 37161}, 37170, 37158, 37166, {f: 2, c: 37253}, 37258,
- {f: 2, c: 37249}, 37252, 37248, 37584, {f: 2, c: 37571}, 37568, 37593,
- 37558, 37583, 37617, 37599, 37592, 37609, 37591, 37597, 37580, 37615,
- 37570, 37608, 37578, 37576, 37582, 37606, 37581, 37589, 37577, 37600,
- 37598, 37607, 37585, 37587, 37557, 37601, 37669, 37574, 37556, 38268,
- 38316, 38315, 38318, 38320, 38564, 38562, 38611, 38661, 38664, 38658,
- 38746, 38794, 38798, 38792, 38864, 38863, 38942, 38941, 38950, 38953,
- 38952, 38944, 38939, 38951, 39090, 39176, 39162, 39185, 39188,
- {f: 2, c: 39190}, 39189, 39388, 39373, 39375, {f: 2, c: 39379}, 39374,
- 39369, [39382, 60270], 39384, 39371, 39383, 39372, 39603, 39660, 39659,
- 39667, 39666, 39665, 39750, 39747, 39783, 39796, 39793, 39782, 39798,
- 39797, 39792, 39784, 39780, 39788, 40188, 40186, 40189, 40191, 40183,
- 40199, 40192, 40185, 40187, 40200, 40197, 40196, 40579, 40659,
- {f: 2, c: 40719}, 20764, 20755, 20759, 20762, 20753, 20958, 21300, 21473,
- 22128, 22112, 22126, 22131, 22118, 22115, 22125, 22130, 22110, 22135,
- 22300, 22299, 22728, 22717, 22729, 22719, 22714, 22722, 22716, 22726,
- 23319, 23321, 23323, 23329, 23316, 23315, 23312, 23318, [23336, 59539],
- 23322, 23328, 23326, 23535, 23980, 23985, 23977, 23975, 23989, 23984,
- 23982, 23978, 23976, 23986, 23981, 23983, 23988, {f: 2, c: 24167}, 24166,
- 24175, 24297, 24295, 24294, 24296, 24293, 24395, 24508, 24507, 24989,
- 25000, 24982, 25029, 25012, 25030, 25025, 25036, 25018, 25023, 25016,
- 24972, 25815, 25814, 25808, 25807, 25801, 25789, 25737, 25795, 25819,
- 25843, 25817, 25907, 25983, 25980, 26018, 26312, 26302, 26304,
- {f: 2, c: 26314}, 26319, 26301, 26299, 26298, 26316, 26403, 27188, 27238,
- 27209, 27239, 27186, 27240, 27198, 27229, 27245, 27254, 27227, 27217,
- 27176, 27226, 27195, 27199, 27201, 27242, 27236, 27216, 27215, 27220,
- 27247, 27241, 27232, 27196, 27230, 27222, 27221, {f: 2, c: 27213}, 27206,
- 27477, 27476, 27478, 27559, {f: 2, c: 27562}, 27592, 27591, 27652, 27651,
- 27654, 28589, 28619, 28579, 28615, 28604, 28622, 28616, 28510, 28612,
- 28605, 28574, 28618, 28584, 28676, 28581, 28590, 28602, 28588, 28586,
- 28623, 28607, 28600, 28578, 28617, 28587, 28621, 28591, 28594, 28592,
- 29125, 29122, 29119, 29112, 29142, {f: 2, c: 29120}, 29131, 29140, 29130,
- 29127, 29135, 29117, 29144, 29116, 29126, {f: 2, c: 29146},
- {f: 2, c: 29341}, 29545, {f: 2, c: 29542}, 29548, 29541, 29547, 29546,
- 29823, 29850, 29856, 29844, 29842, 29845, 29857, 29963, 30080, 30255,
- 30253, 30257, 30269, 30259, 30268, 30261, 30258, 30256, 30395, 30438,
- 30618, 30621, 30625, 30620, 30619, {f: 2, c: 30626}, 30613, 30617, 30615,
- 30941, 30953, 30949, 30954, 30942, 30947, 30939, {f: 2, c: 30945}, 30957,
- {f: 2, c: 30943}, 31140, 31300, 31304, 31303, 31414, 31416, 31413, 31409,
- 31415, 31710, 31715, 31719, 31709, 31701, 31717, 31706, 31720, 31737,
- 31700, 31722, 31714, 31708, 31723, 31704, 31711, 31954, 31956, 31959,
- {f: 2, c: 31952}, 32274, 32289, 32279, 32268, {f: 2, c: 32287}, 32275,
- 32270, 32284, 32277, 32282, 32290, 32267, 32271, 32278, 32269, 32276,
- 32293, 32292, 32579, {f: 2, c: 32635}, 32634, 32689, 32751, 32810, 32809,
- 32876, 33201, 33190, 33198, 33209, 33205, 33195, 33200, 33196, 33204,
- 33202, 33207, 33191, 33266, {f: 3, c: 33365}, 34134, 34117, 34155, 34125,
- 34131, 34145, 34136, 34112, 34118, 34148, 34113, 34146, 34116, 34129,
- 34119, 34147, 34110, 34139, 34161, 34126, 34158, 34165, 34133, 34151,
- 34144, 34188, 34150, 34141, 34132, 34149, 34156, 34403, 34405, 34404,
- 34724, 34715, 34703, 34711, 34707, 34706, 34696, 34689, 34710, 34712,
- 34681, 34695, 34723, 34693, {f: 2, c: 34704}, 34717, 34692, 34708, 34716,
- 34714, 34697, 35102, 35110, 35120, {f: 2, c: 35117}, 35111, 35121, 35106,
- 35113, 35107, 35119, 35116, 35103, 35313, 35552, 35554, 35570,
- {f: 2, c: 35572}, 35549, 35604, 35556, 35551, 35568, 35528, 35550, 35553,
- 35560, 35583, 35567, 35579, {f: 2, c: 35985}, 35984, 36085, 36078, 36081,
- 36080, 36083, 36204, 36206, 36261, 36263, 36403, 36414, 36408, 36416,
- 36421, 36406, {f: 2, c: 36412}, 36417, 36400, 36415, 36541, [36662, 60329],
- 36654, 36661, 36658, 36665, 36663, 36660, 36982, 36985, 36987, 36998,
- 37114, 37171, {f: 2, c: 37173}, 37267, {f: 2, c: 37264}, 37261, 37263,
- 37671, 37662, 37640, 37663, 37638, 37647, 37754, 37688, 37692, 37659,
- 37667, 37650, 37633, 37702, 37677, 37646, 37645, 37579, 37661, 37626,
- 37651, 37625, 37623, 37684, 37634, 37668, 37631, 37673, 37689, 37685,
- 37674, 37652, 37644, 37643, 37630, 37641, 37632, 37627, 37654, 38332,
- 38349, 38334, {f: 2, c: 38329}, 38326, 38335, 38325, 38333, 38569, 38612,
- 38667, 38674, 38672, 38809, 38807, 38804, 38896, 38904, 38965, 38959,
- 38962, 39204, 39199, 39207, 39209, 39326, 39406, 39404, 39397, 39396,
- 39408, 39395, 39402, 39401, 39399, 39609, 39615, 39604, 39611, 39670,
- 39674, 39673, 39671, 39731, 39808, 39813, 39815, 39804, 39806, 39803,
- 39810, 39827, 39826, 39824, 39802, 39829, 39805, 39816, 40229, 40215,
- 40224, 40222, 40212, 40233, 40221, 40216, 40226, 40208, 40217, 40223,
- 40584, {f: 2, c: 40582}, 40622, 40621, {f: 2, c: 40661}, 40698, 40722,
- 40765, 20774, 20773, 20770, 20772, 20768, 20777, 21236, 22163,
- {f: 2, c: 22156}, 22150, 22148, 22147, 22142, 22146, 22143, 22145, 22742,
- 22740, 22735, 22738, 23341, 23333, 23346, 23331, 23340, 23335, 23334,
- 23343, 23342, 23419, {f: 2, c: 23537}, 23991, 24172, 24170, 24510, 25027,
- 25013, 25020, 25063, 25056, 25061, 25060, 25064, 25054, 25839, 25833,
- 25827, 25835, 25828, 25832, 25985, 25984, 26038, 26074, 26322, 27277,
- 27286, 27265, 27301, 27273, 27295, 27291, 27297, 27294, 27271, 27283,
- 27278, 27285, 27267, 27304, 27300, 27281, 27263, 27302, 27290, 27269,
- 27276, 27282, 27483, 27565, 27657, 28620, 28585, 28660, 28628, 28643,
- 28636, 28653, 28647, 28646, 28638, 28658, 28637, 28642, 28648, 29153,
- 29169, 29160, 29170, 29156, 29168, 29154, 29555, {f: 2, c: 29550}, 29847,
- 29874, 29867, 29840, 29866, 29869, 29873, 29861, 29871, {f: 3, c: 29968},
- 29967, 30084, 30275, {f: 2, c: 30280}, 30279, 30372, 30441, 30645, 30635,
- 30642, 30647, 30646, 30644, 30641, 30632, 30704, 30963, 30973, 30978,
- {f: 2, c: 30971}, 30975, 30962, 30981, 30969, 30974, 30980, 31147, 31144,
- 31324, 31323, 31318, 31320, 31316, 31322, 31422, {f: 2, c: 31424}, 31749,
- 31759, 31730, 31744, 31743, 31739, 31758, 31732, 31755, 31731, 31746,
- 31753, 31747, 31745, 31736, 31741, [31750, 58176], {f: 2, c: 31728}, 31760,
- 31754, 31976, 32301, 32316, 32322, 32307, 38984, 32312, 32298, 32329,
- 32320, 32327, 32297, 32332, 32304, 32315, 32310, 32324, 32314, 32581,
- 32639, 32638, 32637, 32756, 32754, 32812, 33211, 33220, 33228, 33226,
- 33221, 33223, 33212, 33257, 33371, 33370, 33372, 34179, 34176, 34191,
- 34215, 34197, 34208, 34187, 34211, 34171, 34212, 34202, 34206, 34167,
- 34172, 34185, 34209, 34170, 34168, 34135, 34190, 34198, 34182, 34189,
- 34201, 34205, 34177, 34210, 34178, 34184, 34181, 34169, 34166, 34200,
- 34192, 34207, 34408, 34750, 34730, 34733, 34757, 34736, 34732, 34745,
- 34741, 34748, 34734, 34761, 34755, 34754, 34764, 34743, 34735, 34756,
- 34762, 34740, 34742, 34751, 34744, 34749, 34782, 34738, 35125, 35123,
- 35132, 35134, 35137, 35154, 35127, 35138, 35245, 35247, 35246,
- {f: 2, c: 35314}, 35614, 35608, 35606, 35601, 35589, 35595, 35618, 35599,
- 35602, 35605, 35591, 35597, 35592, 35590, 35612, 35603, 35610, 35919,
- 35952, 35954, 35953, 35951, 35989, 35988, 36089, 36207, 36430, 36429,
- 36435, 36432, 36428, 36423, 36675, 36672, 36997, 36990, 37176, 37274,
- 37282, 37275, 37273, 37279, 37281, 37277, 37280, 37793, 37763, 37807,
- 37732, 37718, 37703, 37756, 37720, 37724, 37750, 37705, {f: 2, c: 37712},
- 37728, 37741, 37775, 37708, 37738, 37753, 37719, 37717, 37714, 37711,
- 37745, 37751, 37755, 37729, 37726, 37731, 37735, 37710, 37721, 38343,
- 38336, 38345, 38339, 38341, 38327, 38574, 38576, 38572, 38688, 38687,
- 38680, 38685, 38681, 38810, 38817, 38812, 38814, 38813, 38869, 38868,
- 38897, 38977, 38980, 38986, 38985, 38981, 38979, 39205, {f: 2, c: 39211},
- 39210, 39219, 39218, 39215, 39213, 39217, 39216, 39320, 39331, 39329,
- 39426, 39418, 39412, 39415, 39417, 39416, 39414, 39419, {f: 2, c: 39421},
- 39420, 39427, 39614, 39678, 39677, 39681, 39676, 39752, 39834, 39848,
- 39838, 39835, 39846, 39841, 39845, 39844, 39814, 39842, 39840, 39855,
- 40243, 40257, 40295, 40246, {f: 2, c: 40238}, 40241, 40248, 40240, 40261,
- {f: 2, c: 40258}, 40254, 40247, 40256, 40253, 32757, 40237, 40586, 40585,
- 40589, 40624, 40648, 40666, 40699, 40703, 40740, 40739, 40738, 40788,
- [12245, 40864], 20785, {f: 2, c: 20781}, 22168, 22172, 22167, 22170, 22173,
- 22169, 22896, 23356, {f: 2, c: 23657}, 24000, {f: 2, c: 24173}, 25048,
- 25055, {f: 2, c: 25069}, 25073, 25066, 25072, 25067, 25046, 25065, 25855,
- 25860, 25853, 25848, 25857, 25859, 25852, 26004, 26075, {f: 2, c: 26330},
- 26328, 27333, 27321, 27325, 27361, 27334, 27322, {f: 2, c: 27318}, 27335,
- 27316, 27309, 27486, 27593, 27659, 28679, {f: 2, c: 28684}, 28673, 28677,
- 28692, 28686, {f: 2, c: 28671}, 28667, 28710, 28668, 28663, 28682,
- [29185, 60224], 29183, 29177, 29187, 29181, 29558, 29880, 29888, 29877,
- 29889, 29886, 29878, 29883, 29890, 29972, 29971, 30300, 30308, 30297,
- 30288, 30291, 30295, 30298, 30374, 30397, 30444, 30658, 30650, 30988,
- {f: 2, c: 30995}, 30985, 30992, 30994, 30993, 31149, 31148, 31327, 31772,
- 31785, 31769, 31776, 31775, 31789, 31773, 31782, 31784, 31778, 31781,
- 31792, 32348, 32336, 32342, 32355, 32344, 32354, 32351, 32337, 32352,
- 32343, 32339, 32693, 32691, {f: 2, c: 32759}, 32885, {f: 2, c: 33233},
- 33232, 33375, 33374, 34228, 34246, 34240, 34243, 34242, 34227, 34229,
- 34237, 34247, 34244, 34239, 34251, 34254, 34248, 34245, 34225, 34230,
- 34258, 34340, 34232, 34231, 34238, 34409, 34791, 34790, 34786, 34779,
- 34795, 34794, 34789, 34783, 34803, 34788, 34772, 34780, 34771, 34797,
- 34776, 34787, 34775, 34777, 34817, 34804, 34792, 34781, 35155, 35147,
- 35151, 35148, 35142, {f: 2, c: 35152}, 35145, 35626, 35623, 35619, 35635,
- 35632, 35637, 35655, 35631, 35644, 35646, 35633, 35621, 35639, 35622,
- 35638, 35630, 35620, 35643, 35645, 35642, 35906, 35957, 35993, 35992,
- 35991, 36094, 36100, 36098, 36096, 36444, 36450, 36448, 36439, 36438,
- 36446, 36453, 36455, 36443, 36442, 36449, 36445, 36457, 36436,
- {f: 3, c: 36678}, 36683, 37160, {f: 2, c: 37178}, 37182, 37288, 37285,
- 37287, 37295, 37290, 37813, 37772, 37778, 37815, 37787, 37789, 37769,
- 37799, 37774, 37802, 37790, 37798, 37781, 37768, 37785, 37791, 37760,
- 37773, 37809, 37777, 37810, 37796, 37800, 37812, 37795, {f: 2, c: 38354},
- 38353, 38579, 38615, 38618, 24002, 38623, 38616, 38621, 38691, 38690,
- 38693, 38828, 38830, 38824, 38827, 38820, 38826, 38818, 38821, 38871,
- 38873, 38870, 38872, 38906, {f: 3, c: 38992}, 39096, 39233, 39228, 39226,
- 39439, 39435, 39433, 39437, 39428, 39441, 39434, 39429, 39431, 39430,
- 39616, 39644, 39688, {f: 2, c: 39684}, 39721, 39733, 39754, 39756, 39755,
- 39879, 39878, 39875, 39871, 39873, 39861, 39864, 39891, 39862, 39876,
- 39865, 39869, 40284, 40275, 40271, 40266, 40283, 40267, 40281, 40278,
- 40268, 40279, 40274, 40276, 40287, 40280, 40282, 40590, 40588, 40671,
- 40705, 40704, [40726, 58693], 40741, 40747, 40746, 40745, 40744, 40780,
- 40789, {f: 2, c: 20788}, 21142, 21239, 21428, 22187, 22189,
- {f: 2, c: 22182}, 22186, 22188, 22746, 22749, 22747, 22802,
- {f: 3, c: 23357}, 24003, 24176, 24511, 25083, 25863, 25872, 25869, 25865,
- 25868, 25870, 25988, 26078, 26077, 26334, 27367, 27360, 27340, 27345,
- 27353, 27339, 27359, 27356, 27344, 27371, 27343, 27341, 27358, 27488,
- 27568, 27660, 28697, 28711, 28704, 28694, 28715, {f: 3, c: 28705}, 28713,
- 28695, 28708, 28700, 29196, 29194, 29191, 29186, 29189, {f: 2, c: 29349},
- 29348, 29347, 29345, 29899, 29893, 29879, 29891, 29974, 30304,
- {f: 2, c: 30665}, 30660, 30705, 31005, 31003, 31009, 31004, 30999, 31006,
- 31152, {f: 2, c: 31335}, 31795, 31804, 31801, 31788, 31803, 31980, 31978,
- 32374, 32373, 32376, 32368, 32375, 32367, 32378, 32370, 32372, 32360,
- 32587, 32586, 32643, 32646, 32695, {f: 2, c: 32765}, 32888, 33239, 33237,
- 33291, 33380, 33377, 33379, 34283, 34289, 34285, 34265, 34273, 34280,
- 34266, 34263, 34284, 34290, 34296, 34264, 34271, 34275, 34268, 34257,
- 34288, 34278, 34287, 34270, 34274, 34816, 34810, 34819, {f: 2, c: 34806},
- 34825, 34828, 34827, 34822, 34812, 34824, 34815, 34826, 34818, 35170,
- {f: 2, c: 35162}, 35159, 35169, 35164, 35160, 35165, 35161, 35208, 35255,
- 35254, 35318, 35664, 35656, 35658, 35648, 35667, 35670, 35668, 35659,
- 35669, 35665, 35650, 35666, 35671, 35907, 35959, 35958, 35994,
- {f: 2, c: 36102}, 36105, 36268, 36266, 36269, 36267, 36461, 36472, 36467,
- 36458, 36463, 36475, 36546, 36690, 36689, {f: 2, c: 36687}, 36691, 36788,
- 37184, 37183, 37296, 37293, 37854, 37831, 37839, 37826, 37850, 37840,
- 37881, 37868, 37836, 37849, 37801, 37862, 37834, 37844, 37870, 37859,
- 37845, 37828, 37838, 37824, 37842, 37797, 37863, 38269, {f: 2, c: 38362},
- 38625, 38697, {f: 2, c: 38699}, 38696, 38694, 38835, 38839, 38838,
- {f: 3, c: 38877}, 39004, 39001, 39005, 38999, 39103, 39101, 39099, 39102,
- 39240, 39239, 39235, {f: 2, c: 39334}, 39450, 39445, 39461, 39453, 39460,
- 39451, 39458, 39456, 39463, 39459, 39454, 39452, 39444, 39618, 39691,
- 39690, 39694, 39692, 39735, {f: 2, c: 39914}, 39904, 39902, 39908, 39910,
- 39906, 39920, 39892, 39895, 39916, 39900, 39897, 39909, 39893, 39905,
- 39898, 40311, 40321, 40330, 40324, 40328, 40305, 40320, 40312, 40326,
- {f: 2, c: 40331}, 40317, 40299, {f: 2, c: 40308}, 40304, 40297, 40325,
- 40307, 40315, 40322, 40303, 40313, 40319, 40327, 40296, 40596, 40593,
- 40640, 40700, 40749, {f: 2, c: 40768}, 40781, {f: 3, c: 40790}, 21303,
- 22194, 22197, 22195, 22755, 23365, {f: 2, c: 24006}, {f: 2, c: 24302},
- {f: 2, c: 24512}, 25081, 25879, 25878, 25877, 25875, 26079, 26344,
- {f: 2, c: 26339}, 27379, 27376, 27370, 27368, 27385, 27377,
- {f: 2, c: 27374}, 28732, 28725, 28719, 28727, 28724, 28721, 28738, 28728,
- 28735, 28730, 28729, 28714, 28736, 28731, 28723, 28737, {f: 2, c: 29203},
- 29352, 29565, 29564, 29882, 30379, 30378, 30398, 30445, 30668,
- {f: 2, c: 30670}, 30669, 30706, 31013, 31011, {f: 2, c: 31015}, 31012,
- 31017, 31154, 31342, {f: 2, c: 31340}, 31479, 31817, 31816, 31818, 31815,
- 31813, 31982, 32379, 32382, 32385, 32384, 32698, 32767, 32889, 33243,
- 33241, {f: 2, c: 33384}, 34338, 34303, 34305, 34302, 34331, 34304, 34294,
- 34308, 34313, 34309, 34316, 34301, 34841, {f: 2, c: 34832}, 34839, 34835,
- 34838, 35171, 35174, 35257, 35319, 35680, 35690, 35677, 35688, 35683,
- 35685, 35687, 35693, 36270, 36486, 36488, 36484, 36697, {f: 2, c: 36694},
- 36693, 36696, 36698, 37005, 37187, 37185, 37303, 37301, {f: 2, c: 37298},
- 37899, 37907, 37883, 37920, 37903, 37908, 37886, 37909, 37904, 37928,
- 37913, 37901, 37877, 37888, 37879, 37895, 37902, 37910, 37906, 37882,
- 37897, 37880, 37948, 37898, 37887, 37884, 37900, 37878, 37905, 37894,
- 38366, 38368, 38367, {f: 2, c: 38702}, 38841, 38843, {f: 2, c: 38909},
- 39008, {f: 2, c: 39010}, 39007, {f: 2, c: 39105}, 39248, 39246, 39257,
- 39244, 39243, 39251, 39474, 39476, 39473, 39468, 39466, 39478, 39465,
- 39470, 39480, 39469, 39623, 39626, 39622, 39696, 39698, 39697, 39947,
- 39944, 39927, 39941, 39954, 39928, 40000, 39943, 39950, 39942, 39959,
- 39956, 39945, 40351, 40345, 40356, 40349, 40338, 40344, 40336, 40347,
- 40352, 40340, 40348, 40362, 40343, 40353, 40346, 40354, 40360, 40350,
- 40355, 40383, 40361, 40342, {f: 2, c: 40358}, 40601, 40603, 40602, 40677,
- 40676, 40679, 40678, 40752, 40750, 40795, 40800, 40798, 40797, 40793,
- 40849, 20794, 20793, 21144, 21143, 22211, {f: 2, c: 22205}, 23368, 23367,
- 24011, 24015, 24305, 25085, 25883, 27394, 27388, 27395, 27384, 27392,
- {f: 2, c: 28739}, 28746, {f: 2, c: 28744}, {f: 2, c: 28741}, 29213, 29210,
- 29209, 29566, 29975, 30314, 30672, 31021, 31025, 31023, 31828, 31827,
- 31986, 32394, [32391, 60229], 32392, 32395, 32390, 32397, 32589, 32699,
- 32816, 33245, 34328, 34346, 34342, 34335, 34339, 34332, 34329, 34343,
- 34350, 34337, 34336, 34345, 34334, 34341, 34857, 34845, 34843, 34848,
- 34852, 34844, 34859, 34890, 35181, 35177, 35182, 35179, 35322, 35705,
- 35704, 35653, {f: 2, c: 35706}, 36112, 36116, 36271, 36494, 36492, 36702,
- 36699, 36701, 37190, {f: 2, c: 37188}, 37305, 37951, 37947, 37942, 37929,
- 37949, 37936, 37945, 37930, 37943, 37932, 37952, 37937, 38373, 38372,
- 38371, 38709, 38714, 38847, 38881, 39012, 39113, 39110, 39104, 39256,
- 39254, 39481, 39485, 39494, 39492, 39490, 39489, 39482, 39487, 39629,
- 39701, {f: 2, c: 39703}, 39702, 39738, 39762, 39979, 39965, 39964, 39980,
- 39971, {f: 2, c: 39976}, 39972, 39969, 40375, 40374, 40380, 40385, 40391,
- 40394, 40399, 40382, 40389, 40387, 40379, 40373, 40398, {f: 2, c: 40377},
- 40364, 40392, 40369, 40365, 40396, 40371, 40397, 40370, 40570, 40604,
- 40683, 40686, 40685, 40731, 40728, 40730, 40753, 40782, 40805, 40804,
- 40850, 20153, 22214, 22213, 22219, 22897, {f: 2, c: 23371}, 24021, 24017,
- 24306, 25889, 25888, 25894, 25890, 27403, {f: 2, c: 27400}, 27661,
- {f: 3, c: 28757}, 28754, {f: 2, c: 29214}, 29353, 29567, 29912, 29909,
- 29913, 29911, 30317, 30381, 31029, 31156, {f: 2, c: 31344}, 31831, 31836,
- 31833, 31835, 31834, 31988, 31985, 32401, 32591, 32647, 33246, 33387,
- {f: 2, c: 34356}, 34355, 34348, 34354, 34358, 34860, 34856, 34854, 34858,
- 34853, 35185, 35263, 35262, 35323, 35710, 35716, 35714, 35718, 35717,
- 35711, 36117, 36501, 36500, 36506, 36498, 36496, {f: 2, c: 36502}, 36704,
- 36706, 37191, 37964, 37968, {f: 2, c: 37962}, 37967, 37959, 37957,
- {f: 2, c: 37960}, 37958, 38719, 38883, 39018, 39017, 39115, 39252, 39259,
- 39502, {f: 2, c: 39507}, 39500, 39503, 39496, 39498, 39497, 39506, 39504,
- 39632, 39705, 39723, 39739, 39766, 39765, 40006, 40008, 39999, 40004,
- 39993, 39987, 40001, 39996, 39991, 39988, 39986, 39997, 39990, 40411,
- 40402, 40414, 40410, 40395, 40400, 40412, 40401, 40415, 40425, 40409,
- 40408, 40406, 40437, 40405, 40413, 40630, 40688, 40757, 40755, 40754,
- 40770, 40811, 40853, 40866, 20797, 21145, 22760, 22759, 22898, 23373,
- 24024, 34863, 24399, 25089, {f: 2, c: 25091}, 25897, 25893, 26006, 26347,
- {f: 2, c: 27409}, 27407, 27594, 28763, 28762, 29218, 29570, 29569, 29571,
- 30320, 30676, 31847, 31846, 32405, 33388, 34362, 34368, 34361, 34364,
- 34353, 34363, 34366, 34864, 34866, 34862, 34867, 35190, 35188, 35187,
- 35326, 35724, 35726, 35723, 35720, 35909, 36121, 36504, 36708, 36707,
- 37308, 37986, 37973, 37981, 37975, 37982, {f: 2, c: 38852}, 38912, 39510,
- 39513, {f: 3, c: 39710}, 40018, 40024, 40016, 40010, 40013, 40011, 40021,
- 40025, 40012, 40014, 40443, 40439, 40431, 40419, 40427, 40440, 40420,
- 40438, 40417, 40430, 40422, 40434, [40432, 60370], 40418, 40428, 40436,
- 40435, 40424, 40429, 40642, 40656, {f: 2, c: 40690}, 40710, 40732, 40760,
- 40759, 40758, 40771, 40783, 40817, 40816, {f: 2, c: 40814}, 22227, 22221,
- 23374, 23661, 25901, {f: 2, c: 26349}, 27411, 28767, 28769, 28765, 28768,
- 29219, 29915, 29925, 30677, 31032, 31159, 31158, 31850, 32407, 32649,
- 33389, 34371, 34872, 34871, 34869, 34891, {f: 2, c: 35732},
- {f: 3, c: 36510}, 36509, 37310, 37309, 37314, 37995, {f: 2, c: 37992},
- 38629, 38726, 38723, 38727, 38855, 38885, 39518, 39637, 39769, 40035,
- 40039, 40038, 40034, 40030, 40032, 40450, 40446, 40455, 40451, 40454,
- 40453, {f: 2, c: 40448}, 40457, 40447, 40445, 40452, 40608, 40734, 40774,
- {f: 3, c: 40820}, 22228, 25902, 26040, {f: 2, c: 27416}, 27415, 27418,
- 28770, 29222, 29354, {f: 2, c: 30680}, 31033, 31849, 31851, 31990, 32410,
- 32408, 32411, 32409, {f: 2, c: 33248}, {f: 3, c: 34374}, {f: 2, c: 35193},
- 35196, 35195, 35327, {f: 2, c: 35736}, 36517, 36516, 36515, 37998, 37997,
- 37999, 38001, 38003, 38729, 39026, 39263, 40040, 40046, 40045, 40459,
- 40461, 40464, 40463, 40466, 40465, 40609, 40693, 40713, 40775, 40824,
- 40827, 40826, 40825, 22302, 28774, 31855, 34876, 36274, 36518, 37315,
- 38004, 38008, 38006, 38005, 39520, [39726, 60830], 40052, 40051, 40049,
- 40053, 40468, 40467, 40694, 40714, 40868, 28776, 28773, 31991, 34410,
- 34878, 34877, 34879, 35742, 35996, 36521, 36553, 38731, {f: 2, c: 39027},
- 39116, 39265, 39339, 39524, {f: 2, c: 39526}, 39716, 40469, 40471, 40776,
- 25095, 27422, 29223, 34380, 36520, 38018, {f: 2, c: 38016}, 39529, 39528,
- 40473, 34379, 35743, 38019, 40057, 40631, 30325, 39531, 40058, 40477,
- {f: 2, c: 28777}, 29225, 40612, 40830, 40777, 40856, {s: 97}, 65075, 0,
- 65076, 65103, [168, 776, 63208], [710, 63209, 65342], [12541, 63210],
- [12542, 63211], [12445, 63212], [12446, 63213], 0, [12293, 63216],
- [12294, 63217], [12295, 63218], [12540, 63219], [63220, 65339],
- [63221, 65341], [10045, 63222], [12353, 63223], [12354, 63224],
- [12355, 63225], [12356, 63226], [12357, 63227], [12358, 63228],
- [12359, 63229], [12360, 63230], [12361, 63231], [12362, 63232],
- [12363, 63233], [12364, 63234], [12365, 63235], [12366, 63236],
- [12367, 63237], [12368, 63238], [12369, 63239], [12370, 63240],
- [12371, 63241], [12372, 63242], [12373, 63243], [12374, 63244],
- [12375, 63245], [12376, 63246], [12377, 63247], [12378, 63248],
- [12379, 63249], [12380, 63250], [12381, 63251], [12382, 63252],
- [12383, 63253], [12384, 63254], [12385, 63255], [12386, 63256],
- [12387, 63257], [12388, 63258], [12389, 63259], [12390, 63260],
- [12391, 63261], [12392, 63262], [12393, 63263], [12394, 63264],
- [12395, 63265], [12396, 63266], [12397, 63267], [12398, 63268],
- [12399, 63269], [12400, 63270], [12401, 63271], [12402, 63272],
- [12403, 63273], [12404, 63274], [12405, 63275], [12406, 63276],
- [12407, 63277], [12408, 63278], [12409, 63279], [12410, 63280],
- [12411, 63281], [12412, 63282], [12413, 63283], [12414, 63284],
- [12415, 63285], [12416, 63286], [12417, 63287], [12418, 63288],
- [12419, 63289], [12420, 63290], [12421, 63291], [12422, 63292],
- [12423, 63293], [12424, 63294], [12425, 63295], [12426, 63296],
- [12427, 63297], [12428, 63298], [12429, 63299], [12430, 63300],
- [12431, 63301], [12432, 63302], [12433, 63303], [12434, 63304],
- [12435, 63305], [12449, 63306], [12450, 63307], [12451, 63308],
- [12452, 63309], [12453, 63310], [12454, 63311], [12455, 63312],
- [12456, 63313], [12457, 63314], [12458, 63315], [12459, 63316],
- [12460, 63317], [12461, 63318], [12462, 63319], [12463, 63320],
- [12464, 63321], [12465, 63322], [12466, 63323], [12467, 63324],
- [12468, 63325], [12469, 63326], [12470, 63327], [12471, 63328],
- [12472, 63329], [12473, 63330], [12474, 63331], [12475, 63332],
- [12476, 63333], [12477, 63334], [12478, 63335], [12479, 63336],
- [12480, 63337], [12481, 63338], [12482, 63339], [12483, 63340],
- [12484, 63341], [12485, 63342], [12486, 63343], [12487, 63344],
- [12488, 63345], [12489, 63346], [12490, 63347], [12491, 63348],
- [12492, 63349], [12493, 63350], [12494, 63351], [12495, 63352],
- [12496, 63353], [12497, 63354], [12498, 63355], [12499, 63356],
- [12500, 63357], [12501, 63358], [12502, 63359], [12503, 63360],
- [12504, 63361], [12505, 63362], [12506, 63363], [12507, 63364],
- [12508, 63365], [12509, 63366], [12510, 63367], [12511, 63368],
- [12512, 63369], [12513, 63370], [12514, 63371], [12515, 63372],
- [12516, 63373], [12517, 63374], [12518, 63375], [12519, 63376],
- [12520, 63377], [12521, 63378], [12522, 63379], [12523, 63380],
- [12524, 63381], [12525, 63382], [12526, 63383], [12527, 63384],
- [12528, 63385], [12529, 63386], [12530, 63387], [12531, 63388],
- [12532, 63389], [12533, 63390], [12534, 63391], [1040, 63392],
- [1041, 63393], [1042, 63394], [1043, 63395], [1044, 63396], [1045, 63397],
- [1025, 63398], [1046, 63399], [1047, 63400], [1048, 63401], [1049, 63402],
- [1050, 63403], [1051, 63404], [1052, 63405], [1053, 63406], [1054, 63407],
- [1055, 63408], [1056, 63409], [1057, 63410], [1058, 63411], [1059, 63412],
- [1060, 63413], [1061, 63414], [1062, 63415], [1063, 63416], [1064, 63417],
- [1065, 63418], [1066, 63419], [1067, 63420], [1068, 63421], [1069, 63422],
- [1070, 63423], [1071, 63424], [1072, 63425], [1073, 63426], [1074, 63427],
- [1075, 63428], [1076, 63429], [1077, 63430], [1105, 63431], [1078, 63432],
- [1079, 63433], [1080, 63434], [1081, 63435], [1082, 63436], [1083, 63437],
- [1084, 63438], [1085, 63439], [1086, 63440], [1087, 63441], [1088, 63442],
- [1089, 63443], [1090, 63444], [1091, 63445], [1092, 63446], [1093, 63447],
- [1094, 63448], [1095, 63449], [1096, 63450], [1097, 63451], [1098, 63452],
- [1099, 63453], [1100, 63454], [1101, 63455], [1102, 63456], [1103, 63457],
- [8679, 63458], [8632, 63459], [8633, 63460], [20033, 63461],
- [63462, 131276], [20058, 63463], [63464, 131210], [20994, 63465],
- [17553, 63466], 63467, [20872, 63468], [13853, 63469], [63470, 161287],
- {s: 40}, [172, 63511, 65506], [63512, 65508], [63513, 65287],
- [63514, 65282], [12849, 63515], [8470, 63516], [8481, 63517], 30849,
- [37561, 58501], 35023, 22715, 24658, 31911, 23290, 9556, 9574, 9559, 9568,
- 9580, 9571, 9562, 9577, 9565, 9554, 9572, 9557, {s: 3}, 9560, 9575, 9563,
- 9555, 9573, 9558, 9567, 9579, 9570, 9561, 9576, 9564, 9553, {s: 5}, 9619,
- {s: 26}, [58129, 147159], [22462, 58130], [58131, 159443], [28990, 58132],
- [58133, 153568], [27042, 58135], [58136, 166889], [23412, 58137],
- [31305, 58138], [58139, 153825], [58140, 169177], [31333, 58141],
- [31357, 58142], [58143, 154028], [31419, 58144], [31408, 58145],
- [31426, 58146], [31427, 58147], [29137, 58148], [58149, 156813],
- [16842, 58150], [31450, 58151], [31453, 58152], [31466, 58153],
- [16879, 58154], [21682, 58155], [58156, 154625], [31499, 58157],
- [31573, 58158], [31529, 58159], [58160, 152334], [58161, 154878],
- [31650, 58162], [31599, 58163], [33692, 58164], [58165, 154548],
- [58166, 158847], [31696, 58167], [33825, 58168], [31634, 58169], 0,
- [58171, 154912], 0, [33938, 58174], [31738, 58175], 0, [31797, 58177],
- [58178, 154817], [31812, 58179], [31875, 58180], [58181, 149634],
- [31910, 58182], [58184, 148856], [31945, 58185], [31943, 58186],
- [31974, 58187], 0, [31987, 58189], [31989, 58190], [32359, 58192],
- [17693, 58193], [58194, 159300], [32093, 58195], [58196, 159446],
- [32137, 58198], [32171, 58199], [28981, 58200], [32179, 58201], 32214,
- [58203, 147543], [58204, 155689], [32228, 58205], [15635, 58206],
- [32245, 58207], [58208, 137209], [32229, 58209], [58210, 164717], 0,
- [58212, 155937], [58213, 155994], [32366, 58214], 0, [17195, 58216],
- [37996, 58217], [32295, 58218], [32576, 58219], [32577, 58220],
- [32583, 58221], [31030, 58222], [58223, 156368], [39393, 58224],
- [32663, 58225], [58226, 156497], [32675, 58227], [58228, 136801],
- [58229, 131176], [17756, 58230], [58231, 145254], [58233, 164666],
- [32762, 58234], [58235, 156809], 0, [32776, 58237], [32797, 58238], 0,
- [32815, 58240], [58241, 172167], [58242, 158915], [32827, 58243],
- [32828, 58244], [32865, 58245], [58246, 141076], [18825, 58247],
- [58248, 157222], [58249, 146915], [58250, 157416], [26405, 58251],
- [32935, 58252], [58253, 166472], [33031, 58254], [33050, 58255],
- [22704, 58256], [58257, 141046], [27775, 58258], [58259, 156824],
- [25831, 58261], [58262, 136330], [33304, 58263], [58264, 137310],
- [27219, 58265], [58266, 150117], [58267, 150165], [17530, 58268],
- [33321, 58269], [58271, 158290], [58272, 146814], [20473, 58273],
- [58274, 136445], [34018, 58275], [33634, 58276], 0, [58278, 149927],
- [58279, 144688], [58280, 137075], [58281, 146936], [33450, 58282],
- [26907, 58283], [58284, 194964], [16859, 58285], [34123, 58286],
- [33488, 58287], [33562, 58288], [58289, 134678], [58290, 137140],
- [14017, 58291], [58292, 143741], [58293, 144730], [33403, 58294],
- [33506, 58295], [33560, 58296], [58297, 147083], [58298, 159139],
- [58299, 158469], [58300, 158615], [58301, 144846], [15807, 58302],
- [33565, 58303], [21996, 58304], [33669, 58305], [17675, 58306],
- [58307, 159141], [33708, 58308], 0, [33747, 58310], [58312, 159444],
- [27223, 58313], [34138, 58314], [13462, 58315], [58316, 159298],
- [33880, 58318], [58319, 154596], [33905, 58320], [15827, 58321],
- [17636, 58322], [27303, 58323], [33866, 58324], [31064, 58326], 0,
- [58328, 158614], [58329, 159351], [58330, 159299], [34014, 58331], 0,
- [33681, 58333], [17568, 58334], [33939, 58335], [34020, 58336],
- [58337, 154769], [16960, 58338], [58339, 154816], [17731, 58340],
- [34100, 58341], [23282, 58342], 0, [17703, 58344], [34163, 58345],
- [17686, 58346], [26559, 58347], [34326, 58348], [58349, 165413],
- [58350, 165435], [34241, 58351], [58352, 159880], [34306, 58353],
- [58354, 136578], [58355, 159949], [58356, 194994], [17770, 58357],
- [34344, 58358], [13896, 58359], [58360, 137378], [21495, 58361],
- [58362, 160666], [34430, 58363], 0, [58365, 172280], [34798, 58366],
- [58367, 142375], [34737, 58368], [34778, 58369], [34831, 58370, 60990],
- [22113, 58371], [34412, 58372], [26710, 58373], [17935, 58374],
- [34885, 58375], [34886, 58376], [58377, 161248], [58378, 146873],
- [58379, 161252], [34910, 58380], [34972, 58381], [18011, 58382],
- [34996, 58383], [34997, 58384], [35013, 58386], [58388, 161551],
- [35207, 58389], {s: 3}, [35239, 58393], [35260, 58394], [58395, 166437],
- [35303, 58396], [58397, 162084], [58398, 162493], [35484, 58399],
- [30611, 58400], [37374, 58401], [35472, 58402], [58403, 162393],
- [31465, 58404], [58405, 162618], [18195, 58407], [58408, 162616],
- [29052, 58409], [35596, 58410], [35615, 58411], [58412, 152624],
- [58413, 152933], [35647, 58414], 0, [35661, 58416], [35497, 58417],
- [58418, 150138], [35728, 58419], [35739, 58420], [35503, 58421],
- [58422, 136927], [17941, 58423], [34895, 58424], [35995, 58425],
- [58426, 163156], [58427, 163215], [58428, 195028], [14117, 58429],
- [58430, 163155], [36054, 58431], [58432, 163224], [58433, 163261],
- [36114, 58434], [36099, 58435], [58436, 137488], [36059, 58437],
- [28764, 58438], [36113, 58439], [16080, 58441], 0, [36265, 58443],
- [58444, 163842], [58445, 135188], [58446, 149898], [15228, 58447],
- [58448, 164284], [58449, 160012], [31463, 58450], [36525, 58451],
- [36534, 58452], [36547, 58453], [37588, 58454], [36633, 58455],
- [36653, 58456], [58457, 164709], [58458, 164882], [36773, 58459],
- [37635, 58460], [58461, 172703], [58462, 133712], [36787, 58463], 0,
- [58465, 166366], [58466, 165181], [58467, 146875], [24312, 58468],
- [58469, 143970], [36857, 58470], 0, [58474, 140069], [14720, 58475],
- [58476, 159447], [36919, 58477], [58478, 165180], [58479, 162494],
- [36961, 58480], [58481, 165228], [58482, 165387], [37032, 58483],
- [58484, 165651], [37060, 58485], [58486, 165606], [37038, 58487], 0,
- [37223, 58489], [37289, 58491], [37316, 58492], [31916, 58493],
- [58494, 166195], [58495, 138889], [37390, 58496], [27807, 58497],
- [37441, 58498], [37474, 58499], [58500, 153017], [58502, 166598],
- [58503, 146587], [58504, 166668], [58505, 153051], [58506, 134449],
- [37676, 58507], [37739, 58508], [58509, 166625], [58510, 166891],
- [23235, 58512], [58513, 166626], [58514, 166629], [18789, 58515],
- [37444, 58516], [58517, 166892], [58518, 166969], [58519, 166911],
- [37747, 58520], [37979, 58521], [36540, 58522], [38277, 58523],
- [38310, 58524], [37926, 58525], [38304, 58526], [28662, 58527],
- [17081, 58528], [58530, 165592], [58531, 135804], [58532, 146990],
- [18911, 58533], [27676, 58534], [38523, 58535], [38550, 58536],
- [16748, 58537], [38563, 58538], [58539, 159445], [25050, 58540], 58541,
- [30965, 58542], [58543, 166624], [38589, 58544], [21452, 58545],
- [18849, 58546], [58547, 158904], [58548, 131700], [58549, 156688],
- [58550, 168111], [58551, 168165], [58552, 150225], [58553, 137493],
- [58554, 144138], [38705, 58555], [34370, 58556], [38710, 58557],
- [18959, 58558], [17725, 58559], [17797, 58560], [58561, 150249],
- [28789, 58562], [23361, 58563], [38683, 58564], 0, [58566, 168405],
- [38743, 58567], [23370, 58568], [58569, 168427], [38751, 58570],
- [37925, 58571], [20688, 58572], [58573, 143543], [58574, 143548],
- [38793, 58575], [38815, 58576], [38833, 58577], [38846, 58578],
- [38848, 58579], [38866, 58580], [38880, 58581], [58582, 152684],
- [38894, 58583], [29724, 58584], [58585, 169011], 0, [38901, 58587],
- [58588, 168989], [58589, 162170], [19153, 58590], [38964, 58591],
- [38963, 58592], [38987, 58593], [39014, 58594], [15118, 58595],
- [58596, 160117], [15697, 58597], [58598, 132656], [58599, 147804],
- [58600, 153350], [39114, 58601], [39095, 58602], [39112, 58603],
- [39111, 58604], [19199, 58605], [58606, 159015], [58607, 136915],
- [21936, 58608], [39137, 58609], [39142, 58610], [39148, 58611],
- [37752, 58612], [39225, 58613], [58614, 150057], [19314, 58615],
- [58616, 170071], [58617, 170245], [39413, 58618], [39436, 58619],
- [39483, 58620], [39440, 58621], [39512, 58622], [58623, 153381],
- [14020, 58624], [58625, 168113], [58626, 170965], [39648, 58627],
- [39650, 58628], [58629, 170757], [39668, 58630], [19470, 58631],
- [39700, 58632], [39725, 58633], [58634, 165376], [20532, 58635],
- [39732, 58636], [14531, 58638], [58639, 143485], [39760, 58640],
- [39744, 58641], [58642, 171326], [23109, 58643], [58644, 137315],
- [39822, 58645], [39938, 58647], [39935, 58648], [39948, 58649],
- [58650, 171624], [40404, 58651], [58652, 171959], [58653, 172434],
- [58654, 172459], [58655, 172257], [58656, 172323], [58657, 172511],
- [40318, 58658], [40323, 58659], [58660, 172340], [40462, 58661],
- [40388, 58663], [58665, 172435], [58666, 172576], [58667, 137531],
- [58668, 172595], [40249, 58669], [58670, 172217], [58671, 172724],
- [40592, 58672], [40597, 58673], [40606, 58674], [40610, 58675],
- [19764, 58676], [40618, 58677], [40623, 58678], [58679, 148324],
- [40641, 58680], [15200, 58681], [14821, 58682], [15645, 58683],
- [20274, 58684], [14270, 58685], [58686, 166955], [40706, 58687],
- [40712, 58688], [19350, 58689], [37924, 58690], [58691, 159138],
- [40727, 58692, 60836], 0, [40761, 58694], [22175, 58695], [22154, 58696],
- [40773, 58697], [39352, 58698], [58699, 168075], [38898, 58700],
- [33919, 58701], 0, [40809, 58703], [31452, 58704], [40846, 58705],
- [29206, 58706], [19390, 58707], [58708, 149877], [58709, 149947],
- [29047, 58710], [58711, 150008], [58712, 148296], [58713, 150097],
- [29598, 58714], [58715, 166874], [58716, 137466], [31135, 58717],
- [58718, 166270], [58719, 167478], [37737, 58720], [37875, 58721],
- [58722, 166468], [37612, 58723], [37761, 58724], [37835, 58725],
- [58726, 166252], [58727, 148665], [29207, 58728], [16107, 58729],
- [30578, 58730], [31299, 58731], [28880, 58732], [58733, 148595],
- [58734, 148472], [29054, 58735], [58736, 137199], [28835, 58737],
- [58738, 137406], [58739, 144793], [16071, 58740], [58741, 137349],
- [58742, 152623], [58743, 137208], [14114, 58744], [58745, 136955],
- [58746, 137273], [14049, 58747], [58748, 137076], [58749, 137425],
- [58750, 155467], [14115, 58751], [58752, 136896], [22363, 58753],
- [58754, 150053], [58755, 136190], [58756, 135848], [58757, 136134],
- [58758, 136374], [34051, 58759, 58761], [58760, 145062], 0, [33877, 58762],
- [58763, 149908], [58764, 160101], [58765, 146993], [58766, 152924],
- [58767, 147195], [58768, 159826], [17652, 58769], [58770, 145134],
- [58771, 170397], [58772, 159526], [26617, 58773], [14131, 58774],
- [15381, 58775], [15847, 58776], [22636, 58777], [58778, 137506],
- [26640, 58779], [16471, 58780], [58781, 145215], [58782, 147681],
- [58783, 147595], [58784, 147727], [58785, 158753], [21707, 58786],
- [22174, 58787], [58788, 157361], [22162, 58789], [58790, 135135],
- [58791, 134056], [58792, 134669], 0, [58794, 166675], [37788, 58795],
- [20216, 58796], [20779, 58797], [14361, 58798], [58799, 148534],
- [20156, 58800], [58801, 132197], 0, [20299, 58803], [20362, 58804],
- [58805, 153169], [23144, 58806], [58807, 131499], [58808, 132043],
- [14745, 58809], [58810, 131850], [58811, 132116], [13365, 58812],
- [20265, 58813], [58814, 131776], [58815, 167603], [58816, 131701],
- [35546, 58817], [58818, 131596], [20120, 58819], [20685, 58820],
- [20749, 58821], [20386, 58822], [20227, 58823], [58824, 150030],
- [58825, 147082], [20290, 58826], [20526, 58827], [20588, 58828],
- [20609, 58829], [20428, 58830], [20453, 58831], [20568, 58832],
- [20732, 58833], [28278, 58838], [58839, 144789], [58840, 147001],
- [58841, 147135], [28018, 58842], [58843, 137348], [58844, 147081],
- [20904, 58845], [20931, 58846], [58847, 132576], [17629, 58848],
- [58849, 132259], [58850, 132242], [58851, 132241], [36218, 58852],
- [58853, 166556], [58854, 132878], [21081, 58855], [21156, 58856],
- [58857, 133235], [21217, 58858], 0, [18042, 58860], [29068, 58861],
- [58862, 148364], [58863, 134176], [58864, 149932], [58865, 135396],
- [27089, 58866], [58867, 134685], 0, [16094, 58869], [29849, 58870],
- [29716, 58871], [29782, 58872], [29592, 58873], [19342, 58874],
- [58875, 150204], [58876, 147597], [21456, 58877], [13700, 58878],
- [29199, 58879], [58880, 147657], [21940, 58881], [58882, 131909],
- [21709, 58883], [58884, 134086], [22301, 58885], [37469, 58886],
- [38644, 58887], [22493, 58889], [22413, 58890], [22399, 58891],
- [13886, 58892], [22731, 58893], [23193, 58894], [58895, 166470],
- [58896, 136954], [58897, 137071], [58898, 136976], [23084, 58899],
- [22968, 58900], [23166, 58902], [23247, 58903], [23058, 58904],
- [58905, 153926], [58906, 137715], [58907, 137313], [58908, 148117],
- [14069, 58909], [27909, 58910], [29763, 58911], [23073, 58912],
- [58913, 155267], [23169, 58914], [58915, 166871], [58916, 132115],
- [37856, 58917], [29836, 58918], [58919, 135939], [28933, 58920],
- [18802, 58921], [37896, 58922], [58923, 166395], [37821, 58924],
- [14240, 58925], [23582, 58926], [23710, 58927], [24158, 58928],
- [24136, 58929], [58930, 137622], [58931, 137596], [58932, 146158],
- [24269, 58933], [23375, 58934], [58935, 137475], [58936, 137476],
- [14081, 58937], [58938, 137376], [14045, 58939], [58940, 136958],
- [14035, 58941], [33066, 58942], [58943, 166471], [58944, 138682],
- [58945, 144498], [58946, 166312], [24332, 58947, 60916], [24334, 58948],
- [58949, 137511], [58950, 137131], [23147, 58951], [58952, 137019],
- [23364, 58953], [58955, 161277], [34912, 58956], [24702, 58957],
- [58958, 141408], [58959, 140843], [24539, 58960], [16056, 58961],
- [58962, 140719], [58963, 140734], [58964, 168072], [58965, 159603],
- [25024, 58966], [58967, 131134], [58968, 131142], [58969, 140827],
- [24985, 58970], [24984, 58971], [24693, 58972], [58973, 142491],
- [58974, 142599], [58975, 149204], [58976, 168269], [25713, 58977],
- [58978, 149093], [58979, 142186], [14889, 58980], [58981, 142114],
- [58982, 144464], [58983, 170218], [58984, 142968], [25399, 58985],
- [25782, 58987], [25393, 58988], [25553, 58989], [58990, 149987],
- [58991, 142695], [25252, 58992], [58993, 142497], [25659, 58994],
- [25963, 58995], [26994, 58996], [15348, 58997], [58998, 143502],
- [58999, 144045], [59000, 149897], [59001, 144043], [21773, 59002],
- [59003, 144096], [59004, 137433], [59005, 169023], [26318, 59006],
- [59007, 144009], [59008, 143795], [15072, 59009], [59011, 152964],
- [59012, 166690], [59013, 152975], [59014, 136956], [59015, 152923],
- [59016, 152613], [30958, 59017], [59018, 143619], [59019, 137258],
- [59020, 143924], [13412, 59021], [59022, 143887], [59023, 143746],
- [59024, 148169], [26254, 59025], [59026, 159012], [26219, 59027],
- [19347, 59028], [26160, 59029], [59030, 161904], [59031, 138731],
- [26211, 59032], [59033, 144082], [59034, 144097], [26142, 59035],
- [59036, 153714], [14545, 59037], [59038, 145466], [59039, 145340],
- [15257, 59040], [59041, 145314], [59042, 144382], [29904, 59043],
- [15254, 59044], [59046, 149034], [26806, 59047], 0, [15300, 59049],
- [27326, 59050], [59052, 145365], [59053, 148615], [27187, 59054],
- [27218, 59055], [27337, 59056], [27397, 59057], [59058, 137490],
- [25873, 59059], [26776, 59060], [27212, 59061], [15319, 59062],
- [27258, 59063], [27479, 59064], [59065, 147392], [59066, 146586],
- [37792, 59067], [37618, 59068], [59069, 166890], [59070, 166603],
- [37513, 59071], [59072, 163870], [59073, 166364], [37991, 59074],
- [28069, 59075], [28427, 59076], 0, [59079, 147327], [15759, 59080],
- [28164, 59081], [59082, 147516], [23101, 59083], [28170, 59084],
- [22599, 59085], [27940, 59086], [30786, 59087], [28987, 59088],
- [59089, 148250], [59090, 148086], [28913, 59091], [29264, 59092, 61085],
- [29319, 59093], [29332, 59094], [59095, 149391], [59096, 149285],
- [20857, 59097], [59098, 150180], [59099, 132587], [29818, 59100],
- [59101, 147192], [59102, 144991], [59103, 150090], [59104, 149783],
- [59105, 155617], [16134, 59106], [16049, 59107], [59108, 150239],
- [59109, 166947], [59110, 147253], [24743, 59111], [16115, 59112],
- [29900, 59113], [29756, 59114], [37767, 59115], [29751, 59116],
- [17567, 59117], [59118, 159210], [17745, 59119], [30083, 59120],
- [16227, 59121], [59122, 150745], [59123, 150790], [16216, 59124],
- [30037, 59125], [30323, 59126], [59127, 173510], 0, [29800, 59129, 61070],
- [59130, 166604], [59131, 149931], [59132, 149902], [15099, 59133],
- [15821, 59134], [59135, 150094], [16127, 59136], [59137, 149957],
- [59138, 149747], [37370, 59139], [22322, 59140], [37698, 59141],
- [59142, 166627], [59143, 137316], [20703, 59144], [59145, 152097],
- [59146, 152039], [30584, 59147], [59148, 143922], [30478, 59149],
- [30479, 59150], [30587, 59151], [59152, 149143], [59153, 145281],
- [14942, 59154], [59155, 149744], [29752, 59156], [29851, 59157],
- [16063, 59158], [59159, 150202], [59160, 150215], [16584, 59161],
- [59162, 150166], [59163, 156078], [37639, 59164], [59165, 152961],
- [30750, 59166], [30861, 59167], [30856, 59168], [30930, 59169],
- [29648, 59170], [31065, 59171], [59172, 161601], [59173, 153315],
- [16654, 59174], 0, 0, [31141, 59177], [27181, 59178], [59179, 147194],
- [31290, 59180], [31220, 59181], [16750, 59182], [59183, 136934],
- [16690, 59184], [37429, 59185], [31217, 59186], [59187, 134476],
- [59188, 149900], [59189, 131737], [59190, 146874], [59191, 137070],
- [13719, 59192], [21867, 59193], [13680, 59194], [13994, 59195],
- [59196, 131540], [59197, 134157], [31458, 59198], [23129, 59199],
- [59200, 141045], [59201, 154287], [59202, 154268], [23053, 59203],
- [59204, 131675], [30960, 59205], [23082, 59206], [59207, 154566],
- [31486, 59208], [16889, 59209], [31837, 59210], [31853, 59211],
- [16913, 59212], [59213, 154547], [59214, 155324], [59215, 155302],
- [31949, 59216], [59217, 150009], [59218, 137136], [31886, 59219],
- [31868, 59220], [31918, 59221], [27314, 59222], [32220, 59223],
- [32263, 59224], [32211, 59225], [32590, 59226], [59227, 156257],
- [59228, 155996], [59229, 162632], [32151, 59230], [59231, 155266],
- [17002, 59232], [59233, 158581], [59234, 133398], [26582, 59235],
- [59236, 131150], [59237, 144847], [22468, 59238], [59239, 156690],
- [59240, 156664], [32733, 59242], [31527, 59243], [59244, 133164],
- [59245, 154345], [59246, 154947], [31500, 59247], [59248, 155150],
- [39398, 59249], [34373, 59250], [39523, 59251], [27164, 59252],
- [59253, 144447], [59255, 150007], [59256, 157101], [39455, 59257],
- [59258, 157088], 0, [59260, 160039], [59261, 158929], [17642, 59262],
- [33079, 59263], [17410, 59264], [32966, 59265], [33033, 59266],
- [33090, 59267], [59268, 157620], [39107, 59269], [59270, 158274],
- [33378, 59271], [33381, 59272], [59273, 158289], [33875, 59274],
- [59275, 159143], [34320, 59276], [59277, 160283], [23174, 59278],
- [16767, 59279], [59280, 137280], [23339, 59281], [59282, 137377],
- [23268, 59283], [59284, 137432], [34464, 59285], [59286, 195004],
- [59287, 146831], [34861, 59288], [59289, 160802], [23042, 59290],
- [34926, 59291], [20293, 59292], [34951, 59293], [35007, 59294],
- [35046, 59295], [35173, 59296], [35149, 59297], [59298, 153219],
- [35156, 59299], [59300, 161669], [59301, 161668], [59302, 166901],
- [59303, 166873], [59304, 166812], [59305, 166393], [16045, 59306],
- [33955, 59307], [18165, 59308], [18127, 59309], [14322, 59310],
- [35389, 59311], [35356, 59312], [59313, 169032], [24397, 59314],
- [37419, 59315], [59316, 148100], [26068, 59317], [28969, 59318],
- [28868, 59319], [59320, 137285], [40301, 59321], [35999, 59322],
- [36073, 59323], [59324, 163292], [22938, 59325], [30659, 59326],
- [23024, 59327], [14036, 59329], [36394, 59330], [36519, 59331],
- [59332, 150537], [36656, 59333], [36682, 59334], [17140, 59335],
- [27736, 59336], [28603, 59337], [59338, 140065], [18587, 59339],
- [28537, 59340], [28299, 59341], [59342, 137178], [39913, 59343],
- [14005, 59344], [59345, 149807], [37051, 59346], 0, [21873, 59348],
- [18694, 59349], [37307, 59350], [37892, 59351], [59352, 166475],
- [16482, 59353], [59354, 166652], [37927, 59355], [59356, 166941],
- [59357, 166971], [34021, 59358], [35371, 59359], [38297, 59360],
- [38311, 59361], [38295, 59362], [38294, 59363], [59364, 167220],
- [29765, 59365], [16066, 59366], [59367, 149759], [59368, 150082],
- [59369, 148458], [16103, 59370], [59371, 143909], [38543, 59372],
- [59373, 167655], [59374, 167526], [59375, 167525], [16076, 59376],
- [59377, 149997], [59378, 150136], [59379, 147438], [29714, 59380],
- [29803, 59381], [16124, 59382], [38721, 59383], [59384, 168112],
- [26695, 59385], [18973, 59386], [59387, 168083], [59388, 153567], 0,
- [37736, 59390], [59391, 166281], [59392, 166950], [59393, 166703],
- [59394, 156606], [37562, 59395], [23313, 59396], [35689, 59397],
- [18748, 59398], [29689, 59399], [59400, 147995], [38811, 59401], 0,
- [39224, 59403], [59404, 134950], [24001, 59405], [59406, 166853],
- [59407, 150194], [38943, 59408], [59409, 169178], [37622, 59410],
- [59411, 169431], [37349, 59412], [17600, 59413], [59414, 166736],
- [59415, 150119], [59416, 166756], [39132, 59417], [59418, 166469],
- [16128, 59419], [37418, 59420], [18725, 59421], [33812, 59422],
- [39227, 59423], [39245, 59424], [59425, 162566], [15869, 59426], 0,
- [19311, 59428], [39338, 59429], [39516, 59430], [59431, 166757],
- [59432, 153800], [27279, 59433], [39457, 59434], [23294, 59435],
- [39471, 59436], [59437, 170225], [19344, 59438], [59439, 170312],
- [39356, 59440], [19389, 59441], [19351, 59442], [37757, 59443],
- [22642, 59444], [59445, 135938], [22562, 59446], [59447, 149944],
- [59448, 136424], [30788, 59449], [59450, 141087], [59451, 146872],
- [26821, 59452], [15741, 59453], [37976, 59454], [14631, 59455],
- [24912, 59456], [59457, 141185], [59458, 141675], [24839, 59459],
- [40015, 59460], [40019, 59461], [40059, 59462], [39989, 59463],
- [39952, 59464], [39807, 59465], [39887, 59466], [59467, 171565],
- [39839, 59468], [59469, 172533], [59470, 172286], [40225, 59471],
- [19630, 59472], [59473, 147716], [40472, 59474], [19632, 59475],
- [40204, 59476], [59477, 172468], [59478, 172269], [59479, 172275],
- [59480, 170287], [40357, 59481], [33981, 59482], [59483, 159250],
- [59484, 159711], [59485, 158594], [34300, 59486], [17715, 59487],
- [59488, 159140], [59489, 159364], [59490, 159216], [33824, 59491],
- [34286, 59492], [59493, 159232], [59494, 145367], [59495, 155748],
- [31202, 59496], [59497, 144796], [59498, 144960], [59500, 149982],
- [15714, 59501], [37851, 59502], [37566, 59503], [37704, 59504],
- [59505, 131775], [30905, 59506], [37495, 59507], [37965, 59508],
- [20452, 59509], [13376, 59510], [36964, 59511], [59512, 152925],
- [30781, 59513], [30804, 59514], [30902, 59515], [30795, 59516],
- [59517, 137047], [59518, 143817], [59519, 149825], [13978, 59520],
- [20338, 59521], [28634, 59522], [28633, 59523], 0, [28702, 59524, 59525],
- [21524, 59526], [59527, 147893], [22459, 59528], [22771, 59529],
- [22410, 59530], [40214, 59531], [22487, 59532], [28980, 59533],
- [13487, 59534], [59535, 147884], [29163, 59536], [59537, 158784],
- [59538, 151447], 0, [59540, 137141], [59541, 166473], [24844, 59542],
- [23246, 59543], [23051, 59544], [17084, 59545], [59546, 148616],
- [14124, 59547], [19323, 59548], [59549, 166396], [37819, 59550],
- [37816, 59551], [59552, 137430], [59553, 134941], [33906, 59554],
- [59555, 158912], [59556, 136211], [59557, 148218], [59558, 142374],
- [59559, 148417], [22932, 59560], [59561, 146871], [59562, 157505],
- [32168, 59563], [59564, 155995], [59565, 155812], [59566, 149945],
- [59567, 149899], [59568, 166394], [37605, 59569], [29666, 59570],
- [16105, 59571], [29876, 59572], [59573, 166755], [59574, 137375],
- [16097, 59575], [59576, 150195], [27352, 59577], [29683, 59578],
- [29691, 59579], [16086, 59580], [59581, 150078], [59582, 150164],
- [59583, 137177], [59584, 150118], [59585, 132007], [59586, 136228],
- [59587, 149989], [29768, 59588], [59589, 149782], [28837, 59590],
- [59591, 149878], [37508, 59592], [29670, 59593], [37727, 59594],
- [59595, 132350], [37681, 59596], [59597, 166606], [59598, 166422],
- [37766, 59599], [59600, 166887], [59601, 153045], [18741, 59602],
- [59603, 166530], [29035, 59604], [59605, 149827], [59606, 134399],
- [22180, 59607], [59608, 132634], [59609, 134123], [59610, 134328],
- [21762, 59611], [31172, 59612], [59613, 137210], [32254, 59614],
- [59615, 136898], [59616, 150096], [59617, 137298], [17710, 59618],
- [37889, 59619], [14090, 59620], [59621, 166592], [59622, 149933],
- [22960, 59623], [59624, 137407], [59625, 137347], [59626, 160900],
- [23201, 59627], [14050, 59628], [59629, 146779], [14000, 59630],
- [37471, 59631], [23161, 59632], [59633, 166529], [59634, 137314],
- [37748, 59635], [15565, 59636], [59637, 133812], [19094, 59638],
- [14730, 59639], [20724, 59640], [15721, 59641], [15692, 59642],
- [59643, 136092], [29045, 59644], [17147, 59645], [59646, 164376],
- [28175, 59647], [59648, 168164], [17643, 59649], [27991, 59650],
- [59651, 163407], [28775, 59652], [27823, 59653], [15574, 59654],
- [59655, 147437], [59656, 146989], [28162, 59657], [28428, 59658],
- [15727, 59659], [59660, 132085], [30033, 59661], [14012, 59662],
- [13512, 59663], [18048, 59664], [16090, 59665], [18545, 59666],
- [22980, 59667], [37486, 59668], [18750, 59669], [36673, 59670],
- [59671, 166940], [59672, 158656], [22546, 59673], [22472, 59674],
- [14038, 59675], [59676, 136274], [28926, 59677], [59678, 148322],
- [59679, 150129], [59680, 143331], [59681, 135856], [59682, 140221],
- [26809, 59683], [26983, 59684], [59685, 136088], [59686, 144613],
- [59687, 162804], [59688, 145119], [59689, 166531], [59690, 145366],
- [59691, 144378], [59692, 150687], [27162, 59693], [59694, 145069],
- [59695, 158903], [33854, 59696], [17631, 59697], [17614, 59698],
- [59699, 159014], [59700, 159057], [59701, 158850], [59702, 159710], 0, 0,
- [33597, 59705], [59706, 137018], [33773, 59707], [59708, 158848],
- [59709, 159827], [59710, 137179], [22921, 59711], [23170, 59712],
- [59713, 137139], [23137, 59714], [23153, 59715], [59716, 137477],
- [59717, 147964], [14125, 59718], [23023, 59719], [59720, 137020],
- [14023, 59721], [29070, 59722], [37776, 59723], [26266, 59724],
- [59725, 148133], [23150, 59726], [23083, 59727], [59728, 148115],
- [27179, 59729], [59730, 147193], [59731, 161590], [59732, 148571],
- [59733, 148170], [28957, 59734], [59735, 148057], [59736, 166369],
- [20400, 59737], [59738, 159016], [23746, 59739], [59740, 148686],
- [59741, 163405], [59742, 148413], [27148, 59743], [59744, 148054],
- [59745, 135940], 0, [28979, 59747], [59748, 148457], [15781, 59749],
- [27871, 59750], [59751, 194597], [23019, 59754], [24412, 59757],
- [59764, 144128], [31955, 59776], [59783, 162548], [59786, 153334],
- [59790, 162584], [36972, 59791], [33270, 59795], [30476, 59797],
- [27810, 59799], [22269, 59800], [22633, 59828], [26465, 59832],
- [23646, 59838], [22770, 59841], [28857, 59843], [26627, 59853],
- [36795, 59859], [36796, 59861], [20001, 59871], [31545, 59898],
- [15820, 59902], [29482, 57990, 59909], [30048, 59912], [22586, 59920],
- [33446, 59932], [27018, 59940], [24803, 59944], [20206, 59984],
- [39364, 60002], [40639, 60023], [21249, 60025], [26528, 60038],
- [24808, 60046], [20916, 60053], [31363, 60064], [39994, 60075],
- [31432, 60093], [26906, 60098], [22956, 60100], [22592, 60102],
- [21610, 60114], [24807, 60123], [22138, 60125], [26965, 60132],
- [39983, 60133], [34725, 60134], [23584, 60141], [24075, 60143],
- [26398, 60147], [33965, 60157], [35713, 60161], [20088, 60166],
- [25283, 60176], [26709, 60180], 0, [33533, 60190], [35237, 60194],
- [36768, 60196], [38840, 60198], [38983, 60200], [39613, 60201],
- [24497, 60218], [26184, 60219], [26303, 60220], [60221, 162425], 0,
- [60225, 149946], 0, 0, [60230, 131910], [26382, 60232], [26904, 60233],
- [60235, 161367], [60236, 155618], [60239, 161278], [60240, 139418],
- [18640, 60241], [19128, 60242], [60244, 166554], [60247, 147515],
- [60250, 150085], [60251, 132554], [20946, 60252], [60253, 132625],
- [22943, 60254], [60255, 138920], [15294, 60256], [60257, 146687],
- [14747, 60262], [60264, 165352], [60265, 170441], [14178, 60266],
- [60267, 139715], [35678, 60268], [60269, 166734], 0, [29193, 60274],
- [60276, 134264], [60280, 132985], [36570, 60281], [21135, 60283],
- [29041, 60285], [60288, 147274], [60289, 150183], [21948, 60290],
- [60293, 158546], [13427, 60295], [60297, 161330], [18200, 60299],
- [60303, 149823], [20582, 60305], [13563, 60306], [60307, 144332], 0,
- [18300, 60310], [60311, 166216], [60315, 138640], 0, [60320, 162834],
- [36950, 60321], [60323, 151450], [35682, 60324], [23899, 60327],
- [60328, 158711], 0, [60331, 137500], [35562, 60332], [60333, 150006],
- [60335, 147439], [19392, 60337], [60340, 141083], [37989, 60341],
- [60342, 153569], [24981, 60343], [23079, 60344], [60345, 194765], 0,
- [60348, 148769], [20074, 60350], [60351, 149812], [38486, 60352],
- [28047, 60353], [60354, 158909], [35191, 60356], [60359, 156689], 0,
- [31554, 60363], [60364, 168128], [60365, 133649], 0, [31301, 60369],
- [39462, 60372], [13919, 60374], [60375, 156777], [60376, 131105],
- [31107, 60377], [23852, 60380], [60381, 144665], 0, [18128, 60384],
- [30011, 60386], [34917, 60387], [22710, 60389], [14108, 60390],
- [60391, 140685], [15444, 60394], [37505, 60397], [60398, 139642],
- [37680, 60400], [60402, 149968], [27705, 60403], [60406, 134904],
- [34855, 60407], [35061, 60408], [60409, 141606], [60410, 164979],
- [60411, 137137], [28344, 60412], [60413, 150058], [60414, 137248],
- [14756, 60415], 0, 0, [17727, 60419], [26294, 60420], [60421, 171181],
- [60422, 170148], [35139, 60423], [16607, 60427], [60428, 136714],
- [14753, 60429], [60430, 145199], [60431, 164072], [60432, 136133],
- [29101, 60433], [33638, 60434], [60436, 168360], 0, [19639, 60438],
- [60439, 159919], [60440, 166315], [60445, 147834], [31555, 60446],
- [31102, 60447], [28597, 60449], [60450, 172767], [27139, 60451],
- [60452, 164632], [21410, 60453], [60454, 159239], [37823, 60455],
- [26678, 60456], [38749, 59389, 60457], [60458, 164207], [60460, 158133],
- [60461, 136173], [60462, 143919], [23941, 60464], [60465, 166960],
- [22293, 60467], [38947, 60468], [60469, 166217], [23979, 60470],
- [60471, 149896], [26046, 60472], [27093, 60473], [21458, 60474],
- [60475, 150181], [60476, 147329], [15377, 60477], [26422, 60478],
- [60482, 139169], [13770, 60490], [18682, 60493], 0, [30728, 60496],
- [37461, 60497], [17394, 60499], [17375, 60501], [23032, 60505], 0,
- [22155, 60518], [60520, 169449], [36882, 60541], [21953, 60546],
- [17673, 60551], [32383, 60552], [28502, 60553], [27313, 60554],
- [13540, 60556], [60558, 161949], [14138, 60559], 0, [60562, 163876],
- [60565, 162366], [15851, 60567], [60569, 146615], [60574, 156248],
- [22207, 60575], [36366, 60577], [23405, 60578], [25566, 60581], 0,
- [25904, 60585], [22061, 60586], [21530, 60588], [60591, 171416],
- [19581, 60592], [22050, 60593], [22046, 60594], [32585, 60595],
- [22901, 60597], [60598, 146752], [34672, 60599], [33047, 60604],
- [40286, 60605], [36120, 60606], [30267, 60607], [40005, 60608],
- [30286, 60609], [30649, 60610], [37701, 60611], [21554, 60612],
- [33096, 60613], [33527, 60614], [22053, 60615], [33074, 60616],
- [33816, 60617], [32957, 60618], [21994, 60619], [31074, 60620],
- [22083, 60621], [21526, 60622], [60623, 134813], [13774, 60624],
- [22021, 57509, 60625], [22001, 60626], [26353, 60627], [60628, 164578],
- [13869, 60629], [30004, 60630], [22000, 60631], [21946, 60632],
- [21655, 60633], [21874, 60634], [60635, 134209], [60636, 134294],
- [24272, 57652, 60637], [60639, 134774], [60640, 142434], [60641, 134818],
- [40619, 60642], [32090, 60643], 0, [60645, 135285], [25245, 60646],
- [38765, 60647], [21652, 60648], [36045, 60649], [29174, 60650],
- [37238, 60651], [25596, 60652], [25529, 60653], [25598, 60654],
- [21865, 60655], [60656, 142147], [40050, 60657], [60658, 143027],
- [20890, 60659], [13535, 60660], [60661, 134567], [20903, 60662],
- [21581, 60663], [21790, 60664], [21779, 60665], [30310, 60666],
- [36397, 60667], [60668, 157834], [30129, 60669], [32950, 60670],
- [34820, 60671], 0, [35015, 60673], [33206, 60674], [33820, 60675],
- [17644, 60677], [29444, 60678], [33547, 60681], [22139, 60683],
- [37232, 60690], [37384, 60692], [60696, 134905], [29286, 60697],
- [18254, 60699], [60701, 163833], [16634, 60703], [40029, 60704],
- [25887, 60705], [18675, 60707], [60708, 149472], [60709, 171388], 0,
- [60713, 161187], 60715, [60716, 155720], [29091, 60718], [32398, 60719],
- [40272, 60720], [13687, 60723], [27826, 60725], [21351, 60726],
- [14812, 60728], [60731, 149016], [33325, 60734], [21579, 60735], 60739,
- [14930, 60740], [29556, 60742], [60743, 171692], [19721, 60744],
- [39917, 60745], 0, [19547, 60748], [60751, 171998], [33884, 60752],
- [60754, 160434], [25390, 60757], [32037, 60758], [14890, 60761],
- [36872, 60762], [21196, 60763], [15988, 60764], [13946, 60765],
- [17897, 60766], [60767, 132238], [30272, 60768], [23280, 60769],
- [60770, 134838], [30842, 60771], [18358, 60772], [22695, 60773],
- [16575, 60774], [22140, 60775], [39819, 60776], [23924, 60777],
- [30292, 60778], [60779, 173108], [40581, 60780], [19681, 60781], 0,
- [14331, 60783], [24857, 60784], [60786, 148466], 60787, [22109, 60788],
- [60792, 171526], [21044, 60793], [13741, 60795], 0, [40316, 60797],
- [31830, 60798], [39737, 60799], [22494, 60800], [23635, 60802],
- [25811, 60803], [60804, 169168], [60805, 156469], [34477, 60807],
- [60808, 134440], [60811, 134513], 60812, [20990, 60813], [60814, 139023],
- [23950, 60815], [38659, 60816], [60817, 138705], [40577, 60818],
- [36940, 60819], [31519, 60820], [39682, 60821], [23761, 60822],
- [31651, 60823], [25192, 60824], [25397, 60825], [39679, 60826],
- [31695, 60827], [39722, 60828], [31870, 60829], 0, [31810, 60831],
- [31878, 60832], [39957, 60833], [31740, 60834], [39689, 60835], 0, 39982,
- [40794, 60839], [21875, 60840], [23491, 60841], [20477, 60842],
- [40600, 60843], [20466, 60844], [21088, 60845], [21201, 60847],
- [22375, 60848], [20566, 60849], [22967, 60850], [24082, 60851],
- [38856, 60852], [40363, 60853], [36700, 60854], [21609, 60855],
- [38836, 60856], [39232, 60857], [38842, 60858], [21292, 60859],
- [24880, 60860], [26924, 60861], [21466, 60862], [39946, 60863],
- [40194, 60864], [19515, 60865], [38465, 60866], [27008, 60867],
- [20646, 60868], [30022, 60869], [60870, 137069], [39386, 60871],
- [21107, 60872], 60873, [37209, 60874], [38529, 60875], [37212, 60876],
- 60877, [37201, 60878], [60879, 167575], [25471, 60880], [27338, 60882],
- [22033, 60883], [37262, 60884], [30074, 60885], [25221, 60886],
- [29519, 60888], [31856, 60889], [60890, 154657], 60892, [30422, 60894],
- [39837, 60895], [20010, 60896], [60897, 134356], [33726, 60898],
- [34882, 60899], 60900, [23626, 60901], [27072, 60902], 0, 0,
- [21023, 60905], [24053, 60906], [20174, 60907], [27697, 60908],
- [60909, 131570], [20281, 60910], [21660, 60911], 0, [21146, 60913],
- [36226, 60914], [13822, 60915], 0, [13811, 60917], 60918, [27474, 60919],
- [37244, 60920], [40869, 60921], [39831, 60922], [38958, 60923],
- [39092, 60924], [39610, 60925], [40616, 60926], [40580, 60927],
- [31508, 60929], 60930, [27642, 60931], [34840, 60932], [32632, 60933],
- 60934, [22048, 60935], [60936, 173642], [36471, 60937], [40787, 60938],
- 60939, [36308, 60940], [36431, 60941], [40476, 60942], [36353, 60943],
- [25218, 60944], [60945, 164733], [36392, 60946], [36469, 60947],
- [31443, 60948], [31294, 60950], [30936, 60951], [27882, 60952],
- [35431, 60953], [30215, 60954], [40742, 60956], [27854, 60957],
- [34774, 60958], [30147, 60959], [60960, 172722], [30803, 60961],
- [36108, 60963], [29410, 60964], [29553, 60965], [35629, 60966],
- [29442, 60967], [29937, 60968], [36075, 60969], [60970, 150203],
- [34351, 60971], [24506, 60972], [34976, 60973], [17591, 60974], 60975,
- [60977, 159237], 60978, [35454, 60979], [60980, 140571], 60981,
- [24829, 60982], [30311, 60983], [39639, 60984], [40260, 60985],
- [37742, 58859, 60986], [39823, 60987], [34805, 60988], 60989, 0,
- [36087, 60991], [29484, 60992], [38689, 60993], [39856, 60994],
- [13782, 60995], [29362, 60996], [19463, 60997], [31825, 60998],
- [39242, 60999], [24921, 61001], [19460, 61002], [40598, 61003],
- [24957, 61004], 61005, [22367, 61006], [24943, 61007], [25254, 61008],
- [25145, 61009], 0, [14940, 61011], [25058, 61012], [21418, 61013],
- [25444, 61015], [26626, 61016], [13778, 61017], [23895, 61018],
- [36826, 61020], [61021, 167481], 61022, [20697, 61023], [30982, 61025],
- [21298, 61026], [38456, 61027], [61028, 134971], [16485, 61029], 61030,
- [30718, 61031], 61032, [31938, 61033], [61034, 155418], [31962, 61035],
- [31277, 61036], [32870, 61037], [32867, 61038], [32077, 61039],
- [29957, 61040], [29938, 61041], [35220, 61042], [33306, 61043],
- [26380, 61044], [32866, 61045], [61046, 160902], [32859, 61047],
- [29936, 61048], [33027, 61049], [30500, 61050], [35209, 61051],
- [61052, 157644], [30035, 61053], [34729, 61055], [34766, 61056],
- [33224, 61057], [34700, 61058], [35401, 61059], [36013, 61060],
- [35651, 61061], [30507, 61062], [29944, 61063], [34010, 61064],
- [27058, 61066], [36262, 61067], 61068, [35241, 58392, 61069], 0,
- [28089, 61071], [34753, 61072], [61073, 147473], [29927, 61074],
- [15835, 61075], [29046, 61076], [24740, 57702, 61077], [24988, 61078],
- [15569, 61079], 0, [24695, 61081], 61082, [32625, 61083], 0,
- [24809, 61086], [19326, 61087], [57344, 132423], [37595, 57345],
- [57346, 132575], [57347, 147397], [34124, 57348], [17077, 57349],
- [29679, 57350], [20917, 57351], [13897, 57352], [57353, 149826],
- [57354, 166372], [37700, 57355], [57356, 137691], [33518, 57357],
- [57358, 146632], [30780, 57359], [26436, 57360], [25311, 57361],
- [57362, 149811], [57363, 166314], [57364, 131744], [57365, 158643],
- [57366, 135941], [20395, 57367], [57368, 140525], [20488, 57369],
- [57370, 159017], [57371, 162436], [57372, 144896], [57373, 150193],
- [57374, 140563], 0, [57376, 131966], [24484, 57377], [57378, 131968],
- [57379, 131911], [28379, 57380], [57381, 132127], 20702, [20737, 57383],
- [13434, 57384], [20750, 57385], [39020, 57386], [14147, 57387],
- [33814, 57388], [57389, 149924], [57390, 132231], [20832, 57391],
- [57392, 144308], [20842, 57393], [57394, 134143], [57395, 139516],
- [57396, 131813], [57397, 140592], [57398, 132494], [57399, 143923],
- [57400, 137603], [23426, 57401], [34685, 57402], [57403, 132531],
- [57404, 146585], [20914, 57405], [20920, 57406], [40244, 57407],
- [20937, 57408], [20943, 57409], [20945, 57410], [15580, 57411],
- [20947, 57412], [57413, 150182], [20915, 57414], 0, 0, [20973, 57417],
- [33741, 57418], [26942, 57419], [57420, 145197], [24443, 57421],
- [21003, 57422], [21030, 57423], [21052, 57424], [21173, 57425],
- [21079, 57426], [21140, 57427], [21177, 57428], [21189, 57429],
- [31765, 57430], [34114, 57431], [21216, 57432], [34317, 57433],
- [57434, 158483], 0, [57436, 166622], [21833, 57437], [28377, 57438],
- [57439, 147328], [57440, 133460], [57441, 147436], [21299, 57442], 0,
- [57444, 134114], [27851, 57445], [57446, 136998], [26651, 57447],
- [29653, 57448], [24650, 57449], [16042, 57450], [14540, 57451],
- [57452, 136936], [29149, 57453], [17570, 57454], [21357, 57455],
- [21364, 57456], [57457, 165547], [21374, 57458], 0, [57460, 136598],
- [57461, 136723], [30694, 57462], [21395, 57463], [57464, 166555],
- [21408, 57465], [21419, 57466], [21422, 57467], [29607, 57468],
- [57469, 153458], [16217, 57470], [29596, 57471], [21441, 57472],
- [21445, 57473], [27721, 57474], [20041, 57475], [22526, 57476],
- [21465, 57477], [15019, 57478], [57479, 134031], [21472, 57480],
- [57481, 147435], [57482, 142755], [21494, 57483], [57484, 134263],
- [21523, 57485], [28793, 57486], [21803, 57487], [26199, 57488],
- [27995, 57489], [21613, 57490], [57491, 158547], [57492, 134516],
- [21853, 57493], [21647, 57494], [21668, 57495], [18342, 57496],
- [57497, 136973], [57498, 134877], [15796, 57499], [57500, 134477],
- [57501, 166332], [57502, 140952], [21831, 57503], [19693, 57504],
- [21551, 57505], [29719, 57506], [21894, 57507], [21929, 57508], 0,
- [57510, 137431], [57511, 147514], [17746, 57512], [57513, 148533],
- [26291, 57514], [57515, 135348], [22071, 57516], [26317, 57517],
- [57518, 144010], [26276, 57519], 0, [22093, 57521], [22095, 57522],
- [30961, 57523], [22257, 57524], [38791, 57525], [21502, 57526],
- [22272, 57527], [22255, 57528], [22253, 57529], [57530, 166758],
- [13859, 57531], [57532, 135759], [22342, 57533], [57534, 147877],
- [27758, 57535], [28811, 57536], [22338, 57537], [14001, 57538],
- [57539, 158846], [22502, 57540], [57541, 136214], [22531, 57542],
- [57543, 136276], [57544, 148323], [22566, 57545], [57546, 150517], 0,
- [22698, 57548], [13665, 57549], [22752, 57550], [22748, 57551],
- [57552, 135740], [22779, 57553], [23551, 57554], [22339, 57555],
- [57556, 172368], [57557, 148088], [37843, 57558], [13729, 57559],
- [22815, 57560], [26790, 57561], [14019, 57562], [28249, 57563],
- [57564, 136766], [23076, 57565], 0, [57567, 136850], [34053, 57568],
- [22985, 57569], [57570, 134478], [57571, 158849], [57572, 159018],
- [57573, 137180], [23001, 57574], [57575, 137211], [57576, 137138],
- [57577, 159142], [28017, 57578], [57579, 137256], [57580, 136917],
- [23033, 57581], [57582, 159301], [23211, 57583], [23139, 57584],
- [14054, 57585], [57586, 149929], 0, [14088, 57588], [23190, 57589],
- [29797, 57590], [23251, 57591], [57592, 159649], [57593, 140628],
- [57595, 137489], [14130, 57596], [57597, 136888], [24195, 57598],
- [21200, 57599], [23414, 57600], [25992, 57601], [23420, 57602],
- [57603, 162318], [16388, 57604], [18525, 57605], [57606, 131588],
- [23509, 57607], [57609, 137780], [57610, 154060], [57611, 132517],
- [23539, 57612], [23453, 57613], [19728, 57614], [23557, 57615],
- [57616, 138052], [23571, 57617], [29646, 57618], [23572, 57619],
- [57620, 138405], [57621, 158504], [23625, 57622], [18653, 57623],
- [23685, 57624], [23785, 57625], [23791, 57626], [23947, 57627],
- [57628, 138745], [57629, 138807], [23824, 57630], [23832, 57631],
- [23878, 57632], [57633, 138916], [23738, 57634], [24023, 57635],
- [33532, 57636], [14381, 57637], [57638, 149761], [57639, 139337],
- [57640, 139635], [33415, 57641], [14390, 57642], [15298, 57643],
- [24110, 57644], [27274, 57645], 0, 57647, [57648, 148668], [57649, 134355],
- [21414, 57650], [20151, 57651], 0, [21416, 57653], [57654, 137073],
- [24073, 57655], 57656, [57657, 164994], [24313, 57658], [24315, 57659],
- [14496, 57660], [24316, 57661], [26686, 57662], [37915, 57663],
- [24333, 57664], [57665, 131521], [57666, 194708], [15070, 57667],
- [57669, 135994], [24378, 57670], [57671, 157832], [57672, 140240],
- [57674, 140401], [24419, 57675], [57677, 159342], [24434, 57678],
- [37696, 57679], [57680, 166454], [24487, 57681], [23990, 57682],
- [15711, 57683], [57684, 152144], [57685, 139114], [57686, 159992],
- [57687, 140904], [37334, 57688], [57689, 131742], [57690, 166441],
- [24625, 57691], [26245, 57692], [14691, 57694], [15815, 57695],
- [13881, 57696], [22416, 57697], [57698, 141236], [31089, 57699],
- [15936, 57700], [24734, 57701], 0, 0, [57704, 149890], [57705, 149903],
- [57706, 162387], [29860, 57707], [20705, 57708], [23200, 57709],
- [24932, 57710], [24898, 57712], [57713, 194726], [57714, 159442],
- [24961, 57715], [20980, 57716], [57717, 132694], [24967, 57718],
- [23466, 57719], [57720, 147383], [57721, 141407], [25043, 57722],
- [57723, 166813], [57724, 170333], [25040, 57725], [14642, 57726],
- [57727, 141696], [57728, 141505], [24611, 57729], [24924, 57730],
- [25886, 57731], [25483, 57732], [57733, 131352], [25285, 57734],
- [57735, 137072], [25301, 57736], [57737, 142861], [25452, 57738],
- [57739, 149983], [14871, 57740], [25656, 57741], [25592, 57742],
- [57743, 136078], [57744, 137212], [28554, 57746], [57747, 142902], 0,
- [57750, 153373], [25825, 57751], [25829, 57752], [38011, 57753],
- [14950, 57754], [25658, 57755], [14935, 57756], [25933, 57757],
- [28438, 57758], [57759, 150056], [57760, 150051], [25989, 57761],
- [25965, 57762], [25951, 57763], 0, [26037, 57765], [57766, 149824],
- [19255, 57767], [26065, 57768], [16600, 57769], [57770, 137257], 57771,
- [26083, 57772], [24543, 57773], [57774, 144384], [26136, 57775],
- [57776, 143863], [57777, 143864], [26180, 57778], [57779, 143780],
- [57780, 143781], [26187, 57781], [57782, 134773], [26215, 57783],
- [57784, 152038], [26227, 57785], 0, [57788, 143921], [57789, 165364],
- [57790, 143816], [57791, 152339], [30661, 57792], [57793, 141559],
- [39332, 57794], [26370, 57795], [57796, 148380], [57797, 150049],
- [27130, 57799], [57800, 145346], 0, [26471, 57802], [26466, 57803],
- [57804, 147917], [57805, 168173], [26583, 57806], [17641, 57807],
- [26658, 57808], [28240, 57809], [37436, 57810], [26625, 57811],
- [57812, 144358], [57813, 159136], [26717, 57814], [57815, 144495],
- [27105, 57816], [27147, 57817], [57818, 166623], [26995, 57819],
- [26819, 57820], [57821, 144845], [26881, 57822], [26880, 57823],
- [14849, 57825], [57826, 144956], [15232, 57827], [26540, 57828],
- [26977, 57829], [57830, 166474], [17148, 57831], [26934, 57832],
- [27032, 57833], [15265, 57834], [57835, 132041], [33635, 57836],
- [20624, 57837], [27129, 57838], [57839, 144985], [57840, 139562],
- [27205, 57841], [57842, 145155], [27293, 57843], [15347, 57844],
- [26545, 57845], [27336, 57846], [57847, 168348], [15373, 57848],
- [27421, 57849], [57850, 133411], [24798, 57851, 60308], [27445, 57852],
- [27508, 57853], [57854, 141261], [28341, 57855], [57856, 146139], 0,
- [57858, 137560], [14144, 57859], [21537, 57860], [57861, 146266],
- [27617, 57862], [57863, 147196], [27612, 57864], [27703, 57865],
- [57866, 140427], [57867, 149745], [57868, 158545], [27738, 57869],
- [33318, 57870], [27769, 57871], [57872, 146876], [17605, 57873],
- [57874, 146877], [57875, 147876], [57876, 149772], [57877, 149760],
- [57878, 146633], [14053, 57879], [15595, 57880], [57881, 134450],
- [39811, 57882], [57883, 143865], [57884, 140433], [32655, 57885],
- [26679, 57886], [57887, 159013], [57888, 159137], [57889, 159211],
- [28054, 57890], [27996, 57891], [28284, 57892], [28420, 57893],
- [57894, 149887], [57895, 147589], [57896, 159346], [34099, 57897],
- [57898, 159604], [20935, 57899], 0, 0, [33838, 57902], [57903, 166689], 0,
- [57905, 146991], [29779, 57906], [57907, 147330], [31180, 57908],
- [28239, 57909], [23185, 57910], [57911, 143435], [28664, 57912],
- [14093, 57913], [28573, 57914], [57915, 146992], [28410, 57916],
- [57917, 136343], [57918, 147517], [17749, 57919], [37872, 57920],
- [28484, 57921], [28508, 57922], [15694, 57923], [28532, 57924],
- [57925, 168304], [15675, 57926], [28575, 57927], [57928, 147780],
- [28627, 57929], [57930, 147601], [57931, 147797], [57932, 147513],
- [57933, 147440], [57934, 147380], [57935, 147775], [20959, 57936],
- [57937, 147798], [57938, 147799], [57939, 147776], [57940, 156125],
- [28747, 57941], [28798, 57942], [28839, 57943], 0, [28876, 57945],
- [28885, 57946], [28886, 57947], [28895, 57948], [16644, 57949],
- [15848, 57950], [29108, 57951], [29078, 57952], [57953, 148087],
- [28971, 57954], [28997, 57955], [23176, 57956], [29002, 57957], 0,
- [57960, 148325], [29007, 57961], [37730, 57962], [57963, 148161],
- [28972, 57964], [57965, 148570], [57966, 150055], [57967, 150050],
- [29114, 57968], [57969, 166888], [28861, 57970], [29198, 57971],
- [37954, 57972], [29205, 57973], [22801, 57974], [37955, 57975],
- [29220, 57976], [37697, 57977], [57978, 153093], [29230, 57979],
- [29248, 57980], [57981, 149876], [26813, 57982], [29269, 57983],
- [29271, 57984], [15957, 57985], [57986, 143428], [26637, 57987],
- [28477, 57988], [29314, 57989], 0, [29483, 57991], [57992, 149539],
- [57993, 165931], [18669, 57994], [57995, 165892], [29480, 57996],
- [29486, 57997], [29647, 57998], [29610, 57999], [58000, 134202],
- [58001, 158254], [29641, 58002], [29769, 58003], [58004, 147938],
- [58005, 136935], [58006, 150052], [26147, 58007], [14021, 58008],
- [58009, 149943], [58010, 149901], [58011, 150011], [29687, 58012],
- [29717, 58013], [26883, 58014], [58015, 150054], [29753, 58016],
- [16087, 58018], 0, [58020, 141485], [29792, 58021], [58022, 167602],
- [29767, 58023], [29668, 58024], [29814, 58025], [33721, 58026],
- [29804, 58027], [29812, 58029], [37873, 58030], [27180, 58031],
- [29826, 58032], [18771, 58033], [58034, 150156], [58035, 147807],
- [58036, 150137], [58037, 166799], [23366, 58038], [58039, 166915],
- [58040, 137374], [29896, 58041], [58042, 137608], [29966, 58043],
- [29982, 58045], [58046, 167641], [58047, 137803], [23511, 58048],
- [58049, 167596], [37765, 58050], [30029, 58051], [30026, 58052],
- [30055, 58053], [30062, 58054], [58055, 151426], [16132, 58056],
- [58057, 150803], [30094, 58058], [29789, 58059], [30110, 58060],
- [30132, 58061], [30210, 58062], [30252, 58063], [30289, 58064],
- [30287, 58065], [30319, 58066], 58067, [58068, 156661], [30352, 58069],
- [33263, 58070], [14328, 58071], [58072, 157969], [58073, 157966],
- [30369, 58074], [30373, 58075], [30391, 58076], [30412, 58077],
- [58078, 159647], [33890, 58079], [58080, 151709], [58081, 151933],
- [58082, 138780], [30494, 58083], [30502, 58084], [30528, 58085],
- [25775, 58086], [58087, 152096], [30552, 58088], [58089, 144044],
- [30639, 58090], [58091, 166244], [58092, 166248], [58093, 136897],
- [30708, 58094], 0, [26826, 58098], [30895, 58099], [30919, 58100],
- [30931, 58101], [38565, 58102], [31022, 58103], [58104, 153056],
- [30935, 58105], [31028, 58106], [30897, 58107], [58108, 161292],
- [36792, 58109], [34948, 58110], [58113, 140828], [31110, 58114],
- [35072, 58115], [26882, 58116], [31104, 58117], [58118, 153687],
- [31133, 58119], [58120, 162617], [31036, 58121], [31145, 58122],
- [28202, 58123], [58124, 160038], [16040, 58125], [31174, 58126],
- [58127, 168205], [31188, 58128], 0, [21797, 62526], 0, [62528, 134210],
- [62529, 134421], [62530, 151851], [21904, 62531], [62532, 142534],
- [14828, 62533], [62534, 131905], [36422, 62535], [62536, 150968],
- [62537, 169189], 0, [62539, 164030], [30586, 62540], [62541, 142392],
- [14900, 62542], [18389, 62543], [62544, 164189], [62545, 158194],
- [62546, 151018], [25821, 62547], [62548, 134524], [62549, 135092],
- [62550, 134357], 0, [25741, 62552], [36478, 62553], [62554, 134806], 0,
- [62556, 135012], [62557, 142505], [62558, 164438], [62559, 148691], 0,
- [62561, 134470], [62562, 170573], [62563, 164073], [18420, 62564],
- [62565, 151207], [62566, 142530], [39602, 62567], [14951, 62568],
- [62569, 169460], [16365, 62570], [13574, 62571], [62572, 152263],
- [62573, 169940], 0, [62575, 142660], [40302, 62576], [38933, 62577], 0,
- [17369, 62579], 0, [25780, 62581], [21731, 62582], 0, [62584, 142282], 0,
- [14843, 62586], 0, [62588, 157402], [62589, 157462], [62590, 162208],
- [25834, 62591], [62592, 151634], [62593, 134211], [36456, 62594], 0,
- [62596, 166732], [62597, 132913], 0, [18443, 62599], [62600, 131497],
- [16378, 62601], [22643, 62602], [62603, 142733], 0, [62605, 148936],
- [62606, 132348], [62607, 155799], [62608, 134988], 0, [21881, 62610], 0,
- [17338, 62612], 0, [19124, 62614], [62615, 141926], [62616, 135325],
- [33194, 62617], [39157, 62618], [62619, 134556], [25465, 62620],
- [14846, 62621], [62622, 141173], [36288, 62623], [22177, 62624],
- [25724, 62625], [15939, 62626], 0, [62628, 173569], [62629, 134665],
- [62630, 142031], 0, 0, [62633, 135368], [62634, 145858], [14738, 62635],
- [14854, 62636], [62637, 164507], [13688, 62638], [62639, 155209],
- [62640, 139463], 0, 0, [62643, 142514], [62644, 169760], [13500, 62645],
- [27709, 62646], [62647, 151099], 0, 0, [62650, 161140], [62651, 142987],
- [62652, 139784], [62653, 173659], [62654, 167117], [62655, 134778],
- [62656, 134196], [62683, 161337], [62684, 142286], [62687, 142417],
- [14872, 62689], [62691, 135367], [62693, 173618], [62695, 167122],
- [62696, 167321], [62697, 167114], [38314, 62698], 0, [62706, 161630],
- [28992, 62708], 0, [20822, 62385], 0, [20616, 62487], 0, [13459, 62489],
- [20870, 62491], [24130, 63037], [20997, 62495], [21031, 62436],
- [21113, 62497], 0, [13651, 62504], [21442, 62505], [21343, 62715], 0,
- [21823, 62520], 0, [21976, 59986], [13789, 62722], [22049, 63067], 0,
- [22100, 60044], [60148, 135291], 0, [60153, 135379], 0, [61095, 135934], 0,
- 0, [14265, 60104], [23745, 61099], [23829, 63066], [23894, 63030],
- [14392, 63036], [20097, 62477], [24253, 63038], [14612, 63042],
- [25017, 63050], [25232, 63054], [25368, 63056], [25690, 63063],
- [25745, 62381], [33133, 62709], [33156, 59922], [33171, 59924],
- [26624, 63080], [15292, 63093], [29327, 60517], [29389, 59781], 0,
- [29497, 59785], [30018, 59811], [30172, 59817], [16320, 59818],
- [60278, 151205], [16343, 59820], 0, 30336, [30348, 59824, 151388],
- [16552, 59845], [30777, 59846], [16643, 59855], [31377, 59863],
- [31771, 59876], [31981, 59884], [32659, 62658], [32686, 59892], 0,
- [33535, 59936], [22623, 59981], [34482, 59960], 0, [34699, 59963],
- [35143, 59969], 0, [35369, 59972], 0, [36465, 59988], [60484, 164233],
- [36528, 59990], 0, [37214, 62443], [37260, 62441], [39182, 60051],
- [39196, 60054], 0, 0, [39809, 60066], [40384, 60080], [40339, 60078],
- [40620, 60085], [19857, 60540], 0, 37818, [40571, 60084], [28809, 63148],
- [29512, 59788], 0, [31129, 59858], [36791, 59997], 0, [39234, 60056],
- {s: 193}, 8364, {s: 4}, [12443, 63518], [12444, 63519], [11904, 63520],
- {f: 5, c: 62211}, [62216, 131340], 62217, [62218, 131281], [62219, 131277],
- {f: 2, c: 62220}, [62222, 131275], [62223, 139240], 62224, [62225, 131274],
- {f: 4, c: 62226}, [62230, 131342], {f: 2, c: 62231}, {f: 2, c: 62776},
- [62778, 138177], [62779, 194680], [12205, 38737, 62780], [62781, 131206],
- [20059, 62782], [20155, 62783], [13630, 62784], [23587, 62785],
- [24401, 62786], [24516, 62787], [14586, 62788], [25164, 62789],
- [25909, 62790], [27514, 62791], [27701, 62792], [27706, 62793],
- [28780, 62794], [29227, 62795], [20012, 62796], [29357, 62797],
- [62798, 149737], [32594, 62799], [31035, 62800], [31993, 62801],
- [32595, 62802], [62803, 156266], [13505, 62804], [62806, 156491],
- [32770, 62807], [32896, 62808], [62809, 157202], [62810, 158033],
- [21341, 62811], [34916, 62812], [35265, 62813], [62814, 161970],
- [35744, 62815], [36125, 62816], [38021, 62817], [38264, 62818],
- [38271, 62819], [38376, 62820], [62821, 167439], [38886, 62822],
- [39029, 62823], [39118, 62824], [39134, 62825], [39267, 62826],
- [62827, 170000], [40060, 62828], [40479, 62829], [40644, 62830],
- [27503, 62831], [62832, 63751], [20023, 62833], [62834, 131207],
- [38429, 62835], [25143, 62836], [38050, 62837], [11908, 63521],
- [11910, 63522], [11911, 63523], [11912, 63524], [11914, 63525],
- [11916, 63526], [11917, 63527], [11925, 63528], [11932, 63529],
- [11941, 63531], [11943, 63532], [11946, 63533], [11948, 63534],
- [11950, 63535], [11958, 63536], [11964, 63537], [11966, 63538],
- [11978, 63540], [11980, 63541], [11981, 63542], [11983, 63543],
- [11990, 63544], [11991, 63545], [11998, 63546], [62368, 172969],
- [62369, 135493], [25866, 62371], [20029, 62374], [28381, 62375],
- [40270, 62376], [37343, 62377], [62380, 161589], [20250, 62382],
- [20264, 62383], [20392, 62384], [20852, 62386], [20892, 62387],
- [20964, 62388], [21153, 62389], [21160, 62390], [21307, 62391],
- [21326, 62392], [21457, 62393], [21464, 62394], [22242, 62395],
- [22768, 62396], [22788, 62397], [22791, 62398], [22834, 62399],
- [22836, 62400], [23398, 62401], [23454, 62402], [23455, 62403],
- [23706, 62404], [24198, 62405], [24635, 62406], [25993, 62407],
- [26622, 62408], [26628, 62409], [26725, 62410], [27982, 62411],
- [28860, 62412], [30005, 62413], [32420, 62414], [32428, 62415],
- [32442, 62416], [32455, 62417], [32463, 62418], [32479, 62419],
- [32518, 62420], [32567, 62421], [33402, 62422], [33487, 62423],
- [33647, 62424], [35270, 62425], [35774, 62426], [35810, 62427],
- [36710, 62428], [36711, 62429], [36718, 62430], [29713, 62431],
- [31996, 62432], [32205, 62433], [26950, 62434], [31433, 62435],
- [30904, 62442], [32956, 62444], [36107, 62446], [33014, 62447],
- [62448, 133607], [32927, 62451], [40647, 62452], [19661, 62453],
- [40393, 62454], [40460, 62455], [19518, 62456], [62457, 171510],
- [62458, 159758], [40458, 62459], [62460, 172339], [13761, 62461],
- [28314, 62463], [33342, 62464], [29977, 62465], [18705, 62467],
- [39532, 62468], [39567, 62469], [40857, 62470], [31111, 62471],
- [62472, 164972], [62473, 138698], [62474, 132560], [62475, 142054],
- [20004, 62476], [20096, 62478], [20103, 62479], [20159, 62480],
- [20203, 62481], [20279, 62482], [13388, 62483], [20413, 62484],
- [15944, 62485], [20483, 62486], [13437, 62488], [13477, 62490],
- [22789, 62492], [20955, 62493], [20988, 62494], [20105, 62496],
- [21136, 62498], [21287, 62499], [13767, 62500], [21417, 62501],
- [13649, 62502], [21424, 62503], [21539, 62506], [13677, 62507],
- [13682, 62508], [13953, 62509], [21651, 62510], [21667, 62511],
- [21684, 62512], [21689, 62513], [21712, 62514], [21743, 62515],
- [21784, 62516], [21795, 62517], [21800, 62518], [13720, 62519],
- [13733, 62521], [13759, 62522], [21975, 62523], [13765, 62524],
- [62525, 163204], [16467, 62538], [62551, 135412], [62555, 134155],
- [62574, 161992], [62580, 155813], [62583, 142668], [62585, 135287],
- [62587, 135279], [62595, 139681], [62609, 134550], [16571, 62611],
- [62631, 142537], [22098, 62641], [62642, 134961], [62657, 157724],
- [62659, 135375], [62660, 141315], [62661, 141625], [13819, 62662],
- [62663, 152035], [62664, 134796], [62665, 135053], [62666, 134826],
- [16275, 62667], [62668, 134960], [62669, 134471], [62670, 135503],
- [62671, 134732], [62673, 134827], [62674, 134057], [62675, 134472],
- [62676, 135360], [62677, 135485], [16377, 62678], [62679, 140950],
- [25650, 62680], [62681, 135085], [62682, 144372], [62685, 134526],
- [62686, 134527], [62688, 142421], [62690, 134808], [62692, 134958],
- [62694, 158544], [21708, 62699], [33476, 62700], [21945, 62701],
- [62703, 171715], [39974, 62704], [39606, 62705], [62707, 142830],
- [33004, 62710], [23580, 62711], [62712, 157042], [33076, 62713],
- [14231, 62714], [62716, 164029], [37302, 62717], [62718, 134906],
- [62719, 134671], [62720, 134775], [62721, 134907], [62723, 151019],
- [13833, 62724], [62725, 134358], [22191, 62726], [62727, 141237],
- [62728, 135369], [62729, 134672], [62730, 134776], [62731, 135288],
- [62732, 135496], [62733, 164359], [62734, 136277], [62735, 134777],
- [62736, 151120], [62737, 142756], [23124, 62738], [62739, 135197],
- [62740, 135198], [62741, 135413], [62742, 135414], [22428, 62743],
- [62744, 134673], [62745, 161428], [62746, 164557], [62747, 135093],
- [62748, 134779], [62749, 151934], [14083, 62750], [62751, 135094],
- [62752, 135552], [62753, 152280], [62754, 172733], [62755, 149978],
- [62756, 137274], [62757, 147831], [62758, 164476], [22681, 62759],
- [21096, 62760], [13850, 62761], [62762, 153405], [31666, 62763],
- [23400, 62764], [18432, 62765], [19244, 62766], [40743, 62767],
- [18919, 62768], [39967, 62769], [39821, 62770], [62771, 154484],
- [62772, 143677], [22011, 62773], [13810, 62774], [22153, 62775],
- [23870, 63028], [23880, 63029], [15868, 63031], [14351, 63032],
- [23972, 63033], [23993, 63034], [14368, 63035], [24357, 63039],
- [24451, 63040], [14600, 63041], [14655, 63043], [14669, 63044],
- [24791, 63045], [24893, 63046], [23781, 63047], [14729, 63048],
- [25015, 63049], [25039, 63051], [14776, 63052], [25132, 63053],
- [25317, 63055], [14840, 63057], [22193, 63058], [14851, 63059],
- [25570, 63060], [25595, 63061], [25607, 63062], [14923, 63064],
- [25792, 63065], [40863, 63068], [14999, 63069], [25990, 63070],
- [15037, 63071], [26111, 63072], [26195, 63073], [15090, 63074],
- [26258, 63075], [15138, 63076], [26390, 63077], [15170, 63078],
- [26532, 63079], [15192, 63081], [26698, 63082], [26756, 63083],
- [15218, 63084], [15217, 63085], [15227, 63086], [26889, 63087],
- [26947, 63088], [29276, 63089], [26980, 63090], [27039, 63091],
- [27013, 63092], [27094, 63094], [15325, 63095], [27237, 63096],
- [27252, 63097], [27249, 63098], [27266, 63099], [15340, 63100],
- [27289, 63101], [15346, 63102], [27307, 63103], [27317, 63104],
- [27348, 63105], [27382, 63106], [27521, 63107], [27585, 63108],
- [27626, 63109], [27765, 63110], [27818, 63111], [15563, 63112],
- [27906, 63113], [27910, 63114], [27942, 63115], [28033, 63116],
- [15599, 63117], [28068, 63118], [28081, 63119], [28181, 63120],
- [28184, 63121], [28201, 63122], [28294, 63123], [63124, 166336],
- [28347, 63125], [28386, 63126], [28378, 63127], [40831, 63128],
- [28392, 63129], [28393, 63130], [28452, 63131], [28468, 63132],
- [15686, 63133], [63134, 147265], [28545, 63135], [28606, 63136],
- [15722, 63137], [15733, 63138], [29111, 63139], [23705, 63140],
- [15754, 63141], [28716, 63142], [15761, 63143], [28752, 63144],
- [28756, 63145], [28783, 63146], [28799, 63147], [63149, 131877],
- [17345, 63150], [13809, 63151], [63152, 134872], [13902, 58134],
- [15789, 58172], [58173, 154725], [26237, 58183], [31860, 58188],
- [29837, 58197], [32402, 58215], [17667, 58232], [58260, 151480],
- [58270, 133901], [58277, 158474], [13438, 58311], [58317, 143087],
- [58325, 146613], [58343, 159385], [34673, 58364], [25537, 58385],
- [30583, 58387], [35210, 58390], [58406, 147343], [35660, 58415],
- [58440, 150729], [18730, 58464], [58471, 172052], [58472, 165564],
- [58473, 165121], [15088, 58490], [28815, 58511], [58529, 140922],
- [58637, 158120], [58646, 148043], [26760, 58662], [58664, 139611],
- [40802, 58702], [37830, 58793], [58802, 131967], [37734, 58888],
- [37519, 58901], [34324, 58954], [58986, 173147], [16784, 59010],
- [26511, 59045], [26654, 59048], [14435, 59051], [59077, 149996],
- [15129, 59128], [33942, 59176], [59241, 149858], [14818, 59254],
- [33920, 59259], [17262, 59328], [38769, 59402], [39323, 59427],
- [18733, 59499], [28439, 59703], [59704, 160009], [28838, 59746],
- [59752, 150095], [32357, 59753], [23855, 59755], [15859, 59756],
- [59758, 150109], [59759, 137183], [32164, 59760], [33830, 59761],
- [21637, 59762], [59763, 146170], [59765, 131604], [22398, 59766],
- [59767, 133333], [59768, 132633], [16357, 59769], [59770, 139166],
- [59771, 172726], [28675, 59772], [59773, 168283], [23920, 59774],
- [29583, 59775], [59777, 166489], [59778, 168992], [20424, 59779],
- [32743, 59780], [29456, 59782], [29496, 59784], [29505, 59787],
- [16041, 59789], [29173, 59792], [59793, 149746], [29665, 59794],
- [16074, 59796], [16081, 59798], [29721, 59801], [29726, 59802],
- [29727, 59803], [16098, 59804], [16112, 59805], [16116, 59806],
- [16122, 59807], [29907, 59808], [16142, 59809], [16211, 59810],
- [30061, 59812], [30066, 59813], [30093, 59814], [16252, 59815],
- [30152, 59816], [30285, 59819], [30324, 59821], [16348, 59822],
- [30330, 59823], [29064, 59825], [22051, 59826], [35200, 59827],
- [16413, 59829], [30531, 59830], [16441, 59831], [16453, 59833],
- [13787, 59834], [30616, 59835], [16490, 59836], [16495, 59837],
- [30654, 59839], [30667, 59840], [30744, 59842], [30748, 59844],
- [30791, 59847], [30801, 59848], [30822, 59849], [33864, 59850],
- [59851, 152885], [31027, 59852], [31026, 59854], [16649, 59856],
- [31121, 59857], [31238, 59860], [16743, 59862], [16818, 59864],
- [31420, 59865], [33401, 59866], [16836, 59867], [31439, 59868],
- [31451, 59869], [16847, 59870], [31586, 59872], [31596, 59873],
- [31611, 59874], [31762, 59875], [16992, 59877], [17018, 59878],
- [31867, 59879], [31900, 59880], [17036, 59881], [31928, 59882],
- [17044, 59883], [36755, 59885], [28864, 59886], [59887, 134351],
- [32207, 59888], [32212, 59889], [32208, 59890], [32253, 59891],
- [32692, 59893], [29343, 59894], [17303, 59895], [32800, 59896],
- [32805, 59897], [32814, 59899], [32817, 59900], [32852, 59901],
- [22452, 59903], [28832, 59904], [32951, 59905], [33001, 59906],
- [17389, 59907], [33036, 59908], [33038, 59910], [33042, 59911],
- [33044, 59913], [17409, 59914], [15161, 59915], [33110, 59916],
- [33113, 59917], [33114, 59918], [17427, 59919], [33148, 59921],
- [17445, 59923], [17453, 59925], [33189, 59926], [22511, 59927],
- [33217, 59928], [33252, 59929], [33364, 59930], [17551, 59931],
- [33398, 59933], [33482, 59934], [33496, 59935], [17584, 59937],
- [33623, 59938], [38505, 59939], [33797, 59941], [28917, 59942],
- [33892, 59943], [33928, 59945], [17668, 59946], [33982, 59947],
- [34017, 59948], [34040, 59949], [34064, 59950], [34104, 59951],
- [34130, 59952], [17723, 59953], [34159, 59954], [34160, 59955],
- [34272, 59956], [17783, 59957], [34418, 59958], [34450, 59959],
- [34543, 59961], [38469, 59962], [17926, 59964], [17943, 59965],
- [34990, 59966], [35071, 59967], [35108, 59968], [35217, 59970],
- [59971, 162151], [35384, 59973], [35476, 59974], [35508, 59975],
- [35921, 59976], [36052, 59977], [36082, 59978], [36124, 59979],
- [18328, 59980], [36291, 59982], [18413, 59983], [36410, 59985],
- [22356, 59987], [22005, 59989], [18487, 59991], [36558, 59992],
- [36578, 59993], [36580, 59994], [36589, 59995], [36594, 59996],
- [36801, 59998], [36810, 59999], [36812, 60000], [36915, 60001],
- [18605, 60003], [39136, 60004], [37395, 60005], [18718, 60006],
- [37416, 60007], [37464, 60008], [37483, 60009], [37553, 60010],
- [37550, 60011], [37567, 60012], [37603, 60013], [37611, 60014],
- [37619, 60015], [37620, 60016], [37629, 60017], [37699, 60018],
- [37764, 60019], [37805, 60020], [18757, 60021], [18769, 60022],
- [37911, 60024], [37917, 60026], [37933, 60027], [37950, 60028],
- [18794, 60029], [37972, 60030], [38009, 60031], [38189, 60032],
- [38306, 60033], [18855, 60034], [38388, 60035], [38451, 60036],
- [18917, 60037], [18980, 60039], [38720, 60040], [18997, 60041],
- [38834, 60042], [38850, 60043], [19172, 60045], [39097, 60047],
- [19225, 60048], [39153, 60049], [22596, 60050], [39193, 60052],
- [39223, 60055], [39261, 60057], [39266, 60058], [19312, 60059],
- [39365, 60060], [19357, 60061], [39484, 60062], [39695, 60063],
- [39785, 60065], [39901, 60067], [39921, 60068], [39924, 60069],
- [19565, 60070], [39968, 60071], [14191, 60072], [60073, 138178],
- [40265, 60074], [40702, 60076], [22096, 60077], [40381, 60079],
- [40444, 60081], [38134, 60082], [36790, 60083], [40625, 60086],
- [40637, 60087], [40646, 60088], [38108, 60089], [40674, 60090],
- [40689, 60091], [40696, 60092], [40772, 60094], [60095, 131220],
- [60096, 131767], [60097, 132000], [38083, 60099], [60101, 132311],
- [38081, 60103], [60105, 132565], [60106, 132629], [60107, 132726],
- [60108, 136890], [22359, 60109], [29043, 60110], [60111, 133826],
- [60112, 133837], [60113, 134079], [60115, 194619], [60116, 134091],
- [21662, 60117], [60118, 134139], [60119, 134203], [60120, 134227],
- [60121, 134245], [60122, 134268], [60124, 134285], [60126, 134325],
- [60127, 134365], [60128, 134381], [60129, 134511], [60130, 134578],
- [60131, 134600], [60135, 134660], [60136, 134670], [60137, 134871],
- [60138, 135056], [60139, 134957], [60140, 134771], [60142, 135100],
- [60144, 135260], [60145, 135247], [60146, 135286], [60149, 135304],
- [60150, 135318], [13895, 60151], [60152, 135359], [60154, 135471],
- [60155, 135483], [21348, 60156], [60158, 135907], [60159, 136053],
- [60160, 135990], [60162, 136567], [60163, 136729], [60164, 137155],
- [60165, 137159], [28859, 60167], [60168, 137261], [60169, 137578],
- [60170, 137773], [60171, 137797], [60172, 138282], [60173, 138352],
- [60174, 138412], [60175, 138952], [60177, 138965], [60178, 139029],
- [29080, 60179], [60181, 139333], [27113, 60182], [14024, 60183],
- [60184, 139900], [60185, 140247], [60186, 140282], [60187, 141098],
- [60188, 141425], [60189, 141647], [60191, 141671], [60192, 141715],
- [60193, 142037], [60195, 142056], [60197, 142094], [60199, 142143],
- [60202, 142412], [60204, 142472], [60205, 142519], [60206, 154600],
- [60207, 142600], [60208, 142610], [60209, 142775], [60210, 142741],
- [60211, 142914], [60212, 143220], [60213, 143308], [60214, 143411],
- [60215, 143462], [60216, 144159], [60217, 144350], [60222, 144743],
- [60223, 144883], [60227, 144922], [60228, 145174], [22709, 60231],
- [60234, 146087], [60237, 146961], [60238, 147129], [60243, 147737],
- [60245, 148206], [60246, 148237], [60248, 148276], [60249, 148374],
- [60258, 148484], [60259, 148694], [22408, 60260], [60261, 149108],
- [60263, 149295], [60271, 149522], [60272, 149755], [60273, 150037],
- [60275, 150208], [22885, 60277], [60279, 151430], [60282, 151596],
- [22335, 60284], [60286, 152217], [60287, 152601], [60291, 152646],
- [60292, 152686], [60296, 152895], [60298, 152926], [60300, 152930],
- [60301, 152934], [60302, 153543], [60304, 153693], [60309, 153859],
- [60312, 154286], [60313, 154505], [60314, 154630], [22433, 60316],
- [29009, 60317], [60319, 155906], [60322, 156082], [60325, 156674],
- [60326, 156746], [60330, 156804], [60334, 156808], [60336, 156946],
- [60338, 157119], [60339, 157365], [22201, 60347], [60349, 157436],
- [13848, 60355], [60357, 157593], [60358, 157806], [60360, 157790],
- [60362, 157895], [60366, 157990], [60368, 158009], [60371, 158202],
- [60373, 158253], [60378, 158260], [60379, 158555], [60383, 158621],
- [60385, 158884], [60388, 159150], [60392, 159819], [60393, 160205],
- [60395, 160384], [60396, 160389], [60399, 160395], [60401, 160486],
- [38047, 60404], [60405, 160848], [14009, 60416], [60424, 161740],
- [60425, 161880], [22230, 60426], [60435, 162269], [60441, 162301],
- [60442, 162314], [60443, 162571], [60444, 163174], [60448, 163849],
- [60459, 163875], [60463, 163912], [60466, 163971], [60479, 163984],
- [60480, 164084], [60481, 164142], [60483, 164175], [60485, 164271],
- [60486, 164378], [60487, 164614], [60488, 164655], [60489, 164746],
- [60491, 164968], [60492, 165546], [25574, 60494], [60495, 166230],
- [60498, 166328], [60500, 166375], [60502, 166376], [60503, 166726],
- [60504, 166868], [60506, 166921], [60508, 167877], [60509, 168172],
- [60511, 168208], [60512, 168252], [15863, 60513], [60514, 168286],
- [60515, 150218], [36816, 60516], [60519, 169191], [60521, 169392],
- [60522, 169400], [60523, 169778], [60524, 170193], [60525, 170313],
- [60526, 170346], [60527, 170435], [60528, 170536], [60529, 170766],
- [60530, 171354], [60531, 171419], [32415, 60532], [60533, 171768],
- [60534, 171811], [19620, 60535], [38215, 60536], [60537, 172691],
- [29090, 60538], [60539, 172799], [60542, 173515], [19868, 60543],
- [60544, 134300], [36798, 60545], [36794, 60547], [60548, 140464],
- [36793, 60549], [60550, 150163], [20202, 60555], [60557, 166700],
- [36480, 60560], [60561, 137205], [60563, 166764], [60564, 166809],
- [60566, 157359], [60568, 161365], [60570, 153141], [60571, 153942],
- [20122, 60572], [60573, 155265], [60576, 134765], [60579, 147080],
- [60580, 150686], [60583, 137206], [60584, 137339], [60587, 154698],
- [60589, 152337], [15814, 60590], [60596, 155352], [19996, 60600],
- [60601, 135146], [60602, 134473], [60603, 145082], [60638, 151880],
- [21982, 60644], [34694, 60672], [60676, 135361], [60679, 149254],
- [23440, 60680], [60682, 157843], [60684, 141044], [60685, 163119],
- [60686, 147875], [60687, 163187], [60688, 159440], [60689, 160438],
- [60691, 135641], [60693, 146684], [60694, 173737], [60695, 134828],
- [60698, 138402], [60700, 151490], [60702, 135147], [60706, 142752],
- [60710, 135148], [60711, 134666], [60714, 135149], [60717, 135559],
- [19994, 60721], [19972, 60722], [23309, 60724], [13996, 60727],
- [21373, 60729], [13989, 60730], [22682, 60732], [60733, 150382],
- [22442, 60736], [60737, 154261], [60738, 133497], [60741, 140389],
- [60746, 146686], [60747, 171824], [60749, 151465], [60750, 169374],
- [60753, 146870], [60755, 157619], [60756, 145184], [60759, 147191],
- [60760, 146988], [60785, 143578], [60789, 135849], [22439, 60790],
- [60791, 149859], [60794, 159918], [60801, 137068], [60806, 160100],
- [60809, 159010], [60810, 150242], [39963, 60837], [60838, 149822],
- [15878, 60846], [60881, 159011], [60887, 132092], [60891, 146685],
- [60893, 149785], [22394, 60904], [21722, 60912], [29050, 60928],
- [60949, 150135], [60955, 166490], [60962, 194624], [60976, 137275],
- [61000, 155993], [61014, 144373], [61019, 166850], [61024, 138566],
- [61054, 159441], [13877, 61065], [61084, 166701], [21024, 61088],
- [15384, 61089], [61090, 146631], [61091, 155351], [61092, 161366],
- [61093, 152881], [61094, 137540], [61096, 170243], [61097, 159196],
- [61098, 159917], [61100, 156077], [61101, 166415], [61102, 145015],
- [61103, 131310], [61104, 157766], [61105, 151310], [17762, 61106],
- [23327, 61107], [61108, 156492], [40784, 61109], [40614, 61110],
- [61111, 156267], [20962, 57415], [21314, 57416], [26285, 57520],
- [22620, 57547], [21843, 57566], [15749, 57594], [24928, 57608],
- [18606, 57668], [38845, 57676], [57693, 137335], [24755, 57703],
- [33828, 57711], [38932, 57748], [57749, 147596], [57764, 143486],
- [57787, 138813], [15147, 57798], [15666, 57824], [57857, 132021],
- [28801, 57944], [23708, 57959], [58017, 132547], [14128, 58028],
- [58096, 136054], [58097, 150034], [58111, 166699], [58112, 155779],
- [256, 62233], [193, 62234], [461, 62235], [192, 62236], [274, 62237],
- [201, 62238], [282, 62239], [200, 62240], [332, 62241], [211, 62242],
- [465, 62243], [210, 62244], 62245, [7870, 62246], 62247, [7872, 62248],
- [202, 62249], [257, 62250], [225, 62251], [462, 62252], [224, 62253],
- [593, 62254], [275, 62255], [233, 62256], [283, 62257], [232, 62258],
- [299, 62259], [237, 62260], [464, 62261], [236, 62262], [333, 62263],
- [243, 62264], [466, 62265], [242, 62266], [363, 62267], [250, 62268],
- [468, 62269], [249, 62270], [470, 62271], [472, 62272], [474, 62273],
- [476, 62274], [252, 62275], 62276, [7871, 62277], 62278, [7873, 62279],
- [234, 62280], [609, 62281], [643, 63551], [592, 63552], [603, 63553],
- [596, 63554], [629, 63555], [339, 63556], [248, 63557], [331, 63558],
- [650, 63559], [618, 63560], {f: 2, c: 62282}, [11933, 63530],
- [11974, 63539], [12003, 63547], 20539, 28158, [62841, 171123], 62842,
- [15817, 62843], 34959, [62845, 147790], 28791, 23797, [19232, 62848],
- [62849, 152013], [13657, 62850], [62851, 154928], 24866, [62853, 166450],
- 36775, 37366, 29073, 26393, 29626, [62859, 144001], [62860, 172295],
- [15499, 62861], [62862, 137600], [19216, 62863], 30948, 29698, 20910,
- [62867, 165647], [16393, 62868], 27235, [62870, 172730], [16931, 62871],
- 34319, 31274, [62875, 170311], [62876, 166634], 38741, 28749, 21284,
- [62880, 139390], 37876, 30425, [62883, 166371], 62884, 30685, 20131, 20464,
- 20668, 20015, 20247, 62891, 21556, 32139, 22674, 22736, [62896, 138678],
- 24210, 24217, 24514, [62900, 141074], 25995, [62902, 144377], 26905, 27203,
- [62905, 146531], 27903, 29184, [62909, 148741], 29580, [16091, 62911],
- [62912, 150035], 23317, 29881, 35715, [62916, 154788], [62917, 153237],
- 31379, 31724, 31939, 32364, 33528, 34199, 62924, 34960, 62926, 36537,
- 62928, 36815, 34143, 39392, 37409, 62933, [62934, 167353], [62935, 136255],
- [16497, 62936], [17058, 62937], 23066, 39016, 26475, [17014, 62944], 22333,
- 34262, [62948, 149883], 33471, [62950, 160013], [19585, 62951],
- [62952, 159092], 23931, [62954, 158485], [62955, 159678], {f: 2, c: 62956},
- 23446, 62959, 32347],
- 'Adobe-GB1': [{f: 95, c: 32}, {f: 3, c: 12288}, [183, 12539], 713, 711, 168,
- 12291, 12293, 8212, 65374, 8214, [8230, 8943], {f: 2, c: 8216},
- {f: 2, c: 8220}, {f: 2, c: 12308}, {f: 8, c: 12296}, {f: 2, c: 12310},
- {f: 2, c: 12304}, 177, 215, 247, 8758, {f: 2, c: 8743}, 8721, 8719, 8746,
- 8745, 8712, 8759, 8730, 8869, 8741, 8736, 8978, 8857, 8747, 8750, 8801,
- 8780, 8776, 8765, 8733, 8800, {f: 2, c: 8814}, {f: 2, c: 8804}, 8734, 8757,
- 8756, 9794, 9792, 176, {f: 2, c: 8242}, 8451, 65284, 164, {f: 2, c: 65504},
- 8240, 167, 8470, 9734, 9733, 9675, 9679, 9678, 9671, 9670, 9633, 9632,
- 9651, 9650, 8251, 8594, {f: 2, c: 8592}, 8595, 12307, {f: 20, c: 9352},
- {f: 20, c: 9332}, {f: 10, c: 9312}, {f: 10, c: 12832}, {f: 12, c: 8544},
- {f: 3, c: 65281}, 65509, {f: 89, c: 65285}, 65507, {f: 83, c: 12353},
- {f: 86, c: 12449}, {f: 17, c: 913}, {f: 7, c: 931}, {f: 17, c: 945},
- {f: 7, c: 963}, {f: 7, c: 59277}, {f: 2, c: 65077}, {f: 2, c: 65081},
- {f: 2, c: 65087}, {f: 2, c: 65085}, {f: 4, c: 65089}, {f: 2, c: 59284},
- {f: 2, c: 65083}, {f: 2, c: 65079}, 65073, 59286, {f: 2, c: 65075},
- {f: 6, c: 1040}, 1025, {f: 32, c: 1046}, 1105, {f: 26, c: 1078}, 257, 225,
- 462, 224, 275, 233, 283, 232, 299, 237, 464, 236, 333, 243, 466, 242, 363,
- 250, 468, 249, 470, 472, 474, 476, 252, 234, 593, 7743, 324, 328, 505, 609,
- {f: 37, c: 12549}, 0, {f: 76, c: 9472}, {s: 126}, 21834, 38463, 22467,
- 25384, 21710, 21769, 21696, 30353, 30284, 34108, 30702, 33406, 30861,
- 29233, 38552, 38797, 27688, 23433, 20474, 25353, 26263, 23736, 33018,
- 26696, 32942, 26114, 30414, 20985, 25942, 29100, 32753, 34948, 20658,
- 22885, 25034, 28595, 33453, 25420, 25170, 21485, 21543, 31494,
- [12043, 20843], 30116, 24052, 25300, 36299, 38774, 25226, 32793, 22365,
- 38712, 32610, 29240, [12137, 30333], 26575, 30334, 25670, 20336, 36133,
- 25308, 31255, 26001, 29677, 25644, 25203, 33324, 39041, 26495, 29256,
- 25198, 25292, 20276, 29923, 21322, 21150, 32458, 37030, 24110, 26758,
- 27036, 33152, 32465, 26834, 30917, 34444, 38225, 20621, 35876, 33502,
- 32990, 21253, 35090, 21093, 34180, 38649, 20445, 22561, 39281, 23453,
- 25265, 25253, 26292, 35961, 40077, 29190, 26479, 30865, 24754, 21329,
- 21271, 36744, 32972, 36125, 38049, 20493, 29384, 22791, 24811, 28953,
- 34987, 22868, 33519, 26412, 31528, 23849, 32503, 29997, 27893, 36454,
- 36856, 36924, [12240, 40763], [12112, 27604], 37145, 31508, 24444, 30887,
- 34006, 34109, 27605, 27609, 27606, 24065, 24199, 30201, 38381, 25949,
- 24330, 24517, 36767, 22721, 33218, 36991, 38491, 38829, 36793, 32534,
- 36140, 25153, 20415, 21464, 21342, {f: 2, c: 36776}, 36779, 36941, 26631,
- 24426, 33176, 34920, 40150, 24971, 21035, 30250, 24428, 25996, 28626,
- 28392, 23486, 25672, 20853, 20912, 26564, 19993, 31177, 39292, 28851,
- 30149, 24182, 29627, 33760, 25773, 25320, 38069, 27874, 21338, 21187,
- 25615, 38082, 31636, 20271, 24091, 33334, 33046, 33162, 28196, 27850,
- 39539, 25429, [12056, 21340], 21754, 34917, 22496, 19981, 24067, 27493,
- 31807, 37096, 24598, 25830, 29468, 35009, 26448, 25165, 36130, 30572,
- 36393, 37319, 24425, 33756, 34081, 39184, 21442, 34453, 27531, 24813,
- 24808, 28799, 33485, 33329, 20179, 27815, 34255, 25805, 31961, 27133,
- 26361, 33609, 21397, 31574, 20391, 20876, 27979, 23618, 36461, 25554,
- 21449, 33580, 33590, 26597, 30900, 25661, 23519, 23700, 24046, 35815,
- 25286, 26612, 35962, 25600, 25530, 34633, 39307, 35863, 32544, 38130,
- 20135, 38416, 39076, 26124, 29462, 22330, 23581, 24120, 38271, 20607,
- 32928, [12058, 21378], 25950, 30021, 21809, 20513, 36229, 25220, 38046,
- 26397, 22066, 28526, 24034, 21557, 28818, 36710, 25199, 25764, 25507,
- 24443, 28552, 37108, [12162, 33251], [12192, 36784], 23576, 26216, 24561,
- 27785, 38472, 36225, 34924, 25745, 31216, 22478, 27225, 25104, 21576,
- 20056, 31243, 24809, 28548, 35802, 25215, 36894, 39563, 31204, 21507,
- 30196, 25345, 21273, 27744, 36831, 24347, 39536, 32827, 40831, 20360,
- 23610, [12186, 36196], 32709, 26021, 28861, 20805, 20914, [12173, 34411],
- 23815, 23456, 25277, 37228, 30068, 36364, 31264, 24833, 31609, 20167,
- 32504, 30597, 19985, 33261, 21021, 20986, 27249, 21416, 36487, 38148,
- 38607, 28353, 38500, 26970, 30784, 20648, 30679, 25616, 35302, 22788,
- 25571, 24029, 31359, 26941, 20256, 33337, 21912, 20018, 30126, 31383,
- 24162, 24202, 38383, 21019, 21561, 28810, 25462, 38180, 22402, 26149,
- 26943, 37255, 21767, 28147, 32431, 34850, 25139, 32496, 30133, 33576,
- 30913, 38604, 36766, 24904, 29943, 35789, 27492, 21050, 36176, 27425,
- 32874, 33905, 22257, 21254, 20174, 19995, 20945, 31895, 37259, 31751,
- 20419, 36479, 31713, 31388, 25703, 23828, 20652, 33030, 30209, 31929,
- 28140, 32736, 26449, 23384, [12072, 23544], 30923, 25774, 25619, 25514,
- 25387, 38169, 25645, 36798, 31572, 30249, 25171, [12068, 22823], 21574,
- [12109, 27513], 20643, 25140, 24102, 27526, 20195, 36151, 34955, 24453,
- 36910, 24608, 32829, 25285, 20025, 21333, 37112, 25528, 32966, 26086,
- 27694, 20294, 24814, 28129, 35806, 24377, 34507, 24403, 25377, 20826,
- 33633, 26723, [12049, 20992], 25443, 36424, 20498, 23707, 31095, 23548,
- 21040, 31291, 24764, 36947, 30423, 24503, 24471, 30340, 36460, 28783,
- 30331, 31561, 30634, 20979, 37011, 22564, 20302, 28404, 36842, 25932,
- 31515, 29380, 28068, 32735, 23265, 25269, 24213, 22320, 33922, 31532,
- 24093, 24351, 36882, 32532, 39072, 25474, 28359, 30872, 28857, 20856,
- 38747, 22443, 30005, 20291, 30008, 24215, 24806, 22880, 28096, 27583,
- 30857, 21500, 38613, 20939, 20993, 25481, 21514, 38035, 35843, 36300,
- 29241, 30879, 34678, 36845, 35853, 21472, 19969, 30447, 21486, 38025,
- 39030, [12237, 40718], 38189, 23450, 35746, 20002, 19996, 20908, 33891,
- 25026, 21160, 26635, 20375, 24683, 20923, 27934, 20828, 25238,
- [12099, 26007], 38497, [12182, 35910], 36887, 30168, 37117, 30563, 27602,
- 29322, 29420, 35835, 22581, 30585, 36172, 26460, 38208, 32922, 24230,
- 28193, 22930, 31471, 30701, 38203, 27573, 26029, 32526, 22534, 20817,
- 38431, 23545, 22697, 21544, 36466, 25958, 39039, 22244, 38045, 30462,
- 36929, 25479, 21702, 22810, 22842, 22427, 36530, 26421, 36346, 33333,
- 21057, 24816, 22549, 34558, 23784, 40517, 20420, 39069, 35769, 23077,
- 24694, 21380, 25212, 36943, 37122, 39295, 24681, [12157, 32780],
- [12041, 20799], [12159, 32819], 23572, 39285, 27953, [12038, 20108], 36144,
- 21457, 32602, 31567, 20240, 20047, 38400, 27861, 29648, 34281, 24070,
- 30058, 32763, 27146, 30718, 38034, 32321, 20961, 28902, 21453, 36820,
- 33539, 36137, 29359, 39277, 27867, 22346, 33459, [12101, 26041], 32938,
- 25151, 38450, 22952, 20223, 35775, 32442, 25918, 33778, [12206, 38750],
- 21857, 39134, 32933, 21290, 35837, 21536, 32954, 24223, 27832, 36153,
- 33452, 37210, 21545, 27675, 20998, 32439, 22367, 28954, 27774, 31881,
- 22859, 20221, 24575, 24868, 31914, 20016, 23553, 26539, 34562, 23792,
- 38155, 39118, 30127, 28925, 36898, 20911, 32541, 35773, 22857, 20964,
- 20315, 21542, 22827, 25975, 32932, 23413, 25206, 25282, 36752, 24133,
- 27679, 31526, 20239, 20440, 26381, 28014, 28074, 31119, 34993, 24343,
- 29995, 25242, 36741, 20463, 37340, 26023, 33071, 33105, 24220, 33104,
- 36212, 21103, 35206, 36171, 22797, 20613, 20184, [12201, 38428],
- [12119, 29238], 33145, 36127, 23500, 35747, 38468, 22919, 32538, 21648,
- 22134, 22030, 35813, 25913, 27010, 38041, 30422, 28297, [12082, 24178],
- [12130, 29976], 26438, 26577, 31487, 32925, 36214, 24863, 31174, 25954,
- 36195, 20872, 21018, 38050, 32568, 32923, 32434, 23703, 28207, 26464,
- 31705, 30347, [12220, 39640], 33167, 32660, 31957, 25630, 38224, 31295,
- 21578, 21733, 27468, 25601, [12093, 25096], 40509, 33011, 30105, 21106,
- [12208, 38761], 33883, 26684, 34532, 38401, 38548, 38124, 20010, 21508,
- 32473, 26681, 36319, 32789, 26356, 24218, 32697, 22466, 32831, 26775,
- [12079, 24037], 25915, 21151, 24685, 40858, 20379, 36524, 20844, 23467,
- [12088, 24339], 24041, 27742, 25329, 36129, 20849, 38057, 21246, 27807,
- 33503, 29399, 22434, 26500, 36141, 22815, 36764, 33735, 21653, 31629,
- 20272, 27837, 23396, 22993, [12238, 40723], 21476, 34506, [12219, 39592],
- [12181, 35895], 32929, 25925, 39038, 22266, 38599, 21038, [12128, 29916],
- 21072, 23521, 25346, 35074, 20054, 25296, 24618, 26874, 20851, 23448,
- 20896, 35266, 31649, 39302, 32592, 24815, 28748, 36143, 20809,
- [12084, 24191], 36891, 29808, 35268, 22317, 30789, 24402, 40863, 38394,
- 36712, [12225, 39740], 35809, 30328, 26690, 26588, 36330, 36149, 21053,
- 36746, 28378, 26829, 38149, 37101, 22269, 26524, 35065, 36807, 21704,
- 39608, 23401, 28023, 27686, 20133, 23475, 39559, 37219, 25000, 37039,
- 38889, 21547, 28085, 23506, 20989, 21898, 32597, 32752, 25788, 25421,
- 26097, 25022, 24717, 28938, 27735, 27721, 22831, 26477, 33322, 22741,
- 22158, 35946, 27627, 37085, 22909, 32791, 21495, 28009, 21621, 21917,
- 33655, 33743, 26680, [12146, 31166], 21644, 20309, 21512, 30418, 35977,
- 38402, 27827, 28088, 36203, 35088, 40548, 36154, 22079, [12234, 40657],
- 30165, 24456, 29408, 24680, 21756, 20136, 27178, 34913, 24658, 36720,
- 21700, 28888, 34425, 40511, 27946, 23439, 24344, 32418, 21897, 20399,
- 29492, 21564, 21402, 20505, 21518, 21628, 20046, 24573, 29786, 22774,
- 33899, 32993, 34676, 29392, 31946, 28246, 24359, 34382, 21804, 25252,
- 20114, 27818, 25143, 33457, 21719, 21326, 29502, 28369, 30011, 21010,
- 21270, 35805, 27088, 24458, 24576, 28142, 22351, 27426, 29615, 26707,
- 36824, 32531, 25442, 24739, 21796, 30186, 35938, 28949, 28067, 23462,
- 24187, 33618, 24908, 40644, 30970, 34647, 31783, 30343, 20976, 24822,
- 29004, 26179, 24140, 24653, 35854, 28784, 25381, 36745, 24509, 24674,
- 34516, 22238, 27585, 24724, 24935, 21321, 24800, 26214, 36159, 31229,
- 20250, 28905, 27719, 35763, 35826, 32472, 33636, 26127, 23130, 39746,
- 27985, 28151, 35905, 27963, 20249, [12117, 28779], 33719, 25110, 24785,
- 38669, 36135, 31096, 20987, 22334, 22522, 26426, 30072, 31293, 31215,
- 31637, 32908, 39269, 36857, 28608, 35749, 40481, 23020, 32489, 32521,
- 21513, 26497, 26840, 36753, 31821, 38598, 21450, 24613, 30142, 27762,
- 21363, 23241, 32423, 25380, [12047, 20960], 33034, [12080, 24049], 34015,
- 25216, 20864, 23395, 20238, 31085, 21058, 24760, 27982, 23492, 23490,
- 35745, 35760, 26082, 24524, 38469, 22931, 32487, 32426, 22025, 26551,
- 22841, 20339, 23478, 21152, 33626, 39050, 36158, 30002, 38078, 20551,
- 31292, 20215, 26550, 39550, 23233, 27516, 30417, 22362, 23574, 31546,
- 38388, 29006, 20860, 32937, 33392, 22904, 32516, 33575, 26816, 26604,
- 30897, 30839, 25315, 25441, 31616, 20461, 21098, 20943, 33616, 27099,
- 37492, 36341, 36145, 35265, 38190, 31661, 20214, 20581, 33328, 21073,
- 39279, 28176, 28293, 28071, 24314, 20725, 23004, 23558, 27974, 27743,
- 30086, 33931, 26728, 22870, 35762, 21280, 37233, 38477, 34121, 26898,
- 30977, 28966, 33014, 20132, 37066, 27975, 39556, 23047, 22204, 25605,
- 38128, 30699, 20389, 33050, 29409, [12179, 35282], 39290, 32564, 32478,
- 21119, 25945, 37237, 36735, 36739, 21483, 31382, 25581, 25509, 30342,
- 31224, 34903, 38454, 25130, 21163, 33410, 26708, 26480, 25463, 30571,
- 31469, 27905, 32467, 35299, 22992, 25106, 34249, 33445, 30028, 20511,
- 20171, 30117, 35819, 23626, [12081, 24062], 31563, [12100, 26020],
- [12198, 37329], 20170, 27941, 35167, 32039, 38182, 20165, 35880, 36827,
- 38771, 26187, 31105, 36817, 28908, 28024, 23613, 21170, 33606, 20834,
- 33550, 30555, 26230, 40120, 20140, 24778, 31934, 31923, 32463, 20117,
- 35686, 26223, 39048, 38745, 22659, 25964, 38236, 24452, 30153, 38742,
- 31455, 31454, 20928, 28847, 31384, 25578, 31350, 32416, 29590,
- [12210, 38893], 20037, 28792, 20061, 37202, 21417, 25937, 26087,
- [12165, 33276], 33285, 21646, 23601, 30106, 38816, 25304, 29401, 30141,
- 23621, 39545, 33738, 23616, 21632, 30697, 20030, 27822, 32858, 25298,
- 25454, 24040, 20855, 36317, 36382, 38191, 20465, 21477, 24807, 28844,
- 21095, 25424, 40515, 23071, 20518, 30519, 21367, 32482, 25733, 25899,
- 25225, 25496, 20500, 29237, 35273, 20915, 35776, 32477, 22343, 33740,
- 38055, 20891, 21531, 23803, 20426, 31459, 27994, 37089, 39567, 21888,
- 21654, 21345, 21679, 24320, 25577, 26999, 20975, 24936, 21002, 22570,
- 21208, 22350, 30733, 30475, 24247, 24951, 31968, 25179, 25239, 20130,
- 28821, 32771, 25335, 28900, 38752, 22391, 33499, 26607, 26869, 30933,
- 39063, 31185, 22771, 21683, 21487, 28212, 20811, 21051, 23458, 35838,
- 32943, 21827, 22438, 24691, 22353, 21549, 31354, 24656, 23380, 25511,
- 25248, [12061, 21475], 25187, 23495, 26543, 21741, 31391, 33510, 37239,
- 24211, 35044, 22840, 22446, 25358, 36328, 33007, 22359, 31607, 20393,
- 24555, 23485, 27454, 21281, 31568, 29378, 26694, 30719, 30518, 26103,
- 20917, 20111, 30420, 23743, 31397, 33909, 22862, 39745, 20608, 39304,
- 24871, 28291, 22372, 26118, 25414, 22256, 25324, 25193, 24275, 38420,
- 22403, 25289, 21895, 34593, 33098, 36771, 21862, 33713, 26469, 36182,
- 34013, 23146, 26639, 25318, 31726, 38417, 20848, 28572, 35888, 25597,
- 35272, 25042, 32518, 28866, 28389, 29701, 27028, 29436, 24266, 37070,
- 26391, 28010, 25438, 21171, 29282, [12156, 32769], 20332, 23013, 37226,
- 28889, 28061, 21202, 20048, 38647, 38253, 34174, 30922, 32047, 20769,
- 22418, 25794, 32907, 31867, 27882, 26865, 26974, 20919, 21400, 26792,
- 29313, 40654, 31729, 29432, 31163, 28435, 29702, 26446, [12197, 37324],
- 40100, 31036, 33673, 33620, 21519, 26647, 20029, 21385, 21169, 30782,
- 21382, 21033, 20616, 20363, 20432, 30178, [12148, 31435], 31890, 27813,
- [12202, 38582], [12050, 21147], 29827, 21737, 20457, 32852, 33714, 36830,
- 38256, 24265, 24604, 28063, 24088, 25947, 33080, 38142, 24651, 28860,
- 32451, 31918, 20937, 26753, 31921, 33391, 20004, 36742, 37327, 26238,
- 20142, 35845, 25769, 32842, 20698, 30103, 29134, 23525, 36797, 28518,
- 20102, 25730, 38243, 24278, 26009, 21015, 35010, 28872, 21155, 29454,
- 29747, 26519, 30967, 38678, 20020, 37051, 40158, 28107, 20955, 36161,
- 21533, 25294, 29618, 33777, 38646, 40836, 38083, 20278, 32666, 20940,
- 28789, 38517, 23725, 39046, 21478, 20196, 28316, 29705, 27060, 30827,
- 39311, 30041, 21016, 30244, 27969, 26611, 20845, 40857, 32843, 21657,
- 31548, 31423, 38534, 22404, 25314, 38471, 27004, 23044, 25602, 31699,
- 28431, 38475, 33446, 21346, 39045, 24208, 28809, 25523, 21348, 34383,
- 40065, 40595, 30860, 38706, 36335, 36162, [12229, 40575], 28510, 31108,
- 24405, 38470, 25134, 39540, 21525, 38109, 20387, 26053, 23653, 23649,
- 32533, 34385, 27695, 24459, 29575, 28388, 32511, 23782, 25371, 23402,
- 28390, 21365, 20081, 25504, 30053, 25249, 36718, 20262, 20177, 27814,
- 32438, 35770, 33821, 34746, 32599, 36923, 38179, 31657, 39585, 35064,
- 33853, 27931, 39558, 32476, 22920, [12231, 40635], 29595, 30721, 34434,
- 39532, 39554, 22043, 21527, 22475, 20080, 40614, 21334, 36808, 33033,
- 30610, 39314, 34542, 28385, 34067, 26364, 24930, 28459, 35881, 33426,
- 33579, 30450, 27667, 24537, 33725, 29483, 33541, 38170, [12113, 27611],
- [12141, 30683], 38086, 21359, 33538, 20882, 24125, 35980, 36152, 20040,
- 29611, 26522, 26757, 37238, 38665, 29028, 27809, 30473, 23186, 38209,
- 27599, 32654, 26151, 23504, 22969, 23194, 38376, 38391, 20204, 33804,
- 33945, 27308, 30431, 38192, 29467, 26790, 23391, 30511, 37274, 38753,
- 31964, 36855, 35868, 24357, [12150, 31859], 31192, 35269, 27852, 34588,
- 23494, 24130, 26825, 30496, 32501, 20885, 20813, 21193, 23081, 32517,
- [12207, 38754], 33495, 25551, 30596, 34256, 31186, 28218, 24217, 22937,
- 34065, 28781, 27665, 25279, [12139, 30399], 25935, 24751, 38397, 26126,
- 34719, 40483, 38125, 21517, 21629, 35884, {f: 2, c: 25720}, 34321, 27169,
- 33180, 30952, 25705, 39764, 25273, 26411, 33707, 22696, 40664, 27819,
- 28448, 23518, 38476, 35851, 29279, 26576, 25287, 29281, 20137, 22982,
- 27597, 22675, 26286, 24149, 21215, 24917, [12106, 26408], [12140, 30446],
- 30566, 29287, 31302, 25343, 21738, 21584, 38048, 37027, 23068, 32435,
- 27670, 20035, 22902, 32784, 22856, 21335, 30007, 38590, 22218, 25376,
- 33041, 24700, 38393, 28118, 21602, 39297, 20869, 23273, 33021, 22958,
- 38675, 20522, 27877, 23612, 25311, 20320, 21311, 33147, 36870, 28346,
- 34091, 25288, 24180, 30910, 25781, 25467, 24565, 23064, 37247, 40479,
- 23615, 25423, 32834, 23421, 21870, 38218, 38221, 28037, 24744, 26592,
- 29406, 20957, 23425, 25319, 27870, [12124, 29275], 25197, 38062, 32445,
- 33043, 27987, 20892, 24324, 22900, 21162, 24594, [12069, 22899], 26262,
- 34384, 30111, 25386, 25062, 31983, 35834, 21734, 27431, 40485, 27572,
- 34261, 21589, 20598, 27812, 21866, 36276, 29228, 24085, 24597, 29750,
- 25293, 25490, 29260, 24472, 28227, 27966, 25856, 28504, 30424, 30928,
- 30460, 30036, 21028, 21467, 20051, 24222, 26049, 32810, 32982, 25243,
- 21638, 21032, 28846, 34957, 36305, 27873, 21624, 32986, 22521, 35060,
- 36180, 38506, 37197, 20329, 27803, 21943, 30406, 30768, 25256, 28921,
- 28558, 24429, 34028, 26842, 30844, 31735, 33192, 26379, 40527, 25447,
- 30896, 22383, 30738, 38713, 25209, 25259, 21128, 29749, 27607, 21860,
- 33086, 30130, [12138, 30382], 21305, 30174, 20731, 23617, 35692, 31687,
- 20559, [12122, 29255], 39575, 39128, 28418, 29922, 31080, 25735, 30629,
- 25340, 39057, 36139, 21697, 32856, 20050, 22378, 33529, 33805, 24179,
- 20973, 29942, 35780, 23631, 22369, 27900, 39047, 23110, 30772, 39748,
- 36843, 31893, 21078, 25169, 38138, 20166, 33670, 33889, 33769, 33970,
- 22484, 26420, 22275, 26222, 28006, 35889, 26333, 28689, 26399, 27450,
- 26646, 25114, 22971, 19971, 20932, 28422, 26578, 27791, 20854, 26827,
- 22855, 27495, 30054, 23822, 33040, 40784, 26071, 31048, 31041, 39569,
- 36215, 23682, 20062, 20225, 21551, 22865, 30732, 22120, [12115, 27668],
- 36804, 24323, 27773, 27875, 35755, 25488, 24688, 27965, 29301, 25190,
- 38030, 38085, 21315, 36801, 31614, 20191, 35878, 20094, 40660, 38065,
- 38067, 21069, 28508, 36963, 27973, 35892, 22545, 23884, [12107, 27424],
- 27465, 26538, 21595, 33108, 32652, 22681, 34103, 24378, 25250, 27207,
- 38201, 25970, 24708, 26725, 30631, 20052, 20392, 24039, 38808, 25772,
- 32728, 23789, 20431, 31373, 20999, 33540, 19988, 24623, 31363, 38054,
- 20405, 20146, 31206, 29748, 21220, 33465, 25810, 31165, 23517, 27777,
- 38738, 36731, 27682, 20542, 21375, 28165, 25806, 26228, 27696, 24773,
- 39031, 35831, 24198, 29756, 31351, 31179, 19992, 37041, 29699, 27714,
- 22234, 37195, 27845, 36235, 21306, 34502, 26354, 36527, 23624, 39537,
- 28192, 21462, 23094, 40843, 36259, 21435, 22280, 39079, 26435, 37275,
- 27849, 20840, 30154, 25331, [12125, 29356], 21048, 21149, 32570, 28820,
- 30264, 21364, 40522, 27063, 30830, 38592, 35033, 32676, 28982, 29123,
- 20873, 26579, 29924, 22756, 25880, 22199, 35753, 39286, 25200, 32469,
- 24825, 28909, 22764, 20161, [12040, 20154], 24525, 38887, 20219, 35748,
- 20995, 22922, 32427, 25172, 20173, [12103, 26085], 25102, 33592, 33993,
- 33635, 34701, 29076, 28342, 23481, 32466, 20887, 25545, 26580,
- [12161, 32905], 33593, 34837, 20754, 23418, 22914, 36785, 20083, 27741,
- [12042, 20837], 35109, 36719, 38446, 34122, 29790, 38160, 38384, 28070,
- 33509, 24369, 25746, 27922, 33832, 33134, 40131, 22622, 36187, 19977,
- 21441, 20254, 25955, 26705, 21971, 20007, 25620, 39578, 25195, 23234,
- 29791, [12170, 33394], 28073, 26862, 20711, 33678, 30722, 26432, 21049,
- 27801, 32433, 20667, 21861, 29022, 31579, 26194, 29642, 33515, 26441,
- [12077, 23665], 21024, 29053, 34923, 38378, 38485, 25797, 36193, 33203,
- 21892, 27733, 25159, 32558, 22674, 20260, 21830, 36175, 26188, 19978,
- 23578, 35059, 26786, 25422, 31245, 28903, 33421, 21242, 38902, 23569,
- 21736, 37045, 32461, 22882, 36170, 34503, [12166, 33292], 33293, 36198,
- 25668, 23556, 24913, 28041, 31038, 35774, 30775, 30003, 21627, 20280,
- [12189, 36523], 28145, 23072, 32453, 31070, 27784, 23457, 23158, 29978,
- 32958, 24910, 28183, 22768, [12131, 29983], 29989, 29298, 21319, 32499,
- 30465, 30427, 21097, 32988, 22307, 24072, 22833, 29422, 26045, 28287,
- 35799, [12075, 23608], 34417, [12055, 21313], [12143, 30707], 25342, 26102,
- 20160, [12215, 39135], 34432, 23454, 35782, 21490, [12142, 30690], 20351,
- 23630, 39542, 22987, 24335, [12144, 31034], [12064, 22763], 19990, 26623,
- 20107, 25325, 35475, 36893, 21183, 26159, 21980, 22124, 36866, 20181,
- 20365, 37322, 39280, [12114, 27663], 24066, 24643, 23460, 35270, 35797,
- 25910, [12095, 25163], [12216, 39318], 23432, 23551, 25480, 21806, 21463,
- 30246, 20861, 34092, 26530, 26803, 27530, 25234, 36755, 21460, 33298,
- 28113, 30095, 20070, 36174, 23408, 29087, 34223, 26257, 26329, 32626,
- 34560, [12233, 40653], [12239, 40736], 23646, 26415, 36848, 26641, 26463,
- 25101, 31446, 22661, 24246, 25968, 28465, 24661, 21047, 32781, 25684,
- 34928, 29993, 24069, 26643, 25332, 38684, 21452, 29245, 35841,
- [12116, 27700], 30561, 31246, 21550, 30636, 39034, 33308, 35828, 30805,
- 26388, 28865, 26031, 25749, 22070, 24605, 31169, 21496, 19997, 27515,
- 32902, 23546, 21987, 22235, 20282, 20284, 39282, 24051, 26494, 32824,
- 24578, 39042, 36865, 23435, 35772, 35829, 25628, 33368, 25822, 22013,
- 33487, 37221, 20439, 32032, 36895, 31903, 20723, 22609, 28335, 23487,
- 35785, 32899, 37240, 33948, 31639, 34429, 38539, 38543, 32485, 39635,
- 30862, 23681, 31319, 36930, 38567, 31071, 23385, 25439, 31499, 34001,
- 26797, 21766, 32553, 29712, 32034, 38145, 25152, 22604, 20182, 23427,
- 22905, 22612, 29549, 25374, 36427, 36367, 32974, 33492, 25260, 21488,
- 27888, 37214, 22826, 24577, 27760, 22349, 25674, 36138, 30251, 28393,
- 22363, 27264, 30192, 28525, 35885, 35848, 22374, 27631, 34962, 30899,
- 25506, 21497, 28845, 27748, 22616, 25642, 22530, 26848, 33179, 21776,
- 31958, 20504, 36538, 28108, 36255, 28907, 25487, 28059, 28372, 32486,
- 33796, 26691, 36867, 28120, 38518, 35752, 22871, 29305, 34276, 33150,
- 30140, 35466, 26799, 21076, 36386, 38161, 25552, 39064, 36420, 21884,
- 20307, 26367, 22159, 24789, 28053, 21059, 23625, 22825, 28155, 22635,
- [12133, 30000], 29980, 24684, 33300, 33094, 25361, 26465, 36834, 30522,
- 36339, 36148, 38081, 24086, 21381, 21548, 28867, 27712, 24311, 20572,
- 20141, 24237, 25402, 33351, 36890, 26704, 37230, 30643, 21516, 38108,
- 24420, 31461, 26742, 25413, 31570, 32479, 30171, 20599, 25237, 22836,
- 36879, 20984, 31171, 31361, 22270, 24466, 36884, 28034, 23648,
- [12063, 22303], 21520, 20820, 28237, 22242, 25512, 39059, 33151, 34581,
- 35114, 36864, 21534, 23663, 33216, 25302, 25176, 33073, 40501, 38464,
- 39534, 39548, 26925, 22949, 25299, 21822, 25366, 21703, 34521, 27964,
- 23043, [12129, 29926], 34972, 27498, 22806, 35916, 24367, 28286, 29609,
- 39037, 20024, 28919, 23436, 30871, 25405, 26202, 30358, 24779, 23451,
- 23113, 19975, 33109, 27754, 29579, 20129, 26505, [12153, 32593], 24448,
- 26106, 26395, 24536, 22916, 23041, 24013, 24494, 21361, 38886, 36829,
- 26693, 22260, 21807, 24799, 20026, 28493, 32500, 33479, 33806, 22996,
- 20255, 20266, 23614, 32428, 26410, 34074, 21619, 30031, 32963, 21890,
- 39759, 20301, 28205, 35859, 23561, 24944, 21355, 30239, 28201, 34442,
- [12098, 25991], 38395, 32441, 21563, 31283, 32010, 38382, 21985, 32705,
- 29934, 25373, 34583, 28065, 31389, 25105, 26017, 21351, 25569, 27779,
- 24043, 21596, 38056, 20044, 27745, 35820, 23627, [12102, 26080], 33436,
- 26791, 21566, 21556, [12111, 27595], 27494, 20116, 25410, 21320, 33310,
- 20237, 20398, 22366, 25098, 38654, 26212, 29289, 21247, 21153, 24735,
- 35823, 26132, 29081, 26512, 35199, 30802, 30717, 26224, 22075, 21560,
- 38177, 29306, 31232, 24687, 24076, 24713, 33181, [12067, 22805], 24796,
- 29060, 28911, 28330, 27728, 29312, 27268, 34989, 24109, 20064, 23219,
- 21916, 38115, 27927, 31995, 38553, 25103, 32454, 30606, 34430, 21283,
- 38686, 36758, 26247, 23777, 20384, 29421, 19979, 21414, 22799, 21523,
- 25472, 38184, 20808, 20185, 40092, 32420, 21688, 36132, 34900, 33335,
- 38386, 28046, 24358, 23244, 26174, 38505, 29616, 29486, 21439, 33146,
- 39301, 32673, 23466, 38519, 38480, 32447, 30456, 21410, 38262,
- [12217, 39321], 31665, 35140, 28248, 20065, 32724, 31077, 35814, 24819,
- 21709, 20139, 39033, 24055, 27233, 20687, 21521, 35937, 33831, 30813,
- 38660, 21066, 21742, 22179, 38144, 28040, 23477, 28102, 26195,
- [12073, 23567], 23389, 26657, 32918, 21880, 31505, 25928, 26964, 20123,
- 27463, 34638, 38795, 21327, 25375, 25658, 37034, 26012, 32961, 35856,
- 20889, 26800, 21368, 34809, 25032, 27844, 27899, 35874, 23633, 34218,
- 33455, 38156, 27427, [12191, 36763], 26032, 24571, [12092, 24515], 20449,
- 34885, 26143, 33125, 29481, 24826, 20852, 21009, 22411, 24418, 37026,
- [12175, 34892], 37266, 24184, 26447, 24615, 22995, 20804, 20982, 33016,
- 21256, 27769, 38596, 29066, 20241, 20462, 32670, 26429, 21957, 38152,
- 31168, 34966, 32483, 22687, 25100, 38656, 34394, 22040, 39035, 24464,
- 35768, 33988, 37207, 21465, 26093, 24207, 30044, 24676, 32110, 23167,
- 32490, 32493, 36713, 21927, 23459, 24748, 26059, [12126, 29572], 36873,
- 30307, 30505, 32474, 38772, 34203, 23398, [12147, 31348], 38634,
- [12174, 34880], 21195, 29071, 24490, 26092, 35810, 23547, 39535, 24033,
- 27529, 27739, 35757, 35759, 36874, 36805, 21387, 25276, 40486, 40493,
- 21568, 20011, 33469, [12123, 29273], 34460, 23830, 34905, 28079, 38597,
- 21713, 20122, 35766, 28937, 21693, 38409, 28895, 28153, 30416, 20005,
- 30740, 34578, 23721, 24310, [12180, 35328], 39068, 38414, 28814, 27839,
- 22852, 25513, 30524, 34893, 28436, 33395, 22576, 29141, 21388, 30746,
- 38593, 21761, 24422, 28976, 23476, 35866, 39564, 27523, 22830, 40495,
- 31207, 26472, 25196, 20335, 30113, [12154, 32650], 27915, 38451, 27687,
- 20208, 30162, 20859, 26679, 28478, 36992, 33136, 22934, 29814, 25671,
- 23591, 36965, 31377, 35875, 23002, 21676, 33280, 33647, 35201, 32768,
- 26928, 22094, 32822, 29239, 37326, 20918, 20063, 39029, 25494, 19994,
- 21494, 26355, 33099, 22812, 28082, [12032, 19968], 22777, 21307, 25558,
- 38129, 20381, 20234, [12176, 34915], 39056, 22839, 36951, 31227, 20202,
- 33008, 30097, 27778, 23452, 23016, 24413, 26885, 34433, 20506, 24050,
- [12036, 20057], 30691, 20197, 33402, 25233, 26131, [12194, 37009], 23673,
- 20159, 24441, 33222, 36920, 32900, 30123, 20134, 35028, 24847, 27589,
- 24518, 20041, 30410, 28322, 35811, 35758, 35850, 35793, 24322, 32764,
- 32716, 32462, 33589, 33643, 22240, 27575, [12211, 38899], 38452, 23035,
- 21535, 38134, 28139, 23493, 39278, 23609, 24341, 38544, 21360, 33521,
- 27185, 23156, 40560, 24212, 32552, 33721, {f: 2, c: 33828}, 33639, 34631,
- 36814, 36194, 30408, 24433, 39062, 30828, 26144, 21727, 25317, 20323,
- 33219, 30152, 24248, 38605, 36362, 34553, 21647, 27891, 28044, 27704,
- 24703, 21191, [12132, 29992], 24189, 20248, 24736, 24551, 23588, 30001,
- 37038, 38080, 29369, 27833, 28216, [12195, 37193], 26377, 21451, 21491,
- 20305, 37321, 35825, [12060, 21448], 24188, 36802, 28132, 20110, 30402,
- 27014, 34398, 24858, 33286, 20313, 20446, 36926, 40060, 24841, 28189,
- 28180, 38533, 20104, 23089, [12204, 38632], 19982, 23679, 31161, 23431,
- 35821, [12155, 32701], [12127, 29577], 22495, 33419, 37057, 21505, 36935,
- 21947, 23786, 24481, 24840, 27442, 29425, 32946, 35465, 28020, 23507,
- 35029, 39044, 35947, 39533, 40499, 28170, 20900, 20803, 22435, 34945,
- 21407, 25588, 36757, 22253, 21592, 22278, 29503, 28304, 32536, 36828,
- 33489, 24895, 24616, 38498, [12104, 26352], 32422, 36234, 36291, 38053,
- 23731, 31908, [12105, 26376], 24742, 38405, 32792, 20113, 37095, 21248,
- 38504, 20801, 36816, 34164, 37213, 26197, 38901, 23381, 21277, 30776,
- 26434, 26685, 21705, 28798, 23472, 36733, 20877, 22312, 21681, 25874,
- 26242, 36190, 36163, 33039, 33900, 36973, 31967, 20991, 34299, 26531,
- 26089, 28577, 34468, 36481, 22122, 36896, 30338, 28790, 29157, 36131,
- 25321, 21017, 27901, 36156, 24590, 22686, 24974, 26366, 36192, 25166,
- 21939, 28195, 26413, 36711, 38113, 38392, 30504, 26629, 27048, 21643,
- 20045, 28856, 35784, 25688, 25995, 23429, 31364, 20538, 23528, 30651,
- 27617, 35449, 31896, 27838, 30415, 26025, 36759, 23853, 23637, 34360,
- 26632, 21344, 25112, 31449, 28251, 32509, 27167, 31456, 24432, 28467,
- 24352, 25484, 28072, 26454, 19976, 24080, 36134, 20183, 32960, 30260,
- 38556, 25307, 26157, 25214, 27836, 36213, 29031, 32617, 20806, 32903,
- 21484, 36974, 25240, 21746, 34544, 36761, 32773, 38167, 34071, 36825,
- 27993, 29645, 26015, 30495, 29956, 30759, 33275, 36126, 38024, 20390,
- 26517, 30137, 35786, 38663, 25391, 38215, 38453, 33976, 25379, 30529,
- 24449, 29424, 20105, 24596, 25972, 25327, 27491, 25919, 24103, 30151,
- 37073, 35777, 33437, 26525, [12096, 25903], 21553, 34584, 30693, 32930,
- 33026, 27713, 20043, 32455, 32844, 30452, 26893, 27542, 25191, 20540,
- 20356, 22336, 25351, [12108, 27490], 36286, 21482, 26088, 32440, 24535,
- 25370, 25527, [12164, 33267], 33268, 32622, 24092, 23769, 21046, 26234,
- 31209, 31258, 36136, 28825, 30164, 28382, 27835, 31378, 20013, 30405,
- 24544, 38047, 34935, 32456, 31181, 32959, 37325, 20210, 20247,
- [12168, 33311], 21608, 24030, 27954, 35788, 31909, 36724, 32920, 24090,
- 21650, 30385, 23449, 26172, 39588, 29664, 26666, 34523, 26417, 29482,
- 35832, 35803, 36880, [12149, 31481], 28891, 29038, 25284, 30633, 22065,
- 20027, 33879, 26609, 21161, 34496, 36142, 38136, 31569, 20303, 27880,
- 31069, 39547, 25235, [12118, 29226], 25341, 19987, 30742, 36716, 25776,
- 36186, 31686, 26729, 24196, 35013, 22918, 25758, 22766, 29366, 26894,
- 38181, 36861, 36184, 22368, 32512, 35846, 20934, 25417, 25305, 21331,
- 26700, 29730, 33537, 37196, 21828, 30528, 28796, 27978, 20857, 21672,
- 36164, 23039, 28363, 28100, 23388, 32043, 20180, 31869, 28371,
- [12070, 23376], [12163, 33258], 28173, 23383, 39683, 26837, 36394, 23447,
- 32508, 24635, 32437, 37049, [12187, 36208], 22863, 25549, 31199,
- [12188, 36275], 21330, 26063, 31062, 35781, 38459, 32452, 38075, 32386,
- 22068, 37257, 26368, 32618, 23562, 36981, 26152, 24038, 20304, 26590,
- 20570, 20316, 22352, 24231, 20109, 19980, 20800, 19984, 24319, 21317,
- 19989, 20120, 19998, [12224, 39730], 23404, 22121, [12033, 20008], 31162,
- [12035, 20031], [12052, 21269], 20039, 22829, [12120, 29243], 21358, 27664,
- 22239, 32996, 39319, 27603, 30590, 40727, [12034, 20022], 20127, 40720,
- 20060, 20073, 20115, 33416, 23387, 21868, 22031, 20164, 21389, 21405,
- 21411, 21413, 21422, 38757, 36189, [12053, 21274], 21493, 21286, 21294,
- 21310, 36188, 21350, 21347, 20994, 21000, 21006, 21037, 21043,
- {f: 2, c: 21055}, 21068, 21086, 21089, 21084, 33967, 21117, 21122, 21121,
- 21136, 21139, [12044, 20866], 32596, 20155, 20163, 20169, 20162, 20200,
- 20193, 20203, 20190, 20251, 20211, 20258, 20324, 20213, 20261, 20263,
- 20233, 20267, 20318, 20327, 25912, 20314, 20317, 20319, 20311, 20274,
- 20285, 20342, 20340, 20369, 20361, 20355, 20367, 20350, 20347, 20394,
- 20348, 20396, 20372, 20454, 20456, 20458, 20421, 20442, 20451, 20444,
- 20433, 20447, 20472, 20521, 20556, 20467, 20524, 20495, 20526, 20525,
- 20478, 20508, 20492, 20517, 20520, 20606, 20547, 20565, 20552, 20558,
- 20588, 20603, 20645, 20647, 20649, 20666, 20694, 20742, 20717, 20716,
- 20710, 20718, 20743, 20747, 20189, 27709, 20312, 20325, 20430,
- [12245, 40864], 27718, 31860, 20846, 24061, 40649, 39320, 20865, 22804,
- [12051, 21241], 21261, 35335, 21264, 20971, 22809, 20821, [12039, 20128],
- 20822, 20147, 34926, 34980, 20149, 33044, 35026, 31104, 23348, 34819,
- 32696, [12046, 20907], 20913, 20925, 20924, 20935, [12045, 20886], 20898,
- 20901, 35744, {f: 2, c: 35750}, 35754, {f: 2, c: 35764}, 35767,
- {f: 2, c: 35778}, 35787, 35791, 35790, {f: 3, c: 35794}, 35798,
- {f: 2, c: 35800}, 35804, {f: 2, c: 35807}, 35812, {f: 2, c: 35816}, 35822,
- 35824, 35827, 35830, 35833, 35836, {f: 2, c: 35839}, 35842, 35844, 35847,
- 35852, 35855, {f: 2, c: 35857}, {f: 3, c: 35860}, 35865, 35867, 35864,
- 35869, {f: 3, c: 35871}, 35877, 35879, {f: 2, c: 35882}, {f: 2, c: 35886},
- {f: 2, c: 35890}, {f: 2, c: 35893}, [12057, 21353], 21370, 38429, 38434,
- 38433, 38449, 38442, 38461, 38460, 38466, 38473, 38484, 38495, 38503,
- 38508, 38514, 38516, 38536, 38541, 38551, 38576, 37015, 37019, 37021,
- 37017, 37036, 37025, 37044, 37043, 37046, 37050, 37048, 37040, 37071,
- 37061, 37054, 37072, 37060, 37063, 37075, 37094, 37090, 37084, 37079,
- 37083, 37099, 37103, 37118, 37124, 37154, 37150, 37155, 37169, 37167,
- 37177, 37187, 37190, 21005, 22850, 21154, {f: 2, c: 21164}, 21182, 21759,
- 21200, 21206, 21232, 21471, 29166, 30669, [12085, 24308], [12048, 20981],
- 20988, [12223, 39727], [12059, 21430], 24321, 30042, 24047, 22348, 22441,
- 22433, 22654, 22716, 22725, 22737, 22313, 22316, 22314, 22323, 22329,
- {f: 2, c: 22318}, 22364, 22331, 22338, 22377, 22405, 22379, 22406, 22396,
- 22395, 22376, 22381, 22390, 22387, 22445, 22436, 22412, 22450, 22479,
- 22439, 22452, 22419, 22432, 22485, 22488, 22490, 22489, 22482, 22456,
- 22516, 22511, 22520, 22500, 22493, 22539, 22541, 22525, 22509, 22528,
- 22558, 22553, 22596, 22560, 22629, 22636, 22657, 22665, 22682, 22656,
- 39336, 40729, 25087, 33401, 33405, 33407, 33423, 33418, 33448, 33412,
- 33422, 33425, 33431, 33433, 33451, 33464, 33470, 33456, 33480, 33482,
- 33507, 33432, 33463, 33454, {f: 2, c: 33483}, 33473, 33449, 33460, 33441,
- 33450, 33439, 33476, 33486, 33444, 33505, 33545, 33527, 33508, 33551,
- 33543, 33500, 33524, 33490, 33496, 33548, 33531, 33491, 33553, 33562,
- 33542, {f: 2, c: 33556}, 33504, 33493, 33564, 33617, {f: 2, c: 33627},
- 33544, 33682, 33596, 33588, 33585, 33691, 33630, 33583, 33615, 33607,
- 33603, 33631, 33600, 33559, 33632, 33581, 33594, 33587, 33638, 33637,
- 33640, 33563, 33641, 33644, 33642, {f: 2, c: 33645}, 33712, 33656,
- {f: 2, c: 33715}, 33696, 33706, 33683, 33692, 33669, 33660, 33718, 33705,
- 33661, 33720, 33659, 33688, 33694, 33704, 33722, 33724, 33729, 33793,
- 33765, 33752, 22535, 33816, 33803, 33757, 33789, 33750, 33820, 33848,
- 33809, 33798, 33748, 33759, 33807, 33795, {f: 2, c: 33784}, 33770, 33733,
- 33728, 33830, 33776, 33761, 33884, 33873, 33882, 33881, 33907,
- {f: 2, c: 33927}, 33914, 33929, 33912, 33852, 33862, 33897, 33910, 33932,
- 33934, 33841, 33901, 33985, 33997, 34000, 34022, 33981, 34003, 33994,
- 33983, 33978, 34016, 33953, 33977, 33972, 33943, 34021, 34019, 34060,
- 29965, 34104, 34032, 34105, 34079, 34106, 34134, 34107, 34047, 34044,
- 34137, 34120, 34152, 34148, 34142, 34170, 30626, 34115, 34162, 34171,
- 34212, 34216, 34183, 34191, 34169, 34222, 34204, 34181, 34233, 34231,
- 34224, 34259, 34241, 34268, 34303, 34343, 34309, 34345, 34326, 34364,
- [12086, 24318], 24328, 22844, 22849, 32823, 22869, 22874, 22872, 21263,
- [12074, 23586], 23589, 23596, 23604, 25164, 25194, 25247, 25275, 25290,
- 25306, 25303, 25326, 25378, 25334, 25401, 25419, 25411, 25517, 25590,
- 25457, 25466, 25486, 25524, 25453, 25516, 25482, 25449, 25518, 25532,
- 25586, 25592, 25568, 25599, 25540, 25566, 25550, 25682, 25542, 25534,
- 25669, 25665, 25611, 25627, 25632, 25612, 25638, 25633, 25694, 25732,
- 25709, 25750, 25722, {f: 2, c: 25783}, 25753, 25786, 25792, 25808, 25815,
- 25828, 25826, 25865, 25893, 25902, [12087, 24331], 24530, 29977, 24337,
- 21343, 21489, 21501, 21481, 21480, 21499, 21522, 21526, 21510, 21579,
- {f: 3, c: 21586}, 21590, 21571, 21537, 21591, 21593, 21539, 21554, 21634,
- 21652, 21623, 21617, 21604, {f: 2, c: 21658}, 21636, 21622, 21606, 21661,
- 21712, 21677, 21698, 21684, 21714, 21671, 21670, {f: 2, c: 21715}, 21618,
- 21667, 21717, 21691, 21695, 21708, {f: 2, c: 21721}, 21724,
- {f: 2, c: 21673}, 21668, 21725, 21711, 21726, 21787, 21735, 21792, 21757,
- 21780, 21747, {f: 2, c: 21794}, 21775, 21777, 21799, 21802, 21863, 21903,
- 21941, 21833, 21869, 21825, 21845, 21823, 21840, 21820, 21815, 21846,
- {f: 3, c: 21877}, 21811, 21808, 21852, 21899, 21970, 21891, 21937, 21945,
- 21896, 21889, 21919, 21886, 21974, 21905, 21883, 21983, {f: 2, c: 21949},
- 21908, 21913, 21994, 22007, 21961, 22047, 21969, {f: 2, c: 21995}, 21972,
- 21990, 21981, 21956, 21999, 21989, {f: 2, c: 22002}, {f: 2, c: 21964},
- 21992, 22005, 21988, 36756, 22046, 22024, 22028, 22017, 22052, 22051,
- 22014, 22016, 22055, 22061, 22104, 22073, 22103, 22060, 22093, 22114,
- 22105, 22108, 22092, 22100, 22150, 22116, 22129, 22123, {f: 2, c: 22139},
- 22149, 22163, 22191, 22228, [12062, 22231], 22237, 22241, 22261, 22251,
- 22265, 22271, 22276, 22282, 22281, 22300, 24079, 24089, 24084, 24081,
- 24113, {f: 2, c: 24123}, 24119, 24132, 24148, 24155, 24158, 24161, 23692,
- 23674, 23693, 23696, 23702, 23688, {f: 2, c: 23704}, 23697, 23706, 23708,
- 23733, 23714, 23741, 23724, 23723, 23729, 23715, 23745, 23735, 23748,
- 23762, 23780, 23755, 23781, {f: 2, c: 23810}, 23847, 23846, 23854, 23844,
- 23838, 23814, 23835, 23896, 23870, 23860, 23869, 23916, 23899, 23919,
- 23901, 23915, 23883, 23882, 23913, 23924, 23938, 23961, 23965, 35955,
- 23991, 24005, [12091, 24435], 24439, 24450, 24455, 24457, 24460, 24469,
- 24473, 24476, 24488, 24493, 24501, 24508, 34914, [12090, 24417], 29357,
- 29360, 29364, {f: 2, c: 29367}, 29379, 29377, 29390, 29389, 29394, 29416,
- 29423, 29417, 29426, 29428, 29431, 29441, 29427, 29443, {f: 2, c: 29434},
- 29463, 29459, 29473, 29450, 29470, 29469, 29461, 29474, 29497, 29477,
- 29484, 29496, 29489, 29520, 29517, 29527, 29536, 29548, 29551, 29566,
- [12167, 33307], 22821, 39143, 22820, [12065, 22786], 39267,
- {f: 6, c: 39271}, 39284, 39287, 39293, 39296, 39300, 39303, 39306, 39309,
- {f: 2, c: 39312}, {f: 3, c: 39315}, 24192, 24209, 24203, 24214, 24229,
- 24224, 24249, 24245, 24254, 24243, 36179, 24274, 24273, 24283, 24296,
- 24298, 33210, 24516, 24521, 24534, 24527, 24579, 24558, 24580, 24545,
- 24548, 24574, {f: 2, c: 24581}, 24554, 24557, 24568, 24601, 24629, 24614,
- 24603, 24591, 24589, 24617, 24619, 24586, 24639, 24609, {f: 2, c: 24696},
- 24699, 24698, 24642, 24682, 24701, 24726, 24730, 24749, 24733, 24707,
- 24722, 24716, 24731, 24812, 24763, 24753, 24797, 24792, 24774, 24794,
- 24756, 24864, 24870, 24853, 24867, 24820, 24832, 24846, 24875, 24906,
- 24949, 25004, 24980, 24999, 25015, 25044, 25077, 24541, 38579, 38377,
- 38379, 38385, 38387, {f: 2, c: 38389}, 38396, 38398, {f: 2, c: 38403},
- 38406, 38408, {f: 4, c: 38410}, 38415, 38418, {f: 3, c: 38421},
- {f: 2, c: 38425}, 20012, [12121, 29247], 25109, 27701, 27732, 27740, 27722,
- 27811, 27781, 27792, 27796, 27788, {f: 2, c: 27752}, 27764, 27766, 27782,
- 27817, 27856, 27860, 27821, {f: 2, c: 27895}, 27889, 27863, 27826, 27872,
- 27862, 27898, 27883, 27886, 27825, 27859, 27887, 27902, 27961, 27943,
- 27916, 27971, 27976, 27911, 27908, 27929, 27918, 27947, 27981, 27950,
- 27957, 27930, 27983, 27986, 27988, 27955, 28049, 28015, 28062, 28064,
- 27998, {f: 2, c: 28051}, 27996, 28000, 28028, 28003, 28186, 28103, 28101,
- 28126, 28174, 28095, 28128, 28177, 28134, 28125, 28121, 28182, 28075,
- 28172, 28078, 28203, 28270, 28238, 28267, 28338, 28255, 28294,
- {f: 2, c: 28243}, 28210, 28197, 28228, 28383, 28337, 28312, 28384, 28461,
- 28386, 28325, 28327, 28349, 28347, 28343, 28375, 28340, 28367, 28303,
- 28354, 28319, 28514, {f: 2, c: 28486}, 28452, 28437, 28409, 28463, 28470,
- 28491, 28532, 28458, 28425, 28457, 28553, 28557, 28556, 28536, 28530,
- 28540, 28538, 28625, 28617, 28583, 28601, 28598, 28610, 28641, 28654,
- 28638, 28640, 28655, 28698, 28707, 28699, 28729, 28725, 28751, 28766,
- [12071, 23424], 23428, 23445, 23443, 23461, 23480, 29999, 39582, 25652,
- 23524, 23534, 35120, 23536, 36423, 35591, 36790, 36819, 36821, 36837,
- 36846, 36836, 36841, 36838, 36851, 36840, 36869, 36868, 36875, 36902,
- 36881, 36877, 36886, 36897, {f: 2, c: 36917}, 36909, 36911, 36932,
- {f: 2, c: 36945}, 36944, 36968, 36952, 36962, 36955, 26297, 36980, 36989,
- 36994, 37000, 36995, 37003, [12089, 24400], 24407, 24406, 24408, 23611,
- 21675, 23632, 23641, 23409, 23651, 23654, 32700, 24362, 24361, 24365,
- 33396, 24380, 39739, [12076, 23662], 22913, 22915, 22925, {f: 2, c: 22953},
- 22947, 22935, 22986, 22955, 22942, 22948, 22994, 22962, 22959, 22999,
- 22974, {f: 2, c: 23045}, 23005, 23048, 23011, 23000, 23033, 23052, 23049,
- 23090, 23092, 23057, 23075, 23059, 23104, 23143, 23114, 23125, 23100,
- 23138, 23157, 33004, 23210, 23195, 23159, 23162, 23230, 23275, 23218,
- 23250, 23252, 23224, 23264, 23267, 23281, 23254, 23270, 23256, 23260,
- 23305, 23319, 23318, 23346, 23351, 23360, 23573, 23580, 23386, 23397,
- 23411, 23377, 23379, 23394, 39541, {f: 2, c: 39543}, 39546, 39551, 39549,
- {f: 2, c: 39552}, 39557, 39560, 39562, 39568, {f: 2, c: 39570}, 39574,
- 39576, {f: 3, c: 39579}, {f: 2, c: 39583}, {f: 2, c: 39586}, 39589, 39591,
- 32415, 32417, 32419, 32421, {f: 2, c: 32424}, 32429, 32432, 32446,
- {f: 3, c: 32448}, 32457, {f: 2, c: 32459}, 32464, 32468, 32471, 32475,
- {f: 2, c: 32480}, 32488, 32491, {f: 2, c: 32494}, {f: 2, c: 32497}, 32525,
- 32502, {f: 2, c: 32506}, 32510, {f: 3, c: 32513}, {f: 2, c: 32519},
- {f: 2, c: 32523}, 32527, {f: 2, c: 32529}, 32535, 32537, 32540, 32539,
- 32543, {f: 7, c: 32545}, {f: 4, c: 32554}, {f: 5, c: 32559}, 32565,
- [12083, 24186], 30079, [12078, 24027], 30014, 37013, 29582, 29585, 29614,
- 29602, 29599, 29647, 29634, 29649, 29623, 29619, 29632, 29641, 29640,
- 29669, 29657, 39036, 29706, 29673, 29671, 29662, 29626, 29682, 29711,
- 29738, 29787, 29734, 29733, 29736, 29744, 29742, 29740, 29723, 29722,
- 29761, 29788, 29783, 29781, 29785, 29815, 29805, 29822, 29852, 29838,
- {f: 2, c: 29824}, 29831, 29835, 29854, {f: 2, c: 29864}, 29840, 29863,
- 29906, 29882, {f: 3, c: 38890}, 26444, 26451, 26462, 26440, 26473, 26533,
- 26503, 26474, 26483, 26520, 26535, 26485, 26536, 26526, 26541, 26507,
- 26487, 26492, 26608, 26633, 26584, 26634, 26601, 26544, 26636, 26585,
- 26549, 26586, 26547, 26589, 26624, 26563, 26552, 26594, 26638, 26561,
- 26621, {f: 2, c: 26674}, {f: 2, c: 26720}, 26702, 26722, 26692, 26724,
- 26755, 26653, 26709, 26726, 26689, 26727, 26688, 26686, 26698, 26697,
- 26665, 26805, 26767, 26740, 26743, 26771, 26731, 26818, 26990, 26876,
- {f: 2, c: 26911}, 26873, 26916, 26864, 26891, 26881, 26967, 26851, 26896,
- 26993, 26937, 26976, 26946, 26973, 27012, 26987, 27008, 27032, 27000,
- 26932, 27084, {f: 2, c: 27015}, 27086, 27017, 26982, 26979, 27001, 27035,
- 27047, 27067, 27051, 27053, 27092, 27057, 27073, 27082, 27103, 27029,
- 27104, 27021, 27135, 27183, 27117, {f: 2, c: 27159}, 27237, 27122, 27204,
- 27198, 27296, 27216, 27227, 27189, 27278, 27257, 27197, 27176, 27224,
- 27260, 27281, 27280, 27305, 27287, 27307, 29495, 29522, {f: 2, c: 27521},
- 27527, 27524, {f: 2, c: 27538}, 27533, {f: 2, c: 27546}, 27553, 27562,
- 36715, 36717, {f: 3, c: 36721}, {f: 2, c: 36725}, 36728, 36727,
- {f: 2, c: 36729}, 36732, 36734, {f: 2, c: 36737}, 36740, 36743, 36747,
- {f: 3, c: 36749}, 36760, 36762, 36558, 25099, 25111, 25115, 25119, 25122,
- 25121, 25125, 25124, 25132, 33255, 29935, 29940, 29951, 29967, 29969,
- 29971, [12097, 25908], {f: 3, c: 26094}, 26122, 26137, 26482, 26115, 26133,
- 26112, 28805, 26359, 26141, 26164, 26161, 26166, 26165, 32774, 26207,
- 26196, 26177, 26191, 26198, 26209, 26199, 26231, 26244, 26252, 26279,
- 26269, 26302, {f: 2, c: 26331}, 26342, 26345, {f: 2, c: 36146}, 36150,
- 36155, 36157, 36160, {f: 2, c: 36165}, {f: 2, c: 36168}, 36167, 36173,
- 36181, 36185, 35271, {f: 3, c: 35274}, {f: 4, c: 35278}, 29294, 29343,
- 29277, 29286, 29295, {f: 2, c: 29310}, 29316, 29323, 29325, 29327, 29330,
- 25352, 25394, 25520, 25663, 25816, 32772, 27626, 27635, 27645, 27637,
- 27641, 27653, 27655, 27654, 27661, 27669, {f: 3, c: 27672}, 27681, 27689,
- 27684, 27690, 27698, 25909, 25941, 25963, 29261, 29266, 29270, 29232,
- 34402, 21014, 32927, 32924, 32915, 32956, 26378, 32957, 32945, 32939,
- 32941, 32948, 32951, {f: 4, c: 32999}, 32987, 32962, 32964, 32985, 32973,
- 32983, 26384, 32989, 33003, 33009, 33012, 33005, {f: 2, c: 33037}, 33010,
- 33020, 26389, 33042, 35930, 33078, 33054, 33068, 33048, 33074, 33096,
- 33100, 33107, 33140, {f: 2, c: 33113}, 33137, 33120, 33129,
- {f: 2, c: 33148}, 33133, 33127, 22605, 23221, 33160, 33154, 33169, 28373,
- 33187, 33194, 33228, 26406, 33226, 33211, 33217, 33190, 27428, 27447,
- 27449, 27459, 27462, 27481, {f: 3, c: 39121}, 39125, {f: 2, c: 39129},
- [12110, 27571], 24384, 27586, 35315, 26000, 40785, 26003, 26044, 26054,
- 26052, 26051, 26060, 26062, 26066, 26070, 28800, 28828, 28822, 28829,
- 28859, 28864, 28855, 28843, 28849, 28904, 28874, 28944, 28947, 28950,
- 28975, 28977, 29043, 29020, 29032, 28997, 29042, 29002, 29048, 29050,
- 29080, 29107, 29109, 29096, 29088, 29152, 29140, 29159, 29177, 29213,
- 29224, 28780, 28952, 29030, 29113, 25150, 25149, 25155, {f: 2, c: 25160},
- 31035, 31040, 31046, 31049, {f: 2, c: 31067}, 31059, 31066, 31074, 31063,
- 31072, 31087, 31079, 31098, 31109, 31114, 31130, 31143, 31155, 24529,
- 24528, 24636, 24669, 24666, 24679, 24641, 24665, 24675, 24747, 24838,
- 24845, 24925, 25001, 24989, 25035, 25041, 25094, 32896, [12160, 32895],
- 27795, 27894, 28156, 30710, 30712, 30720, 30729, {f: 2, c: 30743}, 30737,
- 26027, 30765, {f: 2, c: 30748}, {f: 3, c: 30777}, 30751, 30780, 30757,
- 30764, 30755, 30761, 30798, 30829, {f: 2, c: 30806}, 30758, 30800, 30791,
- 30796, 30826, 30875, 30867, 30874, 30855, 30876, 30881, 30883, 30898,
- 30905, 30885, 30932, 30937, 30921, 30956, 30962, 30981, 30964, 30995,
- 31012, 31006, 31028, 40859, [12235, 40697], {f: 2, c: 40699}, 30449, 30468,
- 30477, 30457, {f: 2, c: 30471}, 30490, 30498, 30489, 30509, 30502, 30517,
- 30520, {f: 2, c: 30544}, 30535, 30531, 30554, 30568, 30562, 30565, 30591,
- 30605, 30589, 30592, 30604, 30609, {f: 2, c: 30623}, 30640, 30645, 30653,
- 30010, 30016, 30030, 30027, 30024, 30043, 30066, 30073, 30083, 32600,
- 32609, 32607, 35400, 32616, 32628, 32625, 32633, 32641, 32638, 30413,
- 30437, 34866, {f: 3, c: 38021}, 38027, 38026, {f: 2, c: 38028},
- {f: 2, c: 38031}, 38036, 38039, 38037, {f: 3, c: 38042}, {f: 2, c: 38051},
- 38059, 38058, 38061, 38060, {f: 2, c: 38063}, 38066, 38068,
- {f: 5, c: 38070}, {f: 2, c: 38076}, 38079, 38084, {f: 7, c: 38088},
- {f: 3, c: 38096}, {f: 3, c: 38101}, 38105, 38104, 38107, {f: 3, c: 38110},
- 38114, {f: 2, c: 38116}, {f: 2, c: 38119}, 38122, 38121, 38123,
- {f: 2, c: 38126}, {f: 3, c: 38131}, 38135, 38137, {f: 2, c: 38140}, 38143,
- 38147, 38146, {f: 2, c: 38150}, {f: 2, c: 38153}, {f: 3, c: 38157},
- {f: 5, c: 38162}, 38168, 38171, {f: 3, c: 38173}, 38178, {f: 2, c: 38186},
- 38185, 38188, {f: 2, c: 38193}, 38196, {f: 3, c: 38198}, 38204,
- {f: 2, c: 38206}, 38210, 38197, {f: 3, c: 38212}, 38217, 38220,
- {f: 2, c: 38222}, {f: 3, c: 38226}, {f: 4, c: 38230}, 38235,
- {f: 2, c: 38238}, 38237, {f: 2, c: 38241}, {f: 9, c: 38244}, 38255,
- {f: 3, c: 38257}, 38202, 30695, 30700, 38601, 31189, 31213, 31203, 31211,
- 31238, 23879, 31235, 31234, 31262, 31252, 31289, 31287, 31313, 40655,
- 39333, 31344, 30344, 30350, 30355, 30361, 30372, 29918, 29920, 29996,
- 40480, 40482, {f: 5, c: 40488}, 40498, 40497, 40502, 40504, 40503,
- {f: 2, c: 40505}, 40510, {f: 2, c: 40513}, 40516, {f: 4, c: 40518},
- {f: 2, c: 40523}, 40526, 40529, 40533, 40535, {f: 3, c: 40538}, 40542,
- 40547, {f: 7, c: 40550}, 40561, 40557, 40563, [12135, 30098], 30100, 30102,
- 30112, 30109, 30124, 30115, {f: 2, c: 30131}, 30136, 30148, 30129, 30128,
- 30147, 30146, 30166, 30157, 30179, 30184, 30182, 30180, 30187, 30183,
- 30211, 30193, 30204, 30207, 30224, 30208, 30213, 30220, 30231, 30218,
- 30245, 30232, 30229, 30233, 30235, 30268, 30242, 30240, 30272, 30253,
- 30256, 30271, 30261, 30275, 30270, 30259, 30285, 30302, 30292, 30300,
- 30294, 30315, 30319, 32714, 31462, {f: 2, c: 31352}, 31360, 31366, 31368,
- 31381, 31398, 31392, 31404, 31400, 31405, 31411, 34916, 34921, 34930,
- 34941, 34943, 34946, 34978, 35014, 34999, 35004, 35017, 35042, 35022,
- 35043, 35045, 35057, 35098, 35068, 35048, 35070, 35056, 35105, 35097,
- 35091, 35099, 35082, 35124, 35115, 35126, 35137, 35174, 35195,
- [12134, 30091], 32997, 30386, 30388, 30684, [12158, 32786], 32788, 32790,
- 32796, 32800, 32802, {f: 3, c: 32805}, 32809, 32808, 32817, 32779, 32821,
- 32835, 32838, 32845, 32850, 32873, 32881, 35203, 39032, 39040, 39043,
- 39049, {f: 2, c: 39052}, 39055, 39060, {f: 2, c: 39066}, {f: 2, c: 39070},
- {f: 2, c: 39073}, {f: 2, c: 39077}, [12172, 34381], 34388, 34412, 34414,
- 34431, 34426, 34428, 34427, 34472, 34445, 34443, 34476, 34461, 34471,
- 34467, 34474, 34451, 34473, 34486, 34500, 34485, 34510, 34480, 34490,
- 34481, 34479, 34505, 34511, 34484, 34537, {f: 2, c: 34545}, 34541, 34547,
- 34512, 34579, 34526, 34548, 34527, 34520, 34513, 34563, 34567, 34552,
- 34568, 34570, 34573, 34569, 34595, 34619, 34590, 34597, 34606, 34586,
- 34622, 34632, 34612, 34609, 34601, 34615, 34623, 34690, 34594,
- {f: 2, c: 34685}, 34683, 34656, 34672, 34636, 34670, 34699, 34643, 34659,
- 34684, 34660, 34649, 34661, 34707, 34735, 34728, 34770, 34758, 34696,
- 34693, 34733, 34711, 34691, 34731, 34789, 34732, 34741, 34739, 34763,
- 34771, 34749, 34769, 34752, 34762, 34779, 34794, 34784, 34798, 34838,
- 34835, 34814, 34826, 34843, 34849, 34873, 34876, [12152, 32566], 32578,
- {f: 2, c: 32580}, 33296, 31482, 31485, 31496, {f: 2, c: 31491}, 31509,
- 31498, 31531, 31503, 31559, 31544, 31530, 31513, 31534, 31537, 31520,
- 31525, 31524, 31539, 31550, 31518, 31576, 31578, 31557, 31605, 31564,
- 31581, 31584, 31598, 31611, 31586, 31602, 31601, 31632, {f: 2, c: 31654},
- 31672, 31660, 31645, 31656, 31621, 31658, 31644, 31650, 31659, 31668,
- 31697, 31681, 31692, 31709, 31706, {f: 2, c: 31717}, 31722, 31756, 31742,
- 31740, 31759, 31766, 31755, 31775, 31786, 31782, 31800, 31809, 31808,
- 33278, {f: 2, c: 33281}, 33284, 33260, 34884, {f: 3, c: 33313}, 33325,
- 33327, 33320, 33323, 33336, 33339, {f: 2, c: 33331}, 33342, 33348, 33353,
- 33355, 33359, 33370, 33375, 33384, 34942, 34949, 34952, 35032, 35039,
- 35166, 32669, 32671, 32679, {f: 2, c: 32687}, 32690, 31868, 25929, 31889,
- 31901, 31900, 31902, 31906, 31922, {f: 2, c: 31932}, 31937, 31943,
- {f: 2, c: 31948}, 31944, 31941, 31959, 31976, [12169, 33390], 26280, 32703,
- 32718, 32725, 32741, 32737, 32742, 32745, 32750, 32755, [12151, 31992],
- 32119, 32166, 32174, 32327, 32411, 40632, 40628, 36211, 36228, 36244,
- 36241, 36273, 36199, 36205, 35911, 35913, 37194, 37200, {f: 2, c: 37198},
- 37220, 37218, 37217, 37232, 37225, 37231, {f: 2, c: 37245}, 37234, 37236,
- 37241, 37260, 37253, 37264, 37261, 37265, {f: 2, c: 37282}, 37290,
- {f: 3, c: 37293}, 37301, 37300, 37306, [12183, 35925], 40574, 36280, 36331,
- 36357, 36441, 36457, 36277, 36287, 36284, 36282, 36292, {f: 2, c: 36310},
- 36314, 36318, {f: 2, c: 36302}, 36315, 36294, 36332, {f: 2, c: 36343},
- 36323, 36345, 36347, 36324, 36361, 36349, 36372, 36381, 36383, 36396,
- 36398, 36387, 36399, 36410, 36416, 36409, 36405, 36413, 36401, 36425,
- {f: 2, c: 36417}, {f: 2, c: 36433}, 36426, 36464, 36470, 36476, 36463,
- 36468, 36485, 36495, 36500, 36496, 36508, 36510, [12184, 35960], 35970,
- 35978, 35973, 35992, 35988, 26011, 35286, 35294, 35290, 35292, 35301,
- 35307, 35311, 35390, 35622, 38739, 38633, 38643, 38639, 38662, 38657,
- 38664, 38671, 38670, 38698, 38701, 38704, 38718, 40832, 40835,
- {f: 6, c: 40837}, 40844, 40702, 40715, 40717, [12203, 38585],
- {f: 2, c: 38588}, 38606, 38610, 30655, 38624, 37518, 37550, 37576, 37694,
- 37738, 37834, 37775, 37950, 37995, 40063, 40066, {f: 4, c: 40069}, 31267,
- 40075, 40078, {f: 3, c: 40080}, {f: 2, c: 40084}, {f: 2, c: 40090},
- {f: 6, c: 40094}, {f: 5, c: 40101}, 40107, {f: 2, c: 40109},
- {f: 8, c: 40112}, {f: 4, c: 40122}, {f: 4, c: 40132}, {f: 7, c: 40138},
- {f: 3, c: 40147}, {f: 3, c: 40151}, {f: 2, c: 40156}, 40159, 40162, 38780,
- 38789, {f: 2, c: 38801}, 38804, 38831, 38827, 38819, 38834, 38836, 39601,
- 39600, 39607, 40536, 39606, 39610, 39612, 39617, 39616, 39621, 39618,
- {f: 2, c: 39627}, 39633, 39749, 39747, 39751, 39753, 39752, 39757, 39761,
- 39144, 39181, 39214, 39253, 39252, [12221, 39647], 39649, 39654, 39663,
- 39659, 39675, 39661, 39673, 39688, 39695, 39699, 39711, 39715,
- {f: 2, c: 40637}, 32315, 40578, {f: 2, c: 40583}, 40587, 40594, 37846,
- 40605, 40607, {f: 3, c: 40667}, 40672, 40671, 40674, 40681, 40679, 40677,
- 40682, 40687, 40738, 40748, 40751, 40761, 40759, {f: 2, c: 40765}, 40772,
- 12295, {s: 13}, 30362, 34297, 31001, 24859, 39599, 35158, 22761, 32631,
- 25850, 25943, 38930, 36774, 32070, 24171, 32129, 37770, 35607, 39165,
- 23542, 22577, 39825, 36649, [12185, 35997], 37575, 29437, 20633, 24970,
- 32179, 31558, 30050, 25987, 24163, 38281, 37002, 32232, 36022, 35722,
- 36783, 36782, 27161, 40009, 30303, 28693, 28657, 36051, 25839, 39173,
- 25765, 37474, 37457, 39361, 35036, 36001, 21443, 34870, 27544, 24922,
- 24920, 29158, 33980, 33369, 20489, 28356, 21408, 20596, 28204, 23652,
- 35435, 25881, 25723, 34796, 39262, 35730, 32399, 37855, 29987, 38369,
- 39019, 22580, 22039, [12199, 38263], 20767, 33144, 24288, 26274, 37396,
- [12190, 36554], 24505, 22645, 38515, 35183, 31281, 25074, 35488, 39425,
- 36978, 39347, [12242, 40786], 29118, 34909, 34802, 23541, 30087, 36490,
- 31820, 32162, 37276, 37604, 38619, 30990, 20786, 35320, 34389, 20659,
- 30241, 38358, 21109, 37656, 32020, 32189, 36781, 35422, 36060, 32880,
- 24478, 21474, 36517, 31428, 37679, 36948, 24118, 36024, 25812, 21934,
- 37170, 25763, 33213, 24986, 35477, 24392, 30070, 25803, 40680, 34153,
- 27284, 25623, 23798, 31153, 23566, 29128, 37159, 25973, 28364, 36958,
- 32224, 39003, 40670, 22666, 38651, 28593, 37347, 35519, 35548, 37336,
- 38914, 37664, 35330, 26481, 21205, 26847, 20941, [12222, 39717], 29346,
- 29544, 35712, 36077, 37709, 37723, 26039, 32222, 38538, 23565, 22136,
- 38931, 37389, 22890, 22702, 40285, 38989, 35355, 24801, 39187, 20818,
- 29246, 39180, 36019, 30332, 32624, 38309, 31020, 37353, 29033, 31684,
- 36009, 39151, 35370, 32033, [12214, 39131], 35513, 24290, 36027, 32027,
- 22707, 22894, 24996, 31966, 35920, 26963, 37586, [12213, 39080], 30219,
- 39342, 32299, 35575, 40179, 33178, 36667, 25771, 36628, 36070, 24489,
- 36000, 35331, 23142, 32283, 35442, 37411, 33995, 24185, 36245, 36123,
- 23713, 21083, 37628, 32177, 23831, 37804, 25841, 40255, 38307, 37499,
- 20491, 32102, 40852, 38799, 36002, 37390, 28317, 27083, 36092, 34865,
- 39015, 21102, 38364, 35264, 39208, 24931, 36011, 24291, 35215, 27512,
- [12244, 40860], 38312, 36556, 35437, 27331, 36020, 21130, 36645, 37707,
- 22283, 36942, 39405, 38867, 28450, 34399, 38305, 40372, 36032, 36703,
- 40251, 32005, 22778, 35703, 28396, 22057, 33775, 30059, 21123, 35441,
- 25079, 22750, 27489, 29872, 36996, 32233, 35594, 25582, 36637, 36036,
- 31330, 26371, 29172, 21295, 35569, 35496, 32362, 33911, 28222, 29554,
- 36008, 31117, 25802, 27231, 31309, 39249, 35663, 40388, 32318, 32221,
- 26997, 36655, 32026, 25824, 24190, 34186, 21137, 28639, 35336, 35352,
- 38555, 32380, 32000, 22846, 33698, 38960, 36040, 37440, 20729, 39381,
- 27570, 30435, 22533, 31627, 38291, 33393, 32216, 32365, 27298, 40572,
- 25536, 25791, 31777, 20745, 34214, 27323, 37970, 36368, 36068,
- [12178, 35211], 37749, 33382, 21133, 39198, 28472, 28666, 28567, 23559,
- 28479, 34083, 27123, 22892, 35611, 37292, 33184, 28550, 39509, 23308,
- 25898, 37496, 30703, 20709, 39171, 32371, 32094, 36686, 36611, 38542,
- 31680, 28500, 32080, 35489, 32202, 37670, 20677, 35641, 36914, 29180,
- 30433, 21185, 33686, 39912, 39514, 32147, 38968, 37857, 24465, 30169,
- 31478, 31998, 33290, 39378, 33289, 25818, 37624, 25084, 21127, 40273,
- 32121, 35258, 35363, 32118, 37406, 36557, 39423, 38283, 20977, 38982,
- 27579, 35506, 22718, 25031, 25715, 24235, 35122, 35463, 22602, 20744,
- 23532, 31014, 26336, 34407, 24011, 31418, 39243, 28528, 25844, 38346,
- 34847, 33240, 33802, 20358, 36084, 34253, 27396, 25876, 31811, 38348,
- 34349, 28734, 35733, 25900, 35261, 25078, 32412, 29211, 28651, 25736,
- 21214, 28551, 27138, 37939, 22744, 39006, 31852, 38626, 28757, 35023,
- 39881, 31150, 40599, 21426, 21237, 31019, 27511, 28701, 38584, 20486,
- 32879, 34030, 36899, 37934, 24976, 28451, 31806, 25986, 33225, 37832,
- 25088, 29001, 32244, 31975, 20841, 36635, 35538, 30274, 36988, 37904,
- 29557, 33256, 37168, 40023, 36035, 40801, 37428, 38728, 23994, 38936,
- 39230, 21129, [12243, 40845], 32894, 22184, 31840, 22751, 25871, 38580,
- 27155, 23105, 25695, 31757, 34310, 30439, 39025, 24300, 29200, 25796,
- 28407, 34396, 39791, 36034, 37682, 38520, 39522, 37569, 23650, 32311,
- 24942, 28670, 32209, 24018, 25891, 23423, 28772, 20098, 25476, 36650,
- 20523, 20374, 28138, 32184, 35542, 34367, 32645, 37007, 38012, 31854,
- 39486, 39409, 32097, 23229, 29802, 30908, 34718, [12218, 39340], 39393,
- 21966, 36023, [12230, 40613], 36067, 36993, 30622, 39237, 34875, 28415,
- 35646, 37672, 37466, 36031, 37762, [12200, 38272], 24758, 20497, 37683,
- 22818, 35598, 24396, 35219, 32191, 32236, 24287, 28357, 25003, 38313,
- 40180, 37528, 35628, 35584, 30045, 37385, 32013, 38627, 25747, 33126,
- 24817, 39719, 39186, 25836, 33193, 25862, 37312, [12227, 40165], 32886,
- 22169, 38007, 37811, 27320, 29552, 23527, 25840, 28632, 37397, 32016,
- 33215, 28611, 36786, 30247, 35582, 27472, 40407, 27590, 22036, 28442,
- 30436, 40848, 36064, 22132, 40300, 39449, 39108, 38971, 36007, 34315,
- 24977, 35413, 28497, 38935, 25778, 37610, 20693, 27192, 35676, 33229,
- [12241, 40778], 39438, 35912, 21843, 27683, 35350, 29309, 37370, 37467,
- 36983, 31805, 35609, 37666, 37463, 28154, 35700, 22649, 27085, 21958,
- 22715, 34196, 25654, 37740, 27211, 21932, 20689, 32761, 31429, 31434,
- 27453, 35242, 23522, 36629, 27691, 20670, 38915, 35531, 24950, 29898,
- 31406, 36264, 21312, 36544, 39493, 40818, 39028, 27402, 21240, 40306,
- 30906, 35731, 39250, 25854, 32350, 29105, 38860, 35469, 32009, 27054,
- 32104, 36575, 37613, 38287, 28516, 28753, 34217, 39955, 36093, 20632,
- 21930, 39479, 25475, 28544, 27578, 32023, 31721, 26348, 38275, 38493,
- 36109, 32341, 20663, 36062, 29138, 32057, 36050, 25448, 25885, 25086,
- 35373, 32051, 23529, 23352, 33102, 28402, 32882, 32361, 21213, 32854,
- 24107, 29509, 28629, 35433, 26178, 34645, 23526, 35672, 39387, 21218,
- 36969, 37323, 39166, 35222, 35430, 22781, 29560, 27166, 36664, 26360,
- 36118, 23660, 34899, 27193, 31466, 25976, 24101, 38617, 35504, 38918,
- 35500, 30889, 29197, 32114, 39164, 39686, 32883, 24939, 38924, 35359,
- 35494, 25851, 34311, 35380, 32901, 38614, 38568, 32143, 27506, 23403,
- 25613, 32302, 29795, 37782, 29562, 25787, 33274, 24907, 25892, 36010,
- 30321, 28760, 22727, 35674, 35527, 22022, 28271, 29145, 28644, 32295,
- 35342, 39472, 35588, 37563, 38988, 39636, 26781, 36028, 37941, 24307,
- 32893, 28916, 37509, 32113, 38957, 22294, 22615, 22296, 38973, 40213,
- 39345, 39389, 27234, 31402, 35178, 24398, 28771, 38929, 33836, 32178,
- [12209, 38859], 36949, 22285, 29234, 28656, 32173, 33894, 20553, 20702,
- 32239, 35586, 34907, 32862, 32011, 31337, 21839, 25790, 34680, 28198,
- 31401, 21978, 37794, 28879, 35491, 28961, 34154, 22626, 38695, 21209,
- 35492, 37675, 29351, 35186, 32722, 37521, 25138, 32048, 34662, 36676,
- 23805, 20448, 29433, 22151, 37697, 39854, 32406, 36066, 37532, 38289,
- 39023, 38570, 29694, 29563, 32291, 39201, 25010, 32171, 38002, 37129,
- 35443, 38911, 38917, 34157, 22210, 37559, 26313, 22063, 21332, 25406,
- 33029, 35559, 23531, 28681, 35613, 37573, 37313, 33288, 37561, 32137,
- 38920, 35377, 32210, 32396, 36562, 25080, 36984, 30316, 32098, 23416,
- 21211, 35426, 23563, 39348, 35347, 35338, 36956, 22739, 40201, 40232,
- 21854, 20126, 35357, 38329, 40573, 22196, 38996, 38331, 33399, 21421,
- 30831, 35578, 39511, 40230, 26954, 25562, 30221, 38525, 30306, 39178,
- 27171, 22575, 35617, 34277, 29242, [12212, 38913], 26989, 33865, 37291,
- 37541, 38948, 36986, 20736, 34811, 34269, 20740, 25014, 32681, 35427,
- 35696, 35516, 35695, 32377, 34093, 38512, 37504, 39154, 38577, 27387,
- 23344, 40441, 25033, 32403, 29801, 34722, 29151, 29074, 34821, 36111,
- 31310, 21938, 25793, 20653, 30320, 36404, 20778, 24962, 37109, 37438,
- 29494, 35480, 36671, 39192, [12226, 39770], 28417, 33287, 23996, 35486,
- 39729, 29508, 35709, 38928, 39341, 40219, 28149, 36677, 22290, 21729,
- 22291, 32227, 36960, 39000, 32004, 36493, 38000, 38322, 38642, 37142,
- 38549, 36939, 34292, 37270, 26248, 38620, 36617, 25890, 26283, 36106,
- 36124, 33247, 38015, 26839, 31432, 36012, 25799, 21063, 28580, 36042,
- 36104, 36555, 37720, 38296, 35408, 40779, 20661, 27656, 30430, 26028,
- 36670, 23940, 26855, 25136, 32187, 24373, 28466, 24115, 36076, 33081,
- 36249, 34756, 36685, 37754, 36889, 35998, 37341, 20597, 35386, 37806,
- 38499, 24128, 30309, 37165, 35657, 32340, 32887, 22519, 34937, 32025,
- 25711, 25842, 24159, 36074, 28399, 37912, 32066, 31278, 33131, 34886,
- 35589, 36600, 30394, 26205, 39519, 35576, 35461, 29165, 30682, 22225,
- 36015, 37956, 31689, 39376, 23560, 30938, 36681, 36090, 27137, 33674,
- 35037, 22941, 22767, 29376, 37648, 36101, 22684, 32180, 35524, 28310,
- 28609, 36039, 28460, 32156, 32317, 32305, 37138, 35419, 32068, 38013,
- 21959, 21401, 21428, 38760, 36107, 21293, 21297, 36094, 21060, 21132,
- 21108, 20660, 20480, 20630, 20757, 20738, 20756, 20796, 20791, 20712,
- 20674, 20795, 20752, 20794, 20681, 31988, 40652, 22213, 40172, 35131,
- 33248, 35329, 35344, 35340, 35349, 35635, 35406, 35365, 35393, 35382,
- 35398, 35412, 35416, 35410, 35462, 35460, 35455, 35440, 35452, 35445,
- 35436, 35438, 35533, 35554, 35425, 35482, 35493, {f: 2, c: 35473}, 35535,
- 35537, 35529, 35547, 35543, 35522, 35510, 35574, 35563, 35604, 35585,
- 35556, 35565, 35580, 35571, 35558, 35566, 35550, 35624, 35740, 35606,
- 35610, 35600, 35627, 35629, 35670, 35673, 35662, 35742, 35691, 35734,
- 38488, 37178, 37140, 37172, 37087, 37174, 37126, 37192, 33467, 21233,
- 24048, 22538, 22745, 22754, 22752, 22746, 22497, 22607, 22550, 22610,
- 22557, 22628, 34188, 34131, 34294, 33703, 33799, 34031, 33511, 34338,
- 34086, 22603, 29026, 34136, 34045, 34126, 34184, 34234, 29334, 28366,
- 34113, 34254, 34130, 33984, 33874, 33892, 33940, 33845, 34207, 34133,
- 40367, 33939, 32264, 34118, 34146, 34078, 39488, 34362, 37795, 34167,
- 34334, 34298, 34308, 34282, 34330, 22889, 23607, 25451, 25718, 25759,
- 25681, 25692, 25779, 25860, 25878, 25847, 25852, 25883, 22064, 22072,
- 22216, 22182, 21764, 21692, 22144, 22109, 22112, 22069, 22006, 22118,
- 22130, 22156, 22117, 22044, 22062, 21993, 22038, 22208, 22029, 22195,
- 22209, 22127, 36705, 22198, 22165, 22279, 24131, 24172, 24152, 24151,
- 23943, 23796, 23888, 23852, 23975, 23968, 23959, 23821, 23992, 23937,
- 24020, 24480, 29559, 29505, 29546, 29499, 29547, 29568, 29564, 39136,
- 39219, 39145, 39228, {f: 2, c: 39146}, 39149, 39156, 39177, 39185, 39195,
- 39223, 39231, 39235, {f: 3, c: 39240}, 39244, 39266, 24289, 36065, 25082,
- 25006, 24938, 24894, 24757, 24884, 25036, 24927, 25064, 24827, 24887,
- 24818, 24947, 24860, 24978, 38274, 38278, 38344, 38286, 38292, 38284,
- 38373, 38317, 38315, 39726, 38316, 38334, 38326, 39721, 38335, 38333,
- 38332, 38339, 38347, 38356, 38352, 38357, 38366, 28739, 28505, 28711,
- 28696, 28668, 28039, 28025, 28254, 28590, 28687, 28408, 28527, 28150,
- 28543, 28678, 28576, 28683, 28775, 28740, 28677, 28535, 28704, 28703,
- 28722, 28712, 28765, 39467, 36999, 36885, 37008, 23656, 24371, 23285,
- 23255, 23296, 23149, 23304, 23372, 23207, 23291, 23307, 23329, 23338,
- 23321, 39380, 39391, 39385, 39478, 39515, 39377, 39384, 39501, 39498,
- 39394, 39530, 39439, 39437, 39429, 39490, 39469, 39446, 39489, 39470,
- 39480, {f: 2, c: 39491}, 39503, 39525, 39524, 31993, 32006, 32002,
- {f: 2, c: 32007}, 32394, 32028, 32021, 32019, 32058, 32050, 32049, 32272,
- 32060, 32064, 32063, 32093, 32078, 32115, 32134, 32131, 32136, 32190,
- 32186, 32203, 32212, 32196, 32158, 32172, 32185, 32163, 32176, 32199,
- 32217, 32215, 32249, 32242, 32354, 32230, 32246, 32241, 32267, 32225,
- 32265, 32285, 32287, 32286, 32301, 32266, 32273, 32381, 32313, 32309,
- 32306, 32326, 32325, 32392, 32346, 32338, 32366, 32382, 32368, 32367,
- 32408, 29859, 29771, 29903, 38922, 29885, 29759, 29833, 29862, 29908,
- 29914, 38873, 38878, 38876, 27050, 27370, 26776, 26838, 27141, 26783,
- 27355, 27379, 27368, 27359, 27273, 26895, 27208, 26984, 27071, 27194,
- 27292, 27410, 27422, 27357, 27111, 27407, 27414, 27372, 27354, 27384,
- 27315, 27367, 27299, 27347, 27358, 27556, 27550, 27566, 27563, 27567,
- 36564, 36571, 36594, 36603, 36708, 36601, 36604, 36587, 36580, 36706,
- 36602, 36606, 36618, 36615, 36613, 36626, 36646, {f: 2, c: 36638}, 36636,
- 36659, 36678, 36692, 25108, 25127, 29964, 26311, 26308, 26249, 26326,
- 36033, 36016, 36026, 36029, 36100, 36018, 36037, 36112, 36049, 36058,
- 36053, 36075, 36071, 36091, 35224, 35244, 35233, 35263, 35238, 35247,
- 35250, 35255, 27647, 27660, 27692, 29272, 26407, 33110, 33242, 33051,
- 33214, 33121, 33231, 27487, {f: 2, c: 39086}, 39094, 39100, 39110, 39112,
- 36674, 40783, 26005, 29036, 29010, 29079, 29121, 29148, 29182, 31152,
- 31118, 31146, 25055, 24932, 25059, 25095, 28585, 30959, 30893, 30824,
- 30904, 31018, 31025, 30820, 30973, 30951, 30947, 40853, 30616, 30558,
- 30652, 32646, 32648, {f: 3, c: 37330}, 37337, 37335, 37333, 37367, 37351,
- 37348, 37702, 37365, 37369, 37384, 37414, 37445, 37393, 37392, 37377,
- 37415, 37380, 37413, 37376, 37434, 37478, 37431, 37427, 37461, 37437,
- 37432, 37470, {f: 2, c: 37484}, 37439, 37984, 37424, 37449, 37448, 37453,
- 37422, 37433, 37944, 37548, 37536, 37498, 37546, 37614, 37583, 37891,
- 37603, 37946, 37553, 37542, 37799, 37526, 37580, 37545, 37877, 37523,
- 37503, 37801, 37530, 37658, 37547, 37507, 37899, 37544, 37539, 37906,
- 37688, 37617, 37847, 37605, 37616, 37615, 37608, 37564, 37597, 37622,
- {f: 2, c: 37926}, 37571, 37599, 37606, 37650, 37638, 37737, 37659, 37696,
- 37633, 37653, 37678, 37699, {f: 2, c: 37639}, 37663, 37657, 37733, 37703,
- 37750, 37716, 37732, 37802, 37744, 37764, 37860, 37848, 37928, 37767,
- 37836, 37784, 37816, 37823, 37798, 37808, 37813, 37964, 37858,
- {f: 2, c: 37852}, 37837, 37854, 37827, 37831, 37841, 37908, 37917, 37879,
- 37989, 37907, 37997, 37920, 38009, 37881, 37913, 37962, 37938, 37951,
- 37972, 37987, 37758, 31329, 40169, 40182, 40199, 40198, 40227, 40327,
- 40469, 40221, 40223, 40421, 40239, 40409, 40240, 40258, 40478, 40275,
- 40477, 40288, 40274, 40435, 40284, 40289, 40339, 40298, 40303, 40329,
- 40344, 40346, 40384, 40357, 40361, 40386, 40380, 40474, 40403, 40410,
- 40431, 40422, 40434, 40440, 40460, 40442, 40475, 30308, 30296, 30311,
- 30210, {f: 2, c: 30278}, 30281, 30238, 30267, {f: 2, c: 30317}, 30313,
- 30322, 31431, 31414, 35168, 35123, 35165, 35143, 35128, 35172, 30392,
- 32814, 32812, 32889, 32885, 38919, {f: 2, c: 38926}, 38945, 38940, 28481,
- 38950, 38967, 38990, 38995, 39027, 39010, 39001, 39013, 39020, 39024,
- 34787, 34822, 34566, 34851, 34806, 34554, 34799, 34692, 34832, 34760,
- 34833, 34747, 34766, 32588, 31716, 31591, 31849, 31731, 31744, 31691,
- 31836, 31774, 31787, 31779, 31850, 31839, 33380, 33387, 35018, 32677,
- 31986, 31990, 31965, 32310, 40617, 36274, 37317, 37315, 40570, 36489,
- 36428, 36498, 36474, 36437, 36506, 36491, 36499, 36497, 36513, 36451,
- 36522, 36518, 35316, 35318, 38746, 38722, 38717, 38724, 40788, 40799,
- 40793, 40800, 40796, 40806, 40812, 40810, 40823, [12236, 40701], 40703,
- 40713, 35726, 38014, 37864, 39799, 39796, 39809, 39811, 39822, 40056,
- 31308, 39826, 40031, 39824, 39853, 39834, 39850, 39838, 40045, 39851,
- 39837, 40024, 39873, 40058, 39985, 39993, 39971, 39991, 39872, 39882,
- 39879, 39933, 39894, {f: 2, c: 39914}, 39905, 39908, 39911, 39901, 39906,
- 39920, 39899, 39924, 39892, 40029, 39944, 39952, 39949, 39954, 39945,
- 39935, 39968, 39986, 39981, 39976, 39973, 39977, 39987, 39998, 40008,
- 39995, 39989, 40005, 40022, 40020, 40018, 40039, 38851, 38845, 38857,
- 40379, 39631, 39638, 39637, 39768, 39758, 39255, 39260, 39714, 40695,
- 40690, 35180, 38342, 37686, 24390, 34068, 32404, 40803, 22137, 40725,
- 22081, 39662, 35079, 31296, 39091, 38308, 39693, 36852, 24409, 31339,
- 39138, 20642, 34193, 20760, 25458, 21067, 30543, 32397, 26310, 30637,
- [12228, 40565], 22217, 40692, 28635, 25054, 30663, 28720, 40629, 34890,
- 38370, 38854, 31844, 32308, 38822, 40623, 22220, 39089, 27311, 32590,
- 31984, 20418, 32363, 40569, 22190, 39706, 33903, 31142, 31858, 39634,
- 38587, 32251, 35069, 30787, {f: 10, c: 8560}, {f: 2, c: 714}, 729, 8211,
- 8213, 8229, 8245, 8453, 8457, {f: 4, c: 8598}, 8725, 8735, 8739, 8786,
- {f: 2, c: 8806}, 8895, {f: 36, c: 9552}, {f: 15, c: 9601}, {f: 3, c: 9619},
- {f: 2, c: 9660}, {f: 4, c: 9698}, 9737, 8853, 12306, {f: 2, c: 12317},
- {f: 9, c: 12321}, 12963, {f: 2, c: 13198}, {f: 3, c: 13212}, 13217, 13252,
- 13262, {f: 2, c: 13265}, 13269, 65072, 65506, 65508, 8481, 12849, 8208,
- 12540, {f: 2, c: 12443}, {f: 2, c: 12541}, 12294, {f: 2, c: 12445},
- {f: 10, c: 65097}, {f: 4, c: 65108}, {f: 14, c: 65113}, {f: 4, c: 65128},
- 12350, {f: 12, c: 12272}, 19970, {f: 3, c: 19972}, 19983, 19986, 19991,
- {f: 3, c: 19999}, 20003, 20006, 20009, {f: 2, c: 20014}, 20017, 20019,
- 20021, 20023, 20028, {f: 3, c: 20032}, 20036, 20038, 20042, 20049, 20053,
- 20055, {f: 2, c: 20058}, {f: 4, c: 20066}, {f: 2, c: 20071},
- {f: 6, c: 20074}, 20082, {f: 10, c: 20084}, {f: 3, c: 20095},
- {f: 2, c: 20099}, [12037, 20101], 20103, 20106, 20112, {f: 2, c: 20118},
- 20121, {f: 2, c: 20124}, 20131, 20138, {f: 3, c: 20143}, 20148,
- {f: 4, c: 20150}, {f: 3, c: 20156}, 20168, 20172, {f: 2, c: 20175}, 20178,
- {f: 3, c: 20186}, 20192, 20194, {f: 2, c: 20198}, 20201, {f: 3, c: 20205},
- 20209, 20212, {f: 3, c: 20216}, 20220, 20222, 20224, {f: 7, c: 20226},
- {f: 2, c: 20235}, {f: 5, c: 20242}, {f: 2, c: 20252}, 20257, 20259,
- {f: 2, c: 20264}, {f: 3, c: 20268}, 20273, 20275, 20277, 20279, 20281,
- 20283, {f: 5, c: 20286}, {f: 2, c: 20292}, {f: 6, c: 20295}, 20306, 20308,
- 20310, {f: 2, c: 20321}, 20326, 20328, {f: 2, c: 20330}, {f: 2, c: 20333},
- {f: 2, c: 20337}, 20341, {f: 4, c: 20343}, 20349, {f: 3, c: 20352}, 20357,
- 20359, 20362, 20364, 20366, 20368, {f: 2, c: 20370}, 20373,
- {f: 3, c: 20376}, 20380, {f: 2, c: 20382}, {f: 2, c: 20385}, 20388, 20395,
- 20397, {f: 5, c: 20400}, {f: 9, c: 20406}, {f: 2, c: 20416},
- {f: 4, c: 20422}, {f: 3, c: 20427}, {f: 5, c: 20434}, 20441, 20443, 20450,
- {f: 2, c: 20452}, 20455, {f: 2, c: 20459}, 20464, 20466, {f: 4, c: 20468},
- 20473, {f: 3, c: 20475}, 20479, {f: 5, c: 20481}, {f: 2, c: 20487}, 20490,
- 20494, 20496, 20499, {f: 3, c: 20501}, 20507, {f: 2, c: 20509}, 20512,
- {f: 3, c: 20514}, 20519, {f: 11, c: 20527}, 20539, 20541, {f: 4, c: 20543},
- {f: 3, c: 20548}, {f: 2, c: 20554}, 20557, {f: 5, c: 20560},
- {f: 4, c: 20566}, 20571, {f: 8, c: 20573}, {f: 6, c: 20582},
- {f: 7, c: 20589}, {f: 3, c: 20600}, {f: 2, c: 20604}, {f: 4, c: 20609},
- {f: 2, c: 20614}, {f: 4, c: 20617}, {f: 8, c: 20622}, 20631,
- {f: 8, c: 20634}, 20644, 20646, {f: 2, c: 20650}, {f: 4, c: 20654}, 20662,
- {f: 2, c: 20664}, {f: 2, c: 20668}, {f: 3, c: 20671}, {f: 2, c: 20675},
- {f: 3, c: 20678}, {f: 5, c: 20682}, 20688, {f: 3, c: 20690},
- {f: 3, c: 20695}, {f: 3, c: 20699}, {f: 6, c: 20703}, {f: 3, c: 20713},
- {f: 4, c: 20719}, 20724, {f: 3, c: 20726}, 20730, {f: 4, c: 20732}, 20737,
- 20739, 20741, 20746, {f: 4, c: 20748}, 20753, 20755, {f: 2, c: 20758},
- {f: 6, c: 20761}, 20768, {f: 8, c: 20770}, {f: 7, c: 20779},
- {f: 4, c: 20787}, {f: 2, c: 20792}, {f: 2, c: 20797}, 20802, 20807, 20810,
- 20812, {f: 3, c: 20814}, 20819, {f: 3, c: 20823}, 20827, {f: 5, c: 20829},
- {f: 2, c: 20835}, {f: 2, c: 20838}, 20842, 20847, 20850, 20858,
- {f: 2, c: 20862}, {f: 2, c: 20867}, {f: 2, c: 20870}, {f: 2, c: 20874},
- {f: 4, c: 20878}, {f: 2, c: 20883}, 20888, 20890, {f: 3, c: 20893}, 20897,
- 20899, {f: 5, c: 20902}, {f: 2, c: 20909}, 20916, {f: 3, c: 20920},
- {f: 2, c: 20926}, {f: 3, c: 20929}, 20933, 20936, 20938, 20942, 20944,
- {f: 9, c: 20946}, 20956, {f: 2, c: 20958}, {f: 2, c: 20962},
- {f: 6, c: 20965}, 20972, 20974, 20978, 20980, 20983, 20990,
- {f: 2, c: 20996}, 21001, {f: 2, c: 21003}, {f: 2, c: 21007},
- {f: 3, c: 21011}, 21020, {f: 2, c: 21022}, {f: 3, c: 21025},
- {f: 3, c: 21029}, 21034, 21036, 21039, {f: 2, c: 21041}, {f: 2, c: 21044},
- 21052, 21054, {f: 2, c: 21061}, {f: 2, c: 21064}, {f: 2, c: 21070},
- {f: 2, c: 21074}, 21077, {f: 4, c: 21079}, 21085, {f: 2, c: 21087},
- {f: 3, c: 21090}, 21094, 21096, {f: 3, c: 21099}, {f: 2, c: 21104}, 21107,
- {f: 7, c: 21110}, 21118, 21120, {f: 3, c: 21124}, 21131, {f: 2, c: 21134},
- 21138, {f: 7, c: 21140}, 21148, {f: 4, c: 21156}, {f: 3, c: 21166},
- {f: 10, c: 21172}, 21184, 21186, {f: 3, c: 21188}, 21192, 21194,
- {f: 4, c: 21196}, 21201, {f: 2, c: 21203}, 21207, 21210, 21212,
- {f: 2, c: 21216}, 21219, {f: 11, c: 21221}, {f: 3, c: 21234},
- {f: 2, c: 21238}, {f: 3, c: 21243}, {f: 4, c: 21249}, 21255,
- {f: 4, c: 21257}, 21262, {f: 4, c: 21265}, 21272, {f: 2, c: 21275},
- {f: 2, c: 21278}, 21282, {f: 2, c: 21284}, {f: 3, c: 21287},
- {f: 2, c: 21291}, 21296, {f: 6, c: 21298}, [12054, 21304],
- {f: 2, c: 21308}, 21314, 21316, 21318, {f: 3, c: 21323}, 21328,
- {f: 2, c: 21336}, 21339, 21341, 21349, 21352, 21354, {f: 2, c: 21356},
- 21362, 21366, 21369, {f: 4, c: 21371}, {f: 2, c: 21376}, 21379,
- {f: 2, c: 21383}, 21386, {f: 7, c: 21390}, {f: 2, c: 21398},
- {f: 2, c: 21403}, 21406, 21409, 21412, 21415, {f: 3, c: 21418},
- {f: 3, c: 21423}, 21427, 21429, {f: 4, c: 21431}, {f: 3, c: 21436}, 21440,
- {f: 4, c: 21444}, {f: 3, c: 21454}, {f: 2, c: 21458}, 21461, 21466,
- {f: 3, c: 21468}, 21473, 21479, 21492, 21498, {f: 3, c: 21502}, 21506,
- 21509, 21511, 21515, 21524, {f: 3, c: 21528}, 21532, 21538,
- {f: 2, c: 21540}, 21546, 21552, 21555, {f: 2, c: 21558}, 21562, 21565,
- 21567, {f: 2, c: 21569}, {f: 2, c: 21572}, 21575, 21577, {f: 4, c: 21580},
- 21585, 21594, {f: 5, c: 21597}, 21603, 21605, 21607, {f: 8, c: 21609},
- 21620, {f: 2, c: 21625}, {f: 2, c: 21630}, 21633, 21635, 21637,
- {f: 4, c: 21639}, 21645, 21649, 21651, {f: 2, c: 21655}, 21660,
- {f: 5, c: 21662}, 21669, 21678, 21680, 21682, {f: 3, c: 21685},
- {f: 2, c: 21689}, 21694, 21699, 21701, {f: 2, c: 21706}, 21718, 21720,
- 21723, 21728, {f: 3, c: 21730}, {f: 2, c: 21739}, {f: 3, c: 21743},
- {f: 6, c: 21748}, 21755, 21758, 21760, {f: 2, c: 21762}, 21765, 21768,
- {f: 5, c: 21770}, {f: 2, c: 21778}, {f: 6, c: 21781}, {f: 4, c: 21788},
- 21793, {f: 2, c: 21797}, {f: 2, c: 21800}, 21803, 21805, 21810,
- {f: 3, c: 21812}, {f: 4, c: 21816}, 21821, 21824, 21826, 21829,
- {f: 2, c: 21831}, {f: 4, c: 21835}, {f: 2, c: 21841}, 21844,
- {f: 5, c: 21847}, 21853, {f: 2, c: 21855}, {f: 2, c: 21858},
- {f: 2, c: 21864}, 21867, {f: 6, c: 21871}, {f: 2, c: 21881}, 21885, 21887,
- {f: 2, c: 21893}, {f: 3, c: 21900}, 21904, {f: 2, c: 21906},
- {f: 3, c: 21909}, {f: 2, c: 21914}, 21918, {f: 7, c: 21920},
- {f: 2, c: 21928}, 21931, 21933, {f: 2, c: 21935}, 21940, 21942, 21944,
- 21946, 21948, {f: 5, c: 21951}, 21960, {f: 2, c: 21962}, {f: 2, c: 21967},
- 21973, {f: 3, c: 21975}, 21979, 21982, 21984, 21986, 21991,
- {f: 2, c: 21997}, {f: 2, c: 22000}, 22004, {f: 5, c: 22008}, 22015,
- {f: 4, c: 22018}, 22023, {f: 2, c: 22026}, {f: 4, c: 22032}, 22037,
- {f: 2, c: 22041}, 22045, {f: 3, c: 22048}, {f: 2, c: 22053}, 22056,
- {f: 2, c: 22058}, 22067, 22071, 22074, {f: 3, c: 22076}, 22080,
- {f: 10, c: 22082}, {f: 5, c: 22095}, {f: 2, c: 22101}, {f: 2, c: 22106},
- {f: 2, c: 22110}, 22113, 22115, 22119, {f: 2, c: 22125}, 22128, 22131,
- 22133, 22135, 22138, {f: 3, c: 22141}, {f: 4, c: 22145}, {f: 4, c: 22152},
- 22157, {f: 3, c: 22160}, 22164, {f: 3, c: 22166}, {f: 9, c: 22170},
- {f: 2, c: 22180}, 22183, {f: 5, c: 22185}, {f: 3, c: 22192}, 22197,
- {f: 4, c: 22200}, {f: 3, c: 22205}, {f: 2, c: 22211}, {f: 2, c: 22214},
- 22219, {f: 4, c: 22221}, {f: 2, c: 22226}, {f: 2, c: 22229},
- {f: 2, c: 22232}, 22236, 22243, {f: 6, c: 22245}, 22252, {f: 2, c: 22254},
- {f: 2, c: 22258}, {f: 3, c: 22262}, {f: 2, c: 22267}, {f: 3, c: 22272},
- 22277, 22284, {f: 4, c: 22286}, {f: 2, c: 22292}, 22295, {f: 3, c: 22297},
- {f: 2, c: 22301}, {f: 3, c: 22304}, {f: 4, c: 22308}, 22315,
- {f: 2, c: 22321}, {f: 5, c: 22324}, {f: 2, c: 22332}, 22335, 22337,
- {f: 4, c: 22339}, {f: 2, c: 22344}, 22347, {f: 5, c: 22354},
- {f: 2, c: 22360}, {f: 2, c: 22370}, 22373, 22375, 22380, 22382,
- {f: 3, c: 22384}, {f: 2, c: 22388}, {f: 3, c: 22392}, {f: 5, c: 22397},
- {f: 4, c: 22407}, {f: 5, c: 22413}, {f: 7, c: 22420}, {f: 4, c: 22428},
- 22437, 22440, 22442, 22444, {f: 3, c: 22447}, 22451, {f: 3, c: 22453},
- {f: 9, c: 22457}, {f: 7, c: 22468}, {f: 2, c: 22476}, {f: 2, c: 22480},
- 22483, {f: 2, c: 22486}, {f: 2, c: 22491}, 22494, {f: 2, c: 22498},
- {f: 8, c: 22501}, 22510, {f: 4, c: 22512}, {f: 2, c: 22517},
- {f: 2, c: 22523}, {f: 2, c: 22526}, 22529, {f: 2, c: 22531},
- {f: 2, c: 22536}, 22540, {f: 3, c: 22542}, {f: 3, c: 22546},
- {f: 2, c: 22551}, {f: 3, c: 22554}, 22559, {f: 2, c: 22562},
- {f: 5, c: 22565}, {f: 4, c: 22571}, {f: 2, c: 22578}, {f: 14, c: 22582},
- {f: 5, c: 22597}, 22606, 22608, 22611, {f: 2, c: 22613}, {f: 5, c: 22617},
- {f: 3, c: 22623}, 22627, {f: 5, c: 22630}, {f: 8, c: 22637},
- {f: 3, c: 22646}, {f: 4, c: 22650}, 22655, 22658, 22660, {f: 3, c: 22662},
- {f: 7, c: 22667}, {f: 5, c: 22676}, 22683, 22685, {f: 8, c: 22688},
- {f: 4, c: 22698}, {f: 4, c: 22703}, {f: 7, c: 22708}, 22717,
- {f: 2, c: 22719}, {f: 3, c: 22722}, 22726, {f: 9, c: 22728}, 22738, 22740,
- {f: 2, c: 22742}, {f: 3, c: 22747}, 22753, 22755, {f: 4, c: 22757}, 22762,
- 22765, {f: 2, c: 22769}, {f: 2, c: 22772}, {f: 2, c: 22775},
- {f: 2, c: 22779}, {f: 4, c: 22782}, 22787, {f: 2, c: 22789},
- {f: 2, c: 22792}, [12066, 22794], {f: 2, c: 22795}, 22798,
- {f: 4, c: 22800}, {f: 2, c: 22807}, 22811, {f: 2, c: 22813},
- {f: 2, c: 22816}, 22819, 22822, 22824, 22828, 22832, {f: 2, c: 22834},
- {f: 2, c: 22837}, 22843, 22845, {f: 2, c: 22847}, 22851, {f: 2, c: 22853},
- 22858, {f: 2, c: 22860}, 22864, {f: 2, c: 22866}, 22873, {f: 5, c: 22875},
- 22881, {f: 2, c: 22883}, {f: 3, c: 22886}, 22891, 22893, {f: 4, c: 22895},
- 22901, 22903, {f: 3, c: 22906}, {f: 3, c: 22910}, 22917, 22921,
- {f: 2, c: 22923}, {f: 4, c: 22926}, {f: 2, c: 22932}, 22936,
- {f: 3, c: 22938}, {f: 4, c: 22943}, {f: 2, c: 22950}, {f: 2, c: 22956},
- {f: 2, c: 22960}, {f: 6, c: 22963}, 22970, {f: 2, c: 22972},
- {f: 7, c: 22975}, {f: 3, c: 22983}, {f: 4, c: 22988}, {f: 2, c: 22997},
- 23001, 23003, {f: 5, c: 23006}, 23012, {f: 2, c: 23014}, {f: 3, c: 23017},
- {f: 12, c: 23021}, 23034, {f: 3, c: 23036}, 23040, 23042, {f: 2, c: 23050},
- {f: 4, c: 23053}, 23058, {f: 4, c: 23060}, {f: 3, c: 23065},
- {f: 2, c: 23069}, {f: 2, c: 23073}, 23076, {f: 3, c: 23078},
- {f: 7, c: 23082}, 23091, 23093, {f: 5, c: 23095}, {f: 3, c: 23101},
- {f: 4, c: 23106}, {f: 2, c: 23111}, {f: 10, c: 23115}, {f: 4, c: 23126},
- {f: 7, c: 23131}, {f: 3, c: 23139}, {f: 2, c: 23144}, {f: 2, c: 23147},
- {f: 6, c: 23150}, {f: 2, c: 23160}, {f: 4, c: 23163}, {f: 18, c: 23168},
- {f: 7, c: 23187}, {f: 11, c: 23196}, {f: 2, c: 23208}, {f: 7, c: 23211},
- 23220, {f: 2, c: 23222}, {f: 4, c: 23225}, {f: 2, c: 23231},
- {f: 6, c: 23235}, {f: 2, c: 23242}, {f: 5, c: 23245}, 23251, 23253,
- {f: 3, c: 23257}, {f: 3, c: 23261}, 23266, {f: 2, c: 23268},
- {f: 2, c: 23271}, 23274, {f: 5, c: 23276}, {f: 3, c: 23282},
- {f: 5, c: 23286}, {f: 4, c: 23292}, {f: 7, c: 23297}, 23306,
- {f: 9, c: 23309}, 23320, {f: 7, c: 23322}, {f: 8, c: 23330},
- {f: 5, c: 23339}, 23345, 23347, {f: 2, c: 23349}, {f: 7, c: 23353},
- {f: 11, c: 23361}, {f: 3, c: 23373}, 23378, 23382, 23390, {f: 2, c: 23392},
- {f: 2, c: 23399}, {f: 3, c: 23405}, 23410, 23412, {f: 2, c: 23414}, 23417,
- {f: 2, c: 23419}, 23422, 23426, 23430, 23434, {f: 2, c: 23437},
- {f: 3, c: 23440}, 23444, 23446, 23455, {f: 3, c: 23463}, {f: 4, c: 23468},
- {f: 2, c: 23473}, 23479, {f: 3, c: 23482}, {f: 2, c: 23488}, 23491,
- {f: 4, c: 23496}, {f: 3, c: 23501}, 23505, {f: 9, c: 23508}, 23520, 23523,
- 23530, 23533, 23535, {f: 4, c: 23537}, 23543, {f: 2, c: 23549}, 23552,
- {f: 2, c: 23554}, 23557, 23564, 23568, {f: 2, c: 23570}, 23575, 23577,
- 23579, {f: 4, c: 23582}, 23587, 23590, {f: 4, c: 23592}, {f: 4, c: 23597},
- {f: 2, c: 23602}, {f: 2, c: 23605}, {f: 2, c: 23619}, {f: 2, c: 23622},
- {f: 2, c: 23628}, {f: 3, c: 23634}, {f: 3, c: 23638}, {f: 4, c: 23642},
- 23647, 23655, {f: 3, c: 23657}, 23661, 23664, {f: 7, c: 23666},
- {f: 4, c: 23675}, 23680, {f: 5, c: 23683}, {f: 3, c: 23689},
- {f: 2, c: 23694}, {f: 2, c: 23698}, 23701, {f: 4, c: 23709},
- {f: 5, c: 23716}, 23722, {f: 3, c: 23726}, 23730, 23732, 23734,
- {f: 4, c: 23737}, 23742, 23744, {f: 2, c: 23746}, {f: 6, c: 23749},
- {f: 6, c: 23756}, {f: 6, c: 23763}, {f: 7, c: 23770}, {f: 2, c: 23778},
- 23783, 23785, {f: 2, c: 23787}, {f: 2, c: 23790}, {f: 3, c: 23793}, 23797,
- {f: 4, c: 23799}, 23804, {f: 4, c: 23806}, {f: 2, c: 23812},
- {f: 5, c: 23816}, {f: 5, c: 23823}, 23829, {f: 3, c: 23832},
- {f: 2, c: 23836}, {f: 5, c: 23839}, 23845, 23848, {f: 2, c: 23850},
- {f: 5, c: 23855}, {f: 8, c: 23861}, {f: 8, c: 23871}, {f: 2, c: 23880},
- {f: 3, c: 23885}, {f: 7, c: 23889}, {f: 2, c: 23897}, 23900,
- {f: 11, c: 23902}, 23914, {f: 2, c: 23917}, {f: 4, c: 23920},
- {f: 12, c: 23925}, 23939, {f: 2, c: 23941}, {f: 15, c: 23944}, 23960,
- {f: 3, c: 23962}, {f: 2, c: 23966}, {f: 6, c: 23969}, {f: 15, c: 23976},
- 23993, 23995, {f: 8, c: 23997}, {f: 5, c: 24006}, 24012, {f: 4, c: 24014},
- 24019, {f: 6, c: 24021}, 24028, {f: 2, c: 24031}, {f: 2, c: 24035}, 24042,
- {f: 2, c: 24044}, {f: 2, c: 24053}, {f: 5, c: 24056}, {f: 2, c: 24063},
- 24068, 24071, {f: 3, c: 24073}, {f: 2, c: 24077}, {f: 2, c: 24082}, 24087,
- {f: 7, c: 24094}, {f: 3, c: 24104}, 24108, {f: 2, c: 24111}, 24114,
- {f: 2, c: 24116}, {f: 2, c: 24121}, {f: 2, c: 24126}, 24129,
- {f: 6, c: 24134}, {f: 7, c: 24141}, 24150, {f: 2, c: 24153},
- {f: 2, c: 24156}, 24160, {f: 7, c: 24164}, {f: 5, c: 24173}, 24181, 24183,
- {f: 3, c: 24193}, 24197, {f: 2, c: 24200}, {f: 3, c: 24204}, 24210, 24216,
- 24219, 24221, {f: 4, c: 24225}, {f: 3, c: 24232}, 24236, {f: 5, c: 24238},
- 24244, {f: 4, c: 24250}, {f: 10, c: 24255}, {f: 6, c: 24267},
- {f: 2, c: 24276}, {f: 4, c: 24279}, {f: 3, c: 24284}, {f: 4, c: 24292},
- 24297, 24299, {f: 6, c: 24301}, 24309, {f: 2, c: 24312}, {f: 3, c: 24315},
- {f: 3, c: 24325}, 24329, {f: 3, c: 24332}, 24336, 24338, 24340, 24342,
- {f: 2, c: 24345}, {f: 3, c: 24348}, {f: 4, c: 24353}, 24360,
- {f: 2, c: 24363}, 24366, 24368, 24370, 24372, {f: 3, c: 24374}, 24379,
- {f: 3, c: 24381}, {f: 5, c: 24385}, 24391, {f: 3, c: 24393}, 24397, 24399,
- 24401, 24404, {f: 3, c: 24410}, {f: 3, c: 24414}, 24419, 24421,
- {f: 2, c: 24423}, 24427, {f: 2, c: 24430}, 24434, {f: 3, c: 24436}, 24440,
- 24442, {f: 3, c: 24445}, 24451, 24454, {f: 3, c: 24461}, {f: 2, c: 24467},
- 24470, {f: 2, c: 24474}, 24477, 24479, {f: 6, c: 24482}, {f: 2, c: 24491},
- {f: 6, c: 24495}, 24502, 24504, {f: 2, c: 24506}, {f: 5, c: 24510},
- {f: 2, c: 24519}, {f: 2, c: 24522}, 24526, {f: 3, c: 24531},
- {f: 3, c: 24538}, {f: 2, c: 24542}, {f: 2, c: 24546}, {f: 2, c: 24549},
- {f: 2, c: 24552}, 24556, {f: 2, c: 24559}, {f: 3, c: 24562},
- {f: 2, c: 24566}, {f: 2, c: 24569}, 24572, {f: 3, c: 24583},
- {f: 2, c: 24587}, {f: 2, c: 24592}, 24595, {f: 2, c: 24599}, 24602,
- {f: 2, c: 24606}, {f: 3, c: 24610}, {f: 3, c: 24620}, {f: 5, c: 24624},
- {f: 5, c: 24630}, {f: 2, c: 24637}, 24640, {f: 7, c: 24644}, 24652,
- {f: 2, c: 24654}, 24657, {f: 2, c: 24659}, {f: 3, c: 24662},
- {f: 2, c: 24667}, {f: 4, c: 24670}, {f: 2, c: 24677}, 24686,
- {f: 2, c: 24689}, {f: 2, c: 24692}, 24695, 24702, {f: 3, c: 24704},
- {f: 4, c: 24709}, {f: 2, c: 24714}, {f: 4, c: 24718}, 24723, 24725,
- {f: 3, c: 24727}, 24732, 24734, {f: 2, c: 24737}, {f: 2, c: 24740}, 24743,
- {f: 2, c: 24745}, 24750, 24752, 24755, 24759, {f: 2, c: 24761},
- {f: 8, c: 24765}, {f: 3, c: 24775}, {f: 5, c: 24780}, {f: 3, c: 24786},
- {f: 2, c: 24790}, 24793, 24795, 24798, {f: 4, c: 24802}, 24810, 24821,
- {f: 2, c: 24823}, {f: 4, c: 24828}, {f: 4, c: 24834}, 24839,
- {f: 3, c: 24842}, {f: 5, c: 24848}, {f: 4, c: 24854}, {f: 2, c: 24861},
- {f: 2, c: 24865}, 24869, {f: 3, c: 24872}, {f: 8, c: 24876},
- {f: 2, c: 24885}, {f: 6, c: 24888}, {f: 8, c: 24896}, 24905, 24909,
- {f: 2, c: 24911}, {f: 3, c: 24914}, {f: 2, c: 24918}, 24921,
- {f: 2, c: 24923}, 24926, {f: 2, c: 24928}, {f: 2, c: 24933}, 24937,
- {f: 2, c: 24940}, 24943, {f: 2, c: 24945}, 24948, {f: 10, c: 24952},
- {f: 7, c: 24963}, {f: 2, c: 24972}, 24975, 24979, {f: 5, c: 24981},
- {f: 2, c: 24987}, {f: 6, c: 24990}, {f: 2, c: 24997}, 25002, 25005,
- {f: 3, c: 25007}, {f: 3, c: 25011}, {f: 6, c: 25016}, {f: 3, c: 25023},
- {f: 4, c: 25027}, {f: 4, c: 25037}, 25043, {f: 9, c: 25045},
- {f: 3, c: 25056}, {f: 2, c: 25060}, 25063, {f: 9, c: 25065},
- {f: 2, c: 25075}, 25081, 25083, 25085, {f: 5, c: 25089}, 25097, 25107,
- 25113, {f: 3, c: 25116}, 25120, 25123, 25126, {f: 2, c: 25128}, 25131,
- 25133, 25135, 25137, 25141, [12094, 25142], {f: 5, c: 25144}, 25154,
- {f: 3, c: 25156}, 25162, {f: 2, c: 25167}, {f: 3, c: 25173},
- {f: 2, c: 25177}, {f: 7, c: 25180}, {f: 2, c: 25188}, 25192,
- {f: 2, c: 25201}, {f: 2, c: 25204}, {f: 2, c: 25207}, {f: 2, c: 25210},
- 25213, {f: 3, c: 25217}, {f: 4, c: 25221}, {f: 6, c: 25227}, 25236, 25241,
- {f: 3, c: 25244}, 25251, {f: 2, c: 25254}, {f: 2, c: 25257},
- {f: 4, c: 25261}, {f: 3, c: 25266}, {f: 3, c: 25270}, 25274, 25278,
- {f: 2, c: 25280}, 25283, 25291, 25295, 25297, 25301, {f: 2, c: 25309},
- {f: 2, c: 25312}, 25316, {f: 2, c: 25322}, 25328, 25330, 25333,
- {f: 4, c: 25336}, 25344, {f: 4, c: 25347}, {f: 4, c: 25354},
- {f: 2, c: 25359}, {f: 4, c: 25362}, {f: 3, c: 25367}, 25372,
- {f: 2, c: 25382}, 25385, {f: 3, c: 25388}, {f: 2, c: 25392},
- {f: 6, c: 25395}, {f: 2, c: 25403}, {f: 3, c: 25407}, 25412,
- {f: 2, c: 25415}, 25418, {f: 4, c: 25425}, {f: 8, c: 25430}, 25440,
- {f: 3, c: 25444}, 25450, 25452, {f: 2, c: 25455}, {f: 3, c: 25459},
- {f: 2, c: 25464}, {f: 4, c: 25468}, 25473, {f: 2, c: 25477}, 25483, 25485,
- 25489, {f: 3, c: 25491}, 25495, {f: 7, c: 25497}, 25505, 25508, 25510,
- 25515, 25519, {f: 2, c: 25521}, {f: 2, c: 25525}, 25529, 25531, 25533,
- 25535, {f: 3, c: 25537}, 25541, {f: 2, c: 25543}, {f: 3, c: 25546}, 25553,
- {f: 3, c: 25555}, {f: 3, c: 25559}, {f: 3, c: 25563}, 25567, 25570,
- {f: 5, c: 25572}, {f: 2, c: 25579}, {f: 3, c: 25583}, 25587, 25589, 25591,
- {f: 4, c: 25593}, 25598, {f: 2, c: 25603}, {f: 5, c: 25606}, 25614,
- {f: 2, c: 25617}, {f: 2, c: 25621}, {f: 3, c: 25624}, 25629, 25631,
- {f: 4, c: 25634}, {f: 3, c: 25639}, 25643, {f: 6, c: 25646}, 25653,
- {f: 3, c: 25655}, {f: 2, c: 25659}, 25662, 25664, {f: 2, c: 25666}, 25673,
- {f: 6, c: 25675}, 25683, {f: 3, c: 25685}, {f: 3, c: 25689}, 25693,
- {f: 7, c: 25696}, 25704, {f: 3, c: 25706}, 25710, {f: 3, c: 25712},
- {f: 2, c: 25716}, 25719, {f: 6, c: 25724}, 25731, 25734, {f: 8, c: 25737},
- 25748, {f: 2, c: 25751}, {f: 4, c: 25754}, {f: 3, c: 25760},
- {f: 3, c: 25766}, 25770, 25775, 25777, 25780, 25782, 25785, 25789, 25795,
- 25798, {f: 2, c: 25800}, 25804, 25807, 25809, 25811, {f: 2, c: 25813},
- 25817, {f: 3, c: 25819}, 25823, 25825, 25827, 25829, {f: 5, c: 25831},
- {f: 2, c: 25837}, 25843, {f: 2, c: 25845}, {f: 2, c: 25848}, 25853, 25855,
- {f: 3, c: 25857}, 25861, {f: 2, c: 25863}, {f: 5, c: 25866},
- {f: 2, c: 25872}, 25875, 25877, 25879, 25882, 25884, {f: 4, c: 25886},
- {f: 4, c: 25894}, 25901, {f: 4, c: 25904}, 25911, 25914, {f: 2, c: 25916},
- {f: 5, c: 25920}, {f: 2, c: 25926}, {f: 2, c: 25930}, {f: 2, c: 25933},
- 25936, {f: 3, c: 25938}, 25944, 25946, 25948, {f: 3, c: 25951},
- {f: 2, c: 25956}, {f: 4, c: 25959}, {f: 3, c: 25965}, 25969, 25971, 25974,
- {f: 9, c: 25977}, {f: 3, c: 25988}, {f: 3, c: 25992}, {f: 3, c: 25997},
- 26002, 26004, 26006, 26008, 26010, {f: 2, c: 26013}, 26016,
- {f: 2, c: 26018}, 26022, 26024, 26026, 26030, {f: 6, c: 26033}, 26040,
- {f: 2, c: 26042}, {f: 3, c: 26046}, 26050, {f: 4, c: 26055}, 26061,
- {f: 2, c: 26064}, {f: 3, c: 26067}, {f: 8, c: 26072}, 26081,
- {f: 2, c: 26083}, {f: 2, c: 26090}, {f: 4, c: 26098}, {f: 2, c: 26104},
- {f: 5, c: 26107}, 26113, {f: 2, c: 26116}, {f: 3, c: 26119}, 26123, 26125,
- {f: 3, c: 26128}, {f: 3, c: 26134}, {f: 3, c: 26138}, 26142,
- {f: 4, c: 26145}, 26150, {f: 4, c: 26153}, 26158, 26160, {f: 2, c: 26162},
- {f: 5, c: 26167}, 26173, {f: 2, c: 26175}, {f: 7, c: 26180},
- {f: 2, c: 26189}, {f: 2, c: 26192}, {f: 2, c: 26200}, {f: 2, c: 26203},
- 26206, 26208, {f: 2, c: 26210}, 26213, 26215, {f: 5, c: 26217},
- {f: 3, c: 26225}, 26229, {f: 2, c: 26232}, {f: 3, c: 26235},
- {f: 3, c: 26239}, 26243, {f: 2, c: 26245}, {f: 2, c: 26250},
- {f: 4, c: 26253}, {f: 4, c: 26258}, {f: 5, c: 26264}, {f: 4, c: 26270},
- {f: 4, c: 26275}, {f: 2, c: 26281}, {f: 2, c: 26284}, {f: 5, c: 26287},
- {f: 4, c: 26293}, {f: 4, c: 26298}, {f: 5, c: 26303}, 26309, 26312,
- {f: 12, c: 26314}, {f: 2, c: 26327}, 26330, {f: 2, c: 26334},
- {f: 5, c: 26337}, {f: 2, c: 26343}, {f: 2, c: 26346}, {f: 3, c: 26349},
- 26353, {f: 2, c: 26357}, {f: 2, c: 26362}, 26365, {f: 2, c: 26369},
- {f: 4, c: 26372}, 26380, {f: 2, c: 26382}, {f: 3, c: 26385}, 26390,
- {f: 3, c: 26392}, 26396, 26398, {f: 6, c: 26400}, 26409, 26414, 26416,
- {f: 2, c: 26418}, {f: 4, c: 26422}, {f: 2, c: 26427}, {f: 2, c: 26430},
- 26433, {f: 2, c: 26436}, 26439, {f: 2, c: 26442}, 26445, 26450,
- {f: 2, c: 26452}, {f: 5, c: 26455}, 26461, {f: 3, c: 26466},
- {f: 2, c: 26470}, {f: 2, c: 26475}, 26478, 26484, 26486, {f: 4, c: 26488},
- 26493, 26496, {f: 2, c: 26498}, {f: 2, c: 26501}, 26504, 26506,
- {f: 4, c: 26508}, {f: 4, c: 26513}, 26518, 26521, 26523, {f: 3, c: 26527},
- 26532, 26534, 26537, 26540, 26542, {f: 2, c: 26545}, 26548,
- {f: 8, c: 26553}, 26562, {f: 10, c: 26565}, {f: 3, c: 26581}, 26587, 26591,
- 26593, {f: 2, c: 26595}, {f: 3, c: 26598}, {f: 2, c: 26602},
- {f: 2, c: 26605}, 26610, {f: 8, c: 26613}, 26622, {f: 4, c: 26625}, 26630,
- 26637, 26640, 26642, {f: 2, c: 26644}, {f: 5, c: 26648}, {f: 3, c: 26654},
- {f: 7, c: 26658}, {f: 7, c: 26667}, {f: 3, c: 26676}, {f: 2, c: 26682},
- 26687, 26695, 26699, 26701, 26703, 26706, {f: 10, c: 26710}, 26730,
- {f: 8, c: 26732}, 26741, {f: 9, c: 26744}, 26754, 26756, {f: 8, c: 26759},
- {f: 3, c: 26768}, {f: 3, c: 26772}, {f: 4, c: 26777}, 26782,
- {f: 2, c: 26784}, {f: 3, c: 26787}, {f: 4, c: 26793}, 26798,
- {f: 2, c: 26801}, 26804, {f: 10, c: 26806}, 26817, {f: 6, c: 26819}, 26826,
- 26828, {f: 4, c: 26830}, {f: 2, c: 26835}, 26841, {f: 4, c: 26843},
- {f: 2, c: 26849}, {f: 3, c: 26852}, {f: 6, c: 26856}, 26863,
- {f: 3, c: 26866}, {f: 3, c: 26870}, 26875, {f: 4, c: 26877},
- {f: 3, c: 26882}, {f: 5, c: 26886}, 26892, 26897, {f: 12, c: 26899},
- {f: 3, c: 26913}, {f: 8, c: 26917}, {f: 2, c: 26926}, {f: 3, c: 26929},
- {f: 4, c: 26933}, {f: 3, c: 26938}, 26942, {f: 2, c: 26944},
- {f: 7, c: 26947}, {f: 8, c: 26955}, {f: 2, c: 26965}, {f: 2, c: 26968},
- {f: 2, c: 26971}, 26975, {f: 2, c: 26977}, {f: 2, c: 26980}, 26983,
- {f: 2, c: 26985}, 26988, {f: 2, c: 26991}, {f: 3, c: 26994}, 26998,
- {f: 2, c: 27002}, {f: 3, c: 27005}, 27009, 27011, 27013, {f: 3, c: 27018},
- {f: 6, c: 27022}, {f: 2, c: 27030}, {f: 2, c: 27033}, {f: 10, c: 27037},
- 27049, 27052, {f: 2, c: 27055}, {f: 2, c: 27058}, {f: 2, c: 27061},
- {f: 3, c: 27064}, {f: 3, c: 27068}, 27072, {f: 8, c: 27074}, 27087,
- {f: 3, c: 27089}, {f: 6, c: 27093}, {f: 3, c: 27100}, {f: 6, c: 27105},
- {f: 5, c: 27112}, {f: 4, c: 27118}, {f: 9, c: 27124}, 27134, 27136,
- {f: 2, c: 27139}, {f: 4, c: 27142}, {f: 8, c: 27147}, {f: 3, c: 27156},
- {f: 4, c: 27162}, 27168, 27170, {f: 4, c: 27172}, 27177, {f: 4, c: 27179},
- 27184, {f: 3, c: 27186}, {f: 2, c: 27190}, {f: 2, c: 27195},
- {f: 5, c: 27199}, {f: 2, c: 27205}, {f: 2, c: 27209}, {f: 4, c: 27212},
- {f: 7, c: 27217}, 27226, {f: 3, c: 27228}, 27232, {f: 2, c: 27235},
- {f: 11, c: 27238}, {f: 7, c: 27250}, {f: 2, c: 27258}, {f: 3, c: 27261},
- {f: 3, c: 27265}, {f: 4, c: 27269}, {f: 4, c: 27274}, 27279,
- {f: 2, c: 27282}, {f: 2, c: 27285}, {f: 4, c: 27288}, {f: 3, c: 27293},
- 27297, {f: 5, c: 27300}, 27306, {f: 2, c: 27309}, {f: 3, c: 27312},
- {f: 4, c: 27316}, {f: 2, c: 27321}, {f: 7, c: 27324}, {f: 15, c: 27332},
- {f: 6, c: 27348}, 27356, {f: 7, c: 27360}, 27369, 27371, {f: 6, c: 27373},
- {f: 4, c: 27380}, {f: 2, c: 27385}, {f: 8, c: 27388}, {f: 5, c: 27397},
- {f: 4, c: 27403}, {f: 2, c: 27408}, {f: 3, c: 27411}, {f: 7, c: 27415},
- 27423, {f: 2, c: 27429}, {f: 10, c: 27432}, {f: 4, c: 27443}, 27448,
- {f: 2, c: 27451}, {f: 4, c: 27455}, {f: 2, c: 27460}, 27464,
- {f: 2, c: 27466}, {f: 3, c: 27469}, {f: 8, c: 27473}, {f: 5, c: 27482},
- 27488, {f: 2, c: 27496}, {f: 7, c: 27499}, {f: 4, c: 27507}, 27514,
- {f: 4, c: 27517}, 27525, 27528, 27532, {f: 4, c: 27534}, {f: 2, c: 27540},
- 27543, 27545, {f: 2, c: 27548}, {f: 2, c: 27551}, {f: 2, c: 27554},
- {f: 5, c: 27557}, {f: 2, c: 27564}, {f: 2, c: 27568}, 27574,
- {f: 2, c: 27576}, {f: 3, c: 27580}, 27584, {f: 2, c: 27587},
- {f: 4, c: 27591}, 27596, 27598, {f: 2, c: 27600}, 27608, 27610,
- {f: 5, c: 27612}, {f: 8, c: 27618}, {f: 3, c: 27628}, {f: 3, c: 27632},
- 27636, {f: 3, c: 27638}, {f: 3, c: 27642}, 27646, {f: 5, c: 27648},
- {f: 3, c: 27657}, 27662, 27666, 27671, {f: 3, c: 27676}, 27680, 27685,
- 27693, 27697, 27699, {f: 2, c: 27702}, {f: 4, c: 27705}, {f: 2, c: 27710},
- {f: 3, c: 27715}, 27720, {f: 5, c: 27723}, {f: 3, c: 27729}, 27734,
- {f: 3, c: 27736}, {f: 2, c: 27746}, {f: 3, c: 27749}, {f: 5, c: 27755},
- 27761, 27763, 27765, {f: 2, c: 27767}, {f: 3, c: 27770}, {f: 2, c: 27775},
- 27780, 27783, {f: 2, c: 27786}, {f: 2, c: 27789}, {f: 2, c: 27793},
- {f: 4, c: 27797}, 27802, {f: 3, c: 27804}, 27808, 27810, 27816, 27820,
- {f: 2, c: 27823}, {f: 4, c: 27828}, 27834, {f: 4, c: 27840},
- {f: 3, c: 27846}, 27851, {f: 3, c: 27853}, {f: 2, c: 27857},
- {f: 3, c: 27864}, {f: 2, c: 27868}, 27871, 27876, {f: 2, c: 27878}, 27881,
- {f: 2, c: 27884}, 27890, 27892, 27897, {f: 2, c: 27903}, {f: 2, c: 27906},
- {f: 2, c: 27909}, {f: 3, c: 27912}, 27917, {f: 3, c: 27919},
- {f: 4, c: 27923}, 27928, {f: 2, c: 27932}, {f: 6, c: 27935}, 27942,
- {f: 2, c: 27944}, {f: 2, c: 27948}, {f: 2, c: 27951}, 27956,
- {f: 3, c: 27958}, 27962, {f: 2, c: 27967}, 27970, 27972, 27977, 27980,
- 27984, {f: 4, c: 27989}, 27995, 27997, 27999, {f: 2, c: 28001},
- {f: 2, c: 28004}, {f: 2, c: 28007}, {f: 3, c: 28011}, {f: 4, c: 28016},
- {f: 2, c: 28021}, {f: 2, c: 28026}, {f: 5, c: 28029}, {f: 2, c: 28035},
- 28038, {f: 2, c: 28042}, 28045, {f: 2, c: 28047}, 28050, {f: 5, c: 28054},
- 28060, 28066, 28069, {f: 2, c: 28076}, {f: 2, c: 28080}, {f: 2, c: 28083},
- {f: 2, c: 28086}, {f: 6, c: 28089}, {f: 3, c: 28097}, {f: 3, c: 28104},
- {f: 4, c: 28109}, {f: 4, c: 28114}, 28119, {f: 3, c: 28122}, 28127,
- {f: 2, c: 28130}, 28133, {f: 3, c: 28135}, 28141, {f: 2, c: 28143}, 28146,
- 28148, 28152, {f: 8, c: 28157}, {f: 4, c: 28166}, 28171, 28175,
- {f: 2, c: 28178}, 28181, {f: 2, c: 28184}, {f: 2, c: 28187},
- {f: 2, c: 28190}, 28194, {f: 2, c: 28199}, 28202, 28206, {f: 2, c: 28208},
- 28211, {f: 3, c: 28213}, 28217, {f: 3, c: 28219}, {f: 4, c: 28223},
- {f: 8, c: 28229}, {f: 4, c: 28239}, 28245, 28247, {f: 2, c: 28249},
- {f: 2, c: 28252}, {f: 11, c: 28256}, {f: 2, c: 28268}, {f: 14, c: 28272},
- {f: 3, c: 28288}, 28292, {f: 2, c: 28295}, {f: 5, c: 28298},
- {f: 5, c: 28305}, 28311, {f: 3, c: 28313}, 28318, {f: 2, c: 28320},
- {f: 2, c: 28323}, 28326, {f: 2, c: 28328}, {f: 4, c: 28331}, 28336, 28339,
- 28341, {f: 2, c: 28344}, 28348, {f: 3, c: 28350}, 28355, 28358,
- {f: 3, c: 28360}, 28365, 28368, 28370, 28374, {f: 2, c: 28376},
- {f: 3, c: 28379}, 28387, 28391, {f: 2, c: 28394}, {f: 2, c: 28397},
- {f: 2, c: 28400}, 28403, {f: 2, c: 28405}, {f: 5, c: 28410}, 28416,
- {f: 3, c: 28419}, {f: 2, c: 28423}, {f: 5, c: 28426}, {f: 3, c: 28432},
- {f: 4, c: 28438}, {f: 5, c: 28443}, 28449, {f: 4, c: 28453}, 28462, 28464,
- {f: 2, c: 28468}, 28471, {f: 5, c: 28473}, 28480, {f: 4, c: 28482},
- {f: 3, c: 28488}, 28492, {f: 3, c: 28494}, {f: 2, c: 28498},
- {f: 3, c: 28501}, {f: 2, c: 28506}, 28509, {f: 3, c: 28511}, 28515, 28517,
- {f: 6, c: 28519}, 28529, 28531, {f: 2, c: 28533}, 28537, 28539,
- {f: 2, c: 28541}, {f: 3, c: 28545}, 28549, {f: 2, c: 28554},
- {f: 8, c: 28559}, {f: 4, c: 28568}, {f: 3, c: 28573}, {f: 2, c: 28578},
- {f: 2, c: 28581}, 28584, {f: 4, c: 28586}, {f: 2, c: 28591}, 28594,
- {f: 2, c: 28596}, {f: 2, c: 28599}, {f: 6, c: 28602}, {f: 5, c: 28612},
- {f: 7, c: 28618}, {f: 2, c: 28627}, {f: 2, c: 28630}, {f: 2, c: 28633},
- {f: 2, c: 28636}, {f: 2, c: 28642}, {f: 6, c: 28645}, {f: 2, c: 28652},
- {f: 8, c: 28658}, 28667, 28669, {f: 6, c: 28671}, {f: 2, c: 28679}, 28682,
- {f: 3, c: 28684}, 28688, {f: 3, c: 28690}, {f: 2, c: 28694}, 28697, 28700,
- 28702, {f: 2, c: 28705}, {f: 3, c: 28708}, {f: 7, c: 28713}, 28721,
- {f: 2, c: 28723}, {f: 3, c: 28726}, {f: 4, c: 28730}, {f: 4, c: 28735},
- {f: 7, c: 28741}, {f: 2, c: 28749}, 28752, {f: 3, c: 28754},
- {f: 2, c: 28758}, {f: 4, c: 28761}, {f: 4, c: 28767}, {f: 2, c: 28773},
- {f: 3, c: 28776}, 28782, {f: 4, c: 28785}, 28791, {f: 3, c: 28793}, 28797,
- {f: 4, c: 28801}, {f: 3, c: 28806}, {f: 3, c: 28811}, {f: 3, c: 28815},
- 28819, {f: 2, c: 28823}, {f: 2, c: 28826}, {f: 13, c: 28830}, 28848, 28850,
- {f: 3, c: 28852}, 28858, {f: 2, c: 28862}, {f: 4, c: 28868}, 28873,
- {f: 4, c: 28875}, {f: 8, c: 28880}, 28890, {f: 3, c: 28892},
- {f: 4, c: 28896}, 28901, 28906, 28910, {f: 4, c: 28912}, {f: 2, c: 28917},
- 28920, {f: 3, c: 28922}, {f: 11, c: 28926}, {f: 5, c: 28939},
- {f: 2, c: 28945}, 28948, 28951, {f: 6, c: 28955}, {f: 4, c: 28962},
- {f: 8, c: 28967}, {f: 4, c: 28978}, {f: 14, c: 28983}, {f: 3, c: 28998},
- 29003, 29005, {f: 3, c: 29007}, {f: 9, c: 29011}, 29021, {f: 3, c: 29023},
- 29027, 29029, {f: 2, c: 29034}, 29037, {f: 3, c: 29039}, {f: 4, c: 29044},
- 29049, {f: 2, c: 29051}, {f: 6, c: 29054}, {f: 5, c: 29061},
- {f: 4, c: 29067}, {f: 2, c: 29072}, 29075, {f: 2, c: 29077},
- {f: 5, c: 29082}, {f: 7, c: 29089}, {f: 3, c: 29097}, {f: 4, c: 29101},
- 29106, 29108, {f: 3, c: 29110}, {f: 4, c: 29114}, {f: 2, c: 29119}, 29122,
- {f: 4, c: 29124}, {f: 5, c: 29129}, {f: 3, c: 29135}, 29139,
- {f: 3, c: 29142}, {f: 2, c: 29146}, {f: 2, c: 29149}, {f: 4, c: 29153},
- {f: 5, c: 29160}, {f: 5, c: 29167}, {f: 4, c: 29173}, {f: 2, c: 29178},
- 29181, {f: 7, c: 29183}, {f: 6, c: 29191}, {f: 2, c: 29198},
- {f: 10, c: 29201}, 29212, {f: 10, c: 29214}, 29225, 29227,
- {f: 3, c: 29229}, {f: 2, c: 29235}, 29244, {f: 7, c: 29248},
- {f: 3, c: 29257}, {f: 4, c: 29262}, {f: 3, c: 29267}, 29271, 29274, 29276,
- 29278, 29280, {f: 3, c: 29283}, 29288, {f: 4, c: 29290}, {f: 2, c: 29296},
- {f: 2, c: 29299}, {f: 3, c: 29302}, {f: 2, c: 29307}, {f: 2, c: 29314},
- {f: 5, c: 29317}, 29324, 29326, {f: 2, c: 29328}, {f: 3, c: 29331},
- {f: 8, c: 29335}, {f: 2, c: 29344}, {f: 4, c: 29347}, {f: 4, c: 29352},
- 29358, {f: 3, c: 29361}, 29365, {f: 6, c: 29370}, {f: 3, c: 29381},
- {f: 4, c: 29385}, 29391, 29393, {f: 4, c: 29395}, 29400, {f: 4, c: 29402},
- 29407, {f: 6, c: 29410}, {f: 2, c: 29418}, {f: 2, c: 29429},
- {f: 3, c: 29438}, 29442, {f: 6, c: 29444}, {f: 3, c: 29451},
- {f: 4, c: 29455}, 29460, {f: 3, c: 29464}, {f: 2, c: 29471},
- {f: 2, c: 29475}, {f: 3, c: 29478}, 29485, {f: 2, c: 29487},
- {f: 2, c: 29490}, 29493, 29498, {f: 2, c: 29500}, 29504, {f: 2, c: 29506},
- {f: 7, c: 29510}, {f: 2, c: 29518}, 29521, {f: 4, c: 29523},
- {f: 8, c: 29528}, {f: 7, c: 29537}, 29545, 29550, 29553, {f: 2, c: 29555},
- 29558, 29561, 29565, 29567, {f: 3, c: 29569}, {f: 2, c: 29573}, 29576,
- 29578, {f: 2, c: 29580}, {f: 2, c: 29583}, {f: 4, c: 29586},
- {f: 4, c: 29591}, {f: 3, c: 29596}, {f: 2, c: 29600}, {f: 6, c: 29603},
- 29610, {f: 2, c: 29612}, 29617, {f: 3, c: 29620}, {f: 2, c: 29624},
- {f: 4, c: 29628}, 29633, {f: 5, c: 29635}, {f: 2, c: 29643}, 29646,
- {f: 7, c: 29650}, {f: 4, c: 29658}, 29663, {f: 4, c: 29665}, 29670, 29672,
- {f: 3, c: 29674}, {f: 4, c: 29678}, {f: 11, c: 29683}, {f: 4, c: 29695},
- 29700, {f: 2, c: 29703}, {f: 4, c: 29707}, {f: 9, c: 29713},
- {f: 6, c: 29724}, {f: 2, c: 29731}, 29735, 29737, 29739, 29741, 29743,
- {f: 2, c: 29745}, {f: 5, c: 29751}, {f: 2, c: 29757}, 29760,
- {f: 9, c: 29762}, {f: 9, c: 29772}, 29782, 29784, 29789, {f: 3, c: 29792},
- {f: 5, c: 29796}, {f: 2, c: 29803}, {f: 2, c: 29806}, {f: 5, c: 29809},
- {f: 6, c: 29816}, 29823, 29826, {f: 3, c: 29828}, 29832, 29834,
- {f: 2, c: 29836}, 29839, {f: 11, c: 29841}, 29853, {f: 4, c: 29855},
- {f: 2, c: 29860}, {f: 6, c: 29866}, {f: 9, c: 29873}, {f: 2, c: 29883},
- {f: 12, c: 29886}, {f: 4, c: 29899}, {f: 2, c: 29904}, 29907,
- {f: 5, c: 29909}, 29915, 29917, 29919, 29921, 29925, {f: 7, c: 29927},
- {f: 4, c: 29936}, 29941, {f: 7, c: 29944}, {f: 4, c: 29952},
- {f: 7, c: 29957}, 29966, 29968, 29970, {f: 4, c: 29972}, 29979,
- {f: 2, c: 29981}, {f: 3, c: 29984}, 29988, {f: 2, c: 29990}, 29994, 29998,
- 30004, 30006, 30009, {f: 2, c: 30012}, 30015, {f: 4, c: 30017},
- {f: 2, c: 30022}, {f: 2, c: 30025}, 30029, {f: 4, c: 30032},
- {f: 4, c: 30037}, {f: 4, c: 30046}, {f: 2, c: 30051}, {f: 3, c: 30055},
- {f: 6, c: 30060}, 30067, 30069, 30071, {f: 5, c: 30074}, {f: 3, c: 30080},
- {f: 2, c: 30084}, {f: 3, c: 30088}, {f: 3, c: 30092}, 30096, 30099, 30101,
- 30104, {f: 2, c: 30107}, 30110, 30114, {f: 5, c: 30118}, 30125,
- {f: 2, c: 30134}, {f: 2, c: 30138}, {f: 3, c: 30143}, 30150,
- {f: 2, c: 30155}, {f: 4, c: 30158}, 30163, 30167, 30170, {f: 2, c: 30172},
- {f: 3, c: 30175}, 30181, 30185, {f: 4, c: 30188}, {f: 2, c: 30194},
- {f: 4, c: 30197}, {f: 2, c: 30202}, {f: 2, c: 30205}, 30212,
- {f: 4, c: 30214}, {f: 2, c: 30222}, {f: 4, c: 30225}, 30230, 30234,
- {f: 2, c: 30236}, 30243, 30248, 30252, {f: 2, c: 30254}, {f: 2, c: 30257},
- {f: 2, c: 30262}, {f: 2, c: 30265}, 30269, 30273, {f: 2, c: 30276}, 30280,
- {f: 2, c: 30282}, {f: 6, c: 30286}, 30293, 30295, {f: 3, c: 30297}, 30301,
- {f: 2, c: 30304}, 30310, 30312, 30314, {f: 3, c: 30323}, [12136, 30326],
- 30327, {f: 2, c: 30329}, {f: 3, c: 30335}, 30339, 30341, {f: 2, c: 30345},
- {f: 2, c: 30348}, {f: 2, c: 30351}, 30354, {f: 2, c: 30356},
- {f: 2, c: 30359}, {f: 9, c: 30363}, {f: 9, c: 30373}, {f: 2, c: 30383},
- 30387, {f: 3, c: 30389}, 30393, {f: 4, c: 30395}, {f: 2, c: 30400},
- {f: 2, c: 30403}, 30407, 30409, {f: 2, c: 30411}, 30419, 30421,
- {f: 2, c: 30425}, {f: 2, c: 30428}, 30432, 30434, 30438, {f: 6, c: 30440},
- 30448, 30451, {f: 3, c: 30453}, {f: 2, c: 30458}, 30461, {f: 2, c: 30463},
- {f: 2, c: 30466}, {f: 2, c: 30469}, 30474, 30476, {f: 11, c: 30478},
- {f: 4, c: 30491}, 30497, {f: 3, c: 30499}, 30503, {f: 3, c: 30506}, 30510,
- {f: 5, c: 30512}, 30521, 30523, {f: 3, c: 30525}, 30530, {f: 3, c: 30532},
- {f: 7, c: 30536}, {f: 8, c: 30546}, {f: 2, c: 30556}, {f: 2, c: 30559},
- 30564, 30567, {f: 2, c: 30569}, {f: 12, c: 30573}, {f: 3, c: 30586},
- {f: 3, c: 30593}, {f: 6, c: 30598}, {f: 2, c: 30607}, {f: 5, c: 30611},
- {f: 5, c: 30617}, 30625, {f: 2, c: 30627}, 30630, 30632, 30635,
- {f: 2, c: 30638}, {f: 2, c: 30641}, 30644, {f: 5, c: 30646}, 30654,
- {f: 7, c: 30656}, {f: 5, c: 30664}, {f: 9, c: 30670}, {f: 2, c: 30680},
- {f: 5, c: 30685}, 30692, 30694, 30696, 30698, {f: 3, c: 30704},
- {f: 2, c: 30708}, 30711, {f: 4, c: 30713}, {f: 6, c: 30723},
- {f: 2, c: 30730}, {f: 3, c: 30734}, 30739, 30741, 30745, 30747, 30750,
- {f: 3, c: 30752}, 30756, 30760, {f: 2, c: 30762}, {f: 2, c: 30766},
- {f: 3, c: 30769}, {f: 2, c: 30773}, 30781, 30783, {f: 2, c: 30785}, 30788,
- 30790, {f: 4, c: 30792}, 30797, 30799, 30801, {f: 2, c: 30803},
- {f: 5, c: 30808}, {f: 6, c: 30814}, {f: 3, c: 30821}, 30825,
- {f: 7, c: 30832}, {f: 4, c: 30840}, {f: 10, c: 30845}, 30856,
- {f: 2, c: 30858}, {f: 2, c: 30863}, 30866, {f: 3, c: 30868}, 30873,
- {f: 2, c: 30877}, 30880, 30882, 30884, 30886, 30888, {f: 3, c: 30890},
- {f: 2, c: 30894}, {f: 3, c: 30901}, 30907, 30909, {f: 2, c: 30911},
- {f: 3, c: 30914}, {f: 3, c: 30918}, {f: 4, c: 30924}, {f: 3, c: 30929},
- {f: 3, c: 30934}, {f: 8, c: 30939}, {f: 3, c: 30948}, {f: 3, c: 30953},
- {f: 2, c: 30957}, {f: 2, c: 30960}, 30963, {f: 2, c: 30965},
- {f: 2, c: 30968}, {f: 2, c: 30971}, {f: 3, c: 30974}, {f: 3, c: 30978},
- {f: 8, c: 30982}, {f: 4, c: 30991}, {f: 5, c: 30996}, {f: 4, c: 31002},
- {f: 5, c: 31007}, 31013, {f: 3, c: 31015}, {f: 4, c: 31021},
- {f: 2, c: 31026}, {f: 5, c: 31029}, 31037, 31039, {f: 4, c: 31042}, 31047,
- {f: 9, c: 31050}, {f: 2, c: 31060}, {f: 2, c: 31064}, 31073,
- {f: 2, c: 31075}, 31078, {f: 4, c: 31081}, 31086, {f: 7, c: 31088}, 31097,
- {f: 5, c: 31099}, {f: 2, c: 31106}, {f: 4, c: 31110}, {f: 2, c: 31115},
- {f: 10, c: 31120}, {f: 11, c: 31131}, {f: 2, c: 31144}, {f: 3, c: 31147},
- 31151, 31154, {f: 4, c: 31156}, [12145, 31160], 31164, 31167, 31170,
- {f: 2, c: 31172}, {f: 2, c: 31175}, 31178, 31180, {f: 3, c: 31182},
- {f: 2, c: 31187}, {f: 2, c: 31190}, {f: 6, c: 31193}, {f: 3, c: 31200},
- 31205, 31208, 31210, 31212, 31214, {f: 7, c: 31217}, {f: 2, c: 31225},
- 31228, {f: 2, c: 31230}, 31233, {f: 2, c: 31236}, {f: 4, c: 31239}, 31244,
- {f: 5, c: 31247}, {f: 2, c: 31253}, {f: 2, c: 31256}, {f: 3, c: 31259},
- 31263, {f: 2, c: 31265}, {f: 10, c: 31268}, {f: 2, c: 31279}, 31282,
- {f: 3, c: 31284}, 31288, 31290, 31294, {f: 5, c: 31297}, {f: 5, c: 31303},
- {f: 2, c: 31311}, {f: 5, c: 31314}, {f: 9, c: 31320}, {f: 6, c: 31331},
- 31338, {f: 4, c: 31340}, {f: 3, c: 31345}, 31349, {f: 4, c: 31355}, 31362,
- 31365, 31367, {f: 4, c: 31369}, {f: 3, c: 31374}, {f: 2, c: 31379},
- {f: 3, c: 31385}, 31390, {f: 4, c: 31393}, 31399, 31403, {f: 4, c: 31407},
- {f: 2, c: 31412}, {f: 3, c: 31415}, {f: 4, c: 31419}, {f: 4, c: 31424},
- 31430, 31433, {f: 10, c: 31436}, {f: 2, c: 31447}, {f: 4, c: 31450},
- {f: 2, c: 31457}, 31460, {f: 3, c: 31463}, {f: 2, c: 31467}, 31470,
- {f: 6, c: 31472}, {f: 2, c: 31479}, {f: 2, c: 31483}, 31486,
- {f: 3, c: 31488}, 31493, 31495, 31497, {f: 3, c: 31500}, 31504,
- {f: 2, c: 31506}, {f: 3, c: 31510}, 31514, {f: 2, c: 31516}, 31519,
- {f: 3, c: 31521}, 31527, 31529, 31533, {f: 2, c: 31535}, 31538,
- {f: 4, c: 31540}, 31545, 31547, 31549, {f: 6, c: 31551}, 31560, 31562,
- {f: 2, c: 31565}, 31571, 31573, 31575, 31577, 31580, {f: 2, c: 31582},
- 31585, {f: 4, c: 31587}, {f: 6, c: 31592}, {f: 2, c: 31599},
- {f: 2, c: 31603}, 31606, 31608, 31610, {f: 2, c: 31612}, 31615,
- {f: 4, c: 31617}, {f: 5, c: 31622}, 31628, {f: 2, c: 31630},
- {f: 3, c: 31633}, 31638, {f: 4, c: 31640}, {f: 3, c: 31646},
- {f: 3, c: 31651}, {f: 3, c: 31662}, {f: 2, c: 31666}, {f: 3, c: 31669},
- {f: 7, c: 31673}, {f: 2, c: 31682}, 31685, 31688, 31690, {f: 4, c: 31693},
- 31698, {f: 5, c: 31700}, {f: 2, c: 31707}, {f: 3, c: 31710},
- {f: 2, c: 31714}, {f: 2, c: 31719}, {f: 3, c: 31723}, {f: 2, c: 31727},
- 31730, {f: 3, c: 31732}, {f: 4, c: 31736}, 31741, 31743, {f: 6, c: 31745},
- {f: 3, c: 31752}, 31758, {f: 6, c: 31760}, {f: 7, c: 31767}, 31776, 31778,
- {f: 2, c: 31780}, {f: 2, c: 31784}, {f: 12, c: 31788}, {f: 4, c: 31801},
- 31810, {f: 8, c: 31812}, {f: 14, c: 31822}, {f: 2, c: 31837},
- {f: 3, c: 31841}, {f: 4, c: 31845}, 31851, 31853, {f: 3, c: 31855},
- {f: 6, c: 31861}, {f: 11, c: 31870}, {f: 7, c: 31882}, {f: 2, c: 31891},
- 31894, {f: 3, c: 31897}, {f: 2, c: 31904}, 31907, {f: 4, c: 31910},
- {f: 3, c: 31915}, {f: 2, c: 31919}, {f: 5, c: 31924}, {f: 2, c: 31930},
- {f: 2, c: 31935}, {f: 3, c: 31938}, 31942, 31945, 31947, {f: 7, c: 31950},
- 31960, {f: 2, c: 31962}, {f: 6, c: 31969}, {f: 6, c: 31977}, 31985, 31987,
- 31989, 31991, 31994, {f: 2, c: 31996}, 31999, 32001, 32003, 32012,
- {f: 2, c: 32014}, {f: 2, c: 32017}, 32022, 32024, {f: 3, c: 32029},
- {f: 4, c: 32035}, {f: 3, c: 32040}, {f: 3, c: 32044}, {f: 5, c: 32052},
- 32059, {f: 2, c: 32061}, 32065, 32067, 32069, {f: 7, c: 32071}, 32079,
- {f: 12, c: 32081}, {f: 2, c: 32095}, {f: 3, c: 32099}, 32103,
- {f: 5, c: 32105}, {f: 2, c: 32111}, {f: 2, c: 32116}, 32120,
- {f: 7, c: 32122}, 32130, {f: 2, c: 32132}, 32135, {f: 5, c: 32138},
- {f: 3, c: 32144}, {f: 8, c: 32148}, 32157, {f: 3, c: 32159},
- {f: 2, c: 32164}, {f: 4, c: 32167}, 32175, {f: 3, c: 32181}, 32188,
- {f: 4, c: 32192}, {f: 2, c: 32197}, {f: 2, c: 32200}, {f: 5, c: 32204},
- 32211, {f: 2, c: 32213}, {f: 3, c: 32218}, 32223, 32226, {f: 2, c: 32228},
- 32231, {f: 2, c: 32234}, {f: 2, c: 32237}, 32240, 32243, 32245,
- {f: 2, c: 32247}, 32250, {f: 12, c: 32252}, {f: 4, c: 32268},
- {f: 9, c: 32274}, 32284, {f: 3, c: 32288}, {f: 3, c: 32292},
- {f: 3, c: 32296}, 32300, {f: 2, c: 32303}, 32307, 32312, 32314, 32316,
- {f: 2, c: 32319}, {f: 3, c: 32322}, {f: 10, c: 32328}, 32339,
- {f: 4, c: 32342}, {f: 3, c: 32347}, {f: 3, c: 32351}, {f: 6, c: 32355},
- 32364, {f: 2, c: 32369}, {f: 5, c: 32372}, {f: 2, c: 32378},
- {f: 3, c: 32383}, {f: 5, c: 32387}, 32393, 32395, 32398, {f: 3, c: 32400},
- 32405, 32407, {f: 2, c: 32409}, {f: 2, c: 32413}, 32430, 32436,
- {f: 2, c: 32443}, 32470, 32484, 32492, 32505, 32522, 32528, 32542, 32567,
- 32569, {f: 7, c: 32571}, 32579, {f: 6, c: 32582}, 32589, 32591,
- {f: 2, c: 32594}, 32598, 32601, {f: 4, c: 32603}, 32608, {f: 5, c: 32611},
- {f: 3, c: 32619}, 32623, 32627, {f: 2, c: 32629}, 32632, {f: 4, c: 32634},
- {f: 2, c: 32639}, {f: 3, c: 32642}, 32647, 32649, 32651, 32653,
- {f: 5, c: 32655}, {f: 5, c: 32661}, {f: 2, c: 32667}, 32672,
- {f: 2, c: 32674}, 32678, 32680, {f: 5, c: 32682}, 32689, {f: 5, c: 32691},
- {f: 2, c: 32698}, 32702, 32704, {f: 3, c: 32706}, {f: 4, c: 32710}, 32715,
- 32717, {f: 3, c: 32719}, 32723, {f: 2, c: 32726}, {f: 6, c: 32729},
- {f: 3, c: 32738}, {f: 2, c: 32743}, {f: 4, c: 32746}, 32751, 32754,
- {f: 5, c: 32756}, 32762, {f: 3, c: 32765}, 32770, {f: 4, c: 32775},
- {f: 2, c: 32782}, 32785, 32787, {f: 2, c: 32794}, {f: 3, c: 32797}, 32801,
- {f: 2, c: 32803}, 32811, 32813, {f: 2, c: 32815}, 32818, 32820,
- {f: 2, c: 32825}, 32828, 32830, {f: 2, c: 32832}, {f: 2, c: 32836},
- {f: 3, c: 32839}, {f: 4, c: 32846}, 32851, 32853, 32855, 32857,
- {f: 3, c: 32859}, {f: 10, c: 32863}, {f: 4, c: 32875}, 32884, 32888,
- {f: 3, c: 32890}, {f: 2, c: 32897}, 32904, 32906, {f: 6, c: 32909},
- {f: 2, c: 32916}, 32919, 32921, 32926, 32931, {f: 3, c: 32934}, 32940,
- 32944, 32947, {f: 2, c: 32949}, {f: 2, c: 32952}, 32955, 32965,
- {f: 5, c: 32967}, {f: 7, c: 32975}, 32984, {f: 2, c: 32991},
- {f: 2, c: 32994}, 32998, 33006, 33013, 33015, 33017, 33019,
- {f: 4, c: 33022}, {f: 2, c: 33027}, {f: 2, c: 33031}, {f: 2, c: 33035},
- 33045, 33047, 33049, {f: 2, c: 33052}, {f: 13, c: 33055}, {f: 2, c: 33069},
- 33072, {f: 3, c: 33075}, 33079, {f: 4, c: 33082}, {f: 7, c: 33087}, 33095,
- 33097, 33101, 33103, 33106, {f: 2, c: 33111}, {f: 5, c: 33115},
- {f: 3, c: 33122}, 33128, 33130, 33132, 33135, {f: 2, c: 33138},
- {f: 3, c: 33141}, 33153, {f: 5, c: 33155}, 33161, {f: 4, c: 33163}, 33168,
- {f: 6, c: 33170}, 33177, {f: 2, c: 33182}, {f: 2, c: 33185},
- {f: 2, c: 33188}, 33191, {f: 8, c: 33195}, {f: 6, c: 33204}, 33212,
- {f: 2, c: 33220}, {f: 2, c: 33223}, 33227, 33230, {f: 8, c: 33232}, 33241,
- {f: 4, c: 33243}, {f: 2, c: 33249}, {f: 3, c: 33252}, 33257, 33259,
- {f: 5, c: 33262}, {f: 5, c: 33269}, 33277, 33279, 33283, 33291,
- {f: 2, c: 33294}, 33297, 33299, {f: 6, c: 33301}, 33309, 33312,
- {f: 4, c: 33316}, 33321, 33326, 33330, 33338, {f: 2, c: 33340},
- {f: 5, c: 33343}, {f: 2, c: 33349}, 33352, 33354, {f: 3, c: 33356},
- {f: 8, c: 33360}, {f: 4, c: 33371}, {f: 4, c: 33376}, 33381, 33383,
- {f: 2, c: 33385}, {f: 2, c: 33388}, {f: 2, c: 33397}, [12171, 33400],
- {f: 2, c: 33403}, {f: 2, c: 33408}, 33411, {f: 3, c: 33413}, 33417, 33420,
- 33424, {f: 4, c: 33427}, {f: 2, c: 33434}, 33438, 33440, {f: 2, c: 33442},
- 33447, 33458, {f: 2, c: 33461}, 33466, 33468, {f: 2, c: 33471},
- {f: 2, c: 33474}, {f: 2, c: 33477}, 33481, 33488, 33494, {f: 2, c: 33497},
- 33501, 33506, {f: 3, c: 33512}, {f: 3, c: 33516}, 33520, {f: 2, c: 33522},
- {f: 2, c: 33525}, 33528, 33530, {f: 5, c: 33532}, {f: 2, c: 33546}, 33549,
- 33552, {f: 2, c: 33554}, 33558, {f: 2, c: 33560}, {f: 10, c: 33565},
- {f: 2, c: 33577}, 33582, 33584, 33586, 33591, 33595, {f: 3, c: 33597},
- {f: 2, c: 33601}, {f: 2, c: 33604}, 33608, {f: 5, c: 33610}, 33619,
- {f: 5, c: 33621}, 33629, 33634, {f: 7, c: 33648}, {f: 2, c: 33657},
- {f: 7, c: 33662}, {f: 2, c: 33671}, {f: 3, c: 33675}, {f: 3, c: 33679},
- {f: 2, c: 33684}, 33687, {f: 2, c: 33689}, 33693, 33695, 33697,
- {f: 4, c: 33699}, {f: 4, c: 33708}, 33717, 33723, {f: 2, c: 33726},
- {f: 3, c: 33730}, 33734, {f: 2, c: 33736}, 33739, {f: 2, c: 33741},
- {f: 4, c: 33744}, 33749, 33751, {f: 3, c: 33753}, 33758, {f: 3, c: 33762},
- {f: 3, c: 33766}, {f: 4, c: 33771}, {f: 5, c: 33779}, {f: 3, c: 33786},
- {f: 3, c: 33790}, 33794, 33797, {f: 2, c: 33800}, 33808, {f: 6, c: 33810},
- {f: 3, c: 33817}, {f: 6, c: 33822}, {f: 3, c: 33833}, {f: 4, c: 33837},
- {f: 3, c: 33842}, {f: 2, c: 33846}, {f: 3, c: 33849}, {f: 8, c: 33854},
- {f: 2, c: 33863}, {f: 7, c: 33866}, {f: 4, c: 33875}, 33880,
- {f: 4, c: 33885}, 33890, 33893, {f: 2, c: 33895}, 33898, 33902, 33904,
- 33906, 33908, 33913, {f: 7, c: 33915}, {f: 4, c: 33923}, 33930, 33933,
- {f: 4, c: 33935}, {f: 2, c: 33941}, 33944, {f: 2, c: 33946},
- {f: 4, c: 33949}, {f: 13, c: 33954}, {f: 2, c: 33968}, 33971,
- {f: 3, c: 33973}, 33979, 33982, {f: 2, c: 33986}, {f: 4, c: 33989}, 33996,
- {f: 2, c: 33998}, 34002, {f: 2, c: 34004}, {f: 6, c: 34007}, 34014,
- {f: 2, c: 34017}, 34020, {f: 5, c: 34023}, 34029, {f: 11, c: 34033}, 34046,
- {f: 12, c: 34048}, {f: 4, c: 34061}, 34066, {f: 2, c: 34069},
- {f: 2, c: 34072}, {f: 3, c: 34075}, 34080, 34082, {f: 2, c: 34084},
- {f: 4, c: 34087}, {f: 9, c: 34094}, {f: 3, c: 34110}, 34114,
- {f: 2, c: 34116}, 34119, {f: 3, c: 34123}, {f: 3, c: 34127}, 34132, 34135,
- {f: 4, c: 34138}, {f: 3, c: 34143}, 34147, {f: 3, c: 34149},
- {f: 2, c: 34155}, {f: 4, c: 34158}, 34163, {f: 2, c: 34165}, 34168,
- {f: 2, c: 34172}, {f: 5, c: 34175}, 34182, 34185, 34187, {f: 2, c: 34189},
- 34192, {f: 2, c: 34194}, {f: 6, c: 34197}, {f: 2, c: 34205},
- {f: 4, c: 34208}, 34213, 34215, {f: 3, c: 34219}, {f: 6, c: 34225}, 34232,
- {f: 6, c: 34235}, {f: 7, c: 34242}, {f: 3, c: 34250}, {f: 2, c: 34257},
- 34260, {f: 6, c: 34262}, {f: 6, c: 34270}, {f: 3, c: 34278},
- {f: 9, c: 34283}, 34293, {f: 2, c: 34295}, {f: 3, c: 34300},
- {f: 4, c: 34304}, {f: 3, c: 34312}, {f: 5, c: 34316}, {f: 4, c: 34322},
- {f: 3, c: 34327}, {f: 3, c: 34331}, {f: 3, c: 34335}, {f: 4, c: 34339},
- 34344, {f: 3, c: 34346}, {f: 10, c: 34350}, 34361, 34363, {f: 2, c: 34365},
- {f: 13, c: 34368}, {f: 2, c: 34386}, {f: 4, c: 34390}, 34395, 34397,
- {f: 2, c: 34400}, {f: 4, c: 34403}, {f: 3, c: 34408}, 34413,
- {f: 2, c: 34415}, {f: 7, c: 34418}, {f: 7, c: 34435}, {f: 5, c: 34446},
- 34452, {f: 6, c: 34454}, {f: 5, c: 34462}, {f: 2, c: 34469}, 34475,
- {f: 2, c: 34477}, {f: 2, c: 34482}, {f: 3, c: 34487}, {f: 5, c: 34491},
- {f: 3, c: 34497}, 34501, 34504, {f: 2, c: 34508}, {f: 2, c: 34514},
- {f: 3, c: 34517}, 34522, {f: 2, c: 34524}, {f: 4, c: 34528},
- {f: 4, c: 34533}, {f: 3, c: 34538}, 34543, {f: 3, c: 34549},
- {f: 3, c: 34555}, 34559, 34561, {f: 2, c: 34564}, {f: 2, c: 34571},
- {f: 4, c: 34574}, 34580, 34582, 34585, 34587, 34589, {f: 2, c: 34591},
- 34596, {f: 3, c: 34598}, {f: 4, c: 34602}, {f: 2, c: 34607},
- {f: 2, c: 34610}, {f: 2, c: 34613}, {f: 3, c: 34616}, {f: 2, c: 34620},
- {f: 7, c: 34624}, {f: 2, c: 34634}, 34637, {f: 4, c: 34639}, 34644, 34646,
- 34648, {f: 6, c: 34650}, {f: 2, c: 34657}, {f: 7, c: 34663}, 34671,
- {f: 3, c: 34673}, 34677, 34679, {f: 2, c: 34681}, {f: 3, c: 34687},
- {f: 2, c: 34694}, {f: 2, c: 34697}, 34700, {f: 5, c: 34702},
- {f: 3, c: 34708}, {f: 6, c: 34712}, {f: 2, c: 34720}, {f: 5, c: 34723},
- {f: 2, c: 34729}, 34734, {f: 3, c: 34736}, 34740, {f: 4, c: 34742}, 34748,
- {f: 2, c: 34750}, {f: 3, c: 34753}, 34757, 34759, 34761, {f: 2, c: 34764},
- {f: 2, c: 34767}, {f: 7, c: 34772}, {f: 4, c: 34780}, {f: 2, c: 34785},
- 34788, {f: 4, c: 34790}, 34795, 34797, {f: 2, c: 34800}, {f: 3, c: 34803},
- {f: 2, c: 34807}, 34810, {f: 2, c: 34812}, {f: 4, c: 34815}, 34820,
- {f: 3, c: 34823}, {f: 5, c: 34827}, 34834, 34836, {f: 4, c: 34839},
- {f: 3, c: 34844}, 34848, {f: 13, c: 34852}, {f: 3, c: 34867},
- {f: 2, c: 34871}, 34874, {f: 3, c: 34877}, {f: 3, c: 34881},
- {f: 3, c: 34887}, 34891, {f: 5, c: 34894}, {f: 2, c: 34901}, 34904, 34906,
- 34908, {f: 3, c: 34910}, {f: 2, c: 34918}, 34922, 34925, 34927, 34929,
- {f: 4, c: 34931}, 34936, {f: 3, c: 34938}, 34944, 34947, {f: 2, c: 34950},
- {f: 2, c: 34953}, 34956, {f: 4, c: 34958}, {f: 3, c: 34963},
- {f: 5, c: 34967}, {f: 5, c: 34973}, 34979, {f: 6, c: 34981}, 34988,
- {f: 3, c: 34990}, {f: 5, c: 34994}, {f: 4, c: 35000}, {f: 4, c: 35005},
- {f: 2, c: 35011}, {f: 2, c: 35015}, {f: 3, c: 35019}, {f: 2, c: 35024},
- 35027, {f: 2, c: 35030}, {f: 2, c: 35034}, 35038, {f: 2, c: 35040},
- {f: 2, c: 35046}, {f: 7, c: 35049}, 35058, {f: 3, c: 35061},
- {f: 2, c: 35066}, {f: 3, c: 35071}, {f: 4, c: 35075}, {f: 2, c: 35080},
- {f: 5, c: 35083}, 35089, {f: 5, c: 35092}, {f: 5, c: 35100},
- {f: 3, c: 35106}, {f: 4, c: 35110}, {f: 4, c: 35116}, 35121, 35125, 35127,
- {f: 2, c: 35129}, {f: 5, c: 35132}, {f: 2, c: 35138}, {f: 2, c: 35141},
- {f: 14, c: 35144}, {f: 6, c: 35159}, {f: 3, c: 35169}, 35173,
- {f: 3, c: 35175}, 35179, {f: 2, c: 35181}, {f: 2, c: 35184},
- {f: 8, c: 35187}, {f: 2, c: 35196}, [12177, 35198], 35200, 35202,
- {f: 2, c: 35204}, {f: 4, c: 35207}, {f: 3, c: 35212}, {f: 3, c: 35216},
- {f: 2, c: 35220}, 35223, {f: 8, c: 35225}, {f: 4, c: 35234},
- {f: 3, c: 35239}, 35243, {f: 2, c: 35245}, {f: 2, c: 35248},
- {f: 4, c: 35251}, {f: 2, c: 35256}, {f: 2, c: 35259}, 35262, 35267, 35277,
- {f: 3, c: 35283}, {f: 3, c: 35287}, 35291, 35293, {f: 4, c: 35295}, 35300,
- {f: 4, c: 35303}, {f: 3, c: 35308}, {f: 3, c: 35312}, 35317, 35319,
- {f: 7, c: 35321}, {f: 3, c: 35332}, 35337, 35339, 35341, 35343,
- {f: 2, c: 35345}, 35348, 35351, {f: 2, c: 35353}, 35356, 35358,
- {f: 3, c: 35360}, 35364, {f: 4, c: 35366}, {f: 2, c: 35371},
- {f: 3, c: 35374}, {f: 2, c: 35378}, 35381, {f: 3, c: 35383},
- {f: 3, c: 35387}, {f: 2, c: 35391}, {f: 4, c: 35394}, 35399,
- {f: 5, c: 35401}, 35407, 35409, 35411, {f: 2, c: 35414}, {f: 2, c: 35417},
- {f: 2, c: 35420}, {f: 2, c: 35423}, {f: 2, c: 35428}, {f: 2, c: 35431},
- 35434, 35439, 35444, {f: 3, c: 35446}, {f: 2, c: 35450}, {f: 2, c: 35453},
- {f: 4, c: 35456}, 35464, {f: 2, c: 35467}, {f: 3, c: 35470}, 35476,
- {f: 2, c: 35478}, 35481, {f: 3, c: 35483}, 35487, 35490, 35495,
- {f: 3, c: 35497}, {f: 3, c: 35501}, 35505, {f: 3, c: 35507},
- {f: 2, c: 35511}, {f: 2, c: 35514}, {f: 2, c: 35517}, {f: 2, c: 35520},
- 35523, {f: 2, c: 35525}, 35528, 35530, 35532, 35534, 35536,
- {f: 3, c: 35539}, {f: 3, c: 35544}, 35549, {f: 3, c: 35551}, 35555, 35557,
- {f: 3, c: 35560}, 35564, {f: 2, c: 35567}, 35570, {f: 2, c: 35572}, 35577,
- 35579, 35581, 35583, 35587, 35590, {f: 2, c: 35592}, {f: 3, c: 35595},
- 35599, {f: 3, c: 35601}, 35605, 35608, 35612, {f: 3, c: 35614},
- {f: 4, c: 35618}, 35623, {f: 2, c: 35625}, {f: 5, c: 35630},
- {f: 5, c: 35636}, {f: 4, c: 35642}, {f: 10, c: 35647}, {f: 4, c: 35658},
- {f: 6, c: 35664}, 35671, 35675, {f: 9, c: 35677}, {f: 4, c: 35687},
- {f: 2, c: 35693}, {f: 3, c: 35697}, {f: 2, c: 35701}, {f: 5, c: 35704},
- {f: 2, c: 35710}, {f: 9, c: 35713}, {f: 3, c: 35723}, {f: 3, c: 35727},
- 35732, {f: 5, c: 35735}, 35741, 35743, 35756, 35761, 35771, 35783, 35792,
- 35818, 35849, 35870, {f: 9, c: 35896}, {f: 4, c: 35906}, {f: 2, c: 35914},
- {f: 3, c: 35917}, {f: 4, c: 35921}, {f: 4, c: 35926}, {f: 6, c: 35931},
- {f: 7, c: 35939}, {f: 7, c: 35948}, {f: 4, c: 35956}, {f: 7, c: 35963},
- {f: 2, c: 35971}, {f: 3, c: 35974}, 35979, {f: 7, c: 35981},
- {f: 3, c: 35989}, {f: 4, c: 35993}, 35999, {f: 4, c: 36003},
- {f: 2, c: 36013}, 36017, 36021, 36025, 36030, 36038, 36041,
- {f: 6, c: 36043}, 36052, {f: 4, c: 36054}, 36059, 36061, 36063, 36069,
- {f: 2, c: 36072}, {f: 6, c: 36078}, {f: 5, c: 36085}, {f: 5, c: 36095},
- {f: 2, c: 36102}, 36105, 36108, 36110, {f: 5, c: 36113}, {f: 4, c: 36119},
- 36128, {f: 2, c: 36177}, 36183, 36191, 36197, {f: 3, c: 36200}, 36204,
- {f: 2, c: 36206}, {f: 2, c: 36209}, {f: 9, c: 36216}, {f: 2, c: 36226},
- {f: 4, c: 36230}, {f: 5, c: 36236}, {f: 2, c: 36242}, {f: 3, c: 36246},
- {f: 5, c: 36250}, {f: 3, c: 36256}, {f: 4, c: 36260}, {f: 8, c: 36265},
- {f: 2, c: 36278}, 36281, 36283, 36285, {f: 3, c: 36288}, 36293,
- {f: 4, c: 36295}, 36301, 36304, {f: 4, c: 36306}, {f: 2, c: 36312}, 36316,
- {f: 3, c: 36320}, {f: 3, c: 36325}, 36329, {f: 2, c: 36333},
- {f: 3, c: 36336}, 36340, 36342, 36348, {f: 7, c: 36350}, {f: 3, c: 36358},
- 36363, {f: 2, c: 36365}, {f: 3, c: 36369}, {f: 8, c: 36373},
- {f: 2, c: 36384}, {f: 5, c: 36388}, 36395, 36397, 36400, {f: 2, c: 36402},
- {f: 3, c: 36406}, {f: 2, c: 36411}, {f: 2, c: 36414}, 36419,
- {f: 2, c: 36421}, {f: 4, c: 36429}, {f: 2, c: 36435}, {f: 3, c: 36438},
- {f: 9, c: 36442}, {f: 2, c: 36452}, {f: 2, c: 36455}, {f: 2, c: 36458},
- 36462, 36465, 36467, 36469, {f: 3, c: 36471}, 36475, {f: 2, c: 36477},
- 36480, {f: 3, c: 36482}, 36486, 36488, 36492, 36494, {f: 5, c: 36501},
- 36507, 36509, {f: 2, c: 36511}, {f: 3, c: 36514}, {f: 3, c: 36519},
- {f: 2, c: 36525}, {f: 2, c: 36528}, {f: 7, c: 36531}, {f: 5, c: 36539},
- {f: 9, c: 36545}, {f: 3, c: 36559}, 36563, {f: 6, c: 36565},
- {f: 3, c: 36572}, {f: 4, c: 36576}, {f: 6, c: 36581}, {f: 6, c: 36588},
- {f: 5, c: 36595}, 36605, {f: 4, c: 36607}, 36612, 36614, 36616,
- {f: 7, c: 36619}, 36627, {f: 5, c: 36630}, {f: 5, c: 36640},
- {f: 2, c: 36647}, {f: 4, c: 36651}, {f: 3, c: 36656}, {f: 4, c: 36660},
- {f: 2, c: 36665}, {f: 2, c: 36668}, {f: 2, c: 36672}, 36675,
- {f: 2, c: 36679}, {f: 3, c: 36682}, {f: 5, c: 36687}, {f: 10, c: 36693},
- 36704, 36707, 36709, 36714, 36736, 36748, 36754, 36765, {f: 3, c: 36768},
- {f: 2, c: 36772}, 36775, 36778, 36780, {f: 2, c: 36787}, [12193, 36789],
- {f: 2, c: 36791}, {f: 3, c: 36794}, {f: 2, c: 36799}, 36803, 36806,
- {f: 5, c: 36809}, 36815, 36818, {f: 2, c: 36822}, 36826, {f: 2, c: 36832},
- 36835, 36839, 36844, 36847, {f: 2, c: 36849}, {f: 2, c: 36853},
- {f: 3, c: 36858}, {f: 2, c: 36862}, {f: 2, c: 36871}, 36876, 36878, 36883,
- 36888, 36892, {f: 2, c: 36900}, {f: 6, c: 36903}, {f: 2, c: 36912},
- {f: 2, c: 36915}, 36919, {f: 2, c: 36921}, 36925, {f: 2, c: 36927}, 36931,
- {f: 2, c: 36933}, {f: 3, c: 36936}, 36940, 36950, {f: 2, c: 36953}, 36957,
- 36959, 36961, 36964, {f: 2, c: 36966}, {f: 3, c: 36970}, {f: 3, c: 36975},
- 36979, 36982, 36985, 36987, 36990, {f: 2, c: 36997}, 37001,
- {f: 3, c: 37004}, 37010, 37012, 37014, 37016, 37018, 37020,
- {f: 3, c: 37022}, {f: 2, c: 37028}, {f: 3, c: 37031}, 37035, 37037, 37042,
- 37047, {f: 2, c: 37052}, {f: 2, c: 37055}, {f: 2, c: 37058}, 37062,
- {f: 2, c: 37064}, {f: 3, c: 37067}, 37074, {f: 3, c: 37076},
- {f: 3, c: 37080}, 37086, 37088, {f: 3, c: 37091}, {f: 2, c: 37097}, 37100,
- 37102, {f: 4, c: 37104}, {f: 2, c: 37110}, {f: 4, c: 37113},
- {f: 3, c: 37119}, 37123, 37125, {f: 2, c: 37127}, {f: 8, c: 37130}, 37139,
- 37141, {f: 2, c: 37143}, {f: 4, c: 37146}, {f: 3, c: 37151},
- {f: 3, c: 37156}, {f: 5, c: 37160}, 37166, 37171, 37173, {f: 2, c: 37175},
- {f: 8, c: 37179}, {f: 2, c: 37188}, 37191, 37201, {f: 4, c: 37203},
- {f: 2, c: 37208}, {f: 2, c: 37211}, {f: 2, c: 37215}, {f: 3, c: 37222},
- 37227, 37229, 37235, {f: 3, c: 37242}, {f: 5, c: 37248}, 37254, 37256,
- 37258, {f: 2, c: 37262}, {f: 3, c: 37267}, {f: 3, c: 37271},
- {f: 5, c: 37277}, {f: 6, c: 37284}, {f: 4, c: 37296}, {f: 4, c: 37302},
- {f: 5, c: 37307}, 37314, 37316, [12196, 37318], 37320, 37328, 37334,
- {f: 2, c: 37338}, {f: 5, c: 37342}, {f: 2, c: 37349}, 37352,
- {f: 11, c: 37354}, 37366, 37368, {f: 5, c: 37371}, {f: 2, c: 37378},
- {f: 3, c: 37381}, {f: 3, c: 37386}, 37391, {f: 2, c: 37394},
- {f: 8, c: 37398}, {f: 4, c: 37407}, 37412, {f: 6, c: 37416}, 37423,
- {f: 2, c: 37425}, {f: 2, c: 37429}, {f: 2, c: 37435}, {f: 4, c: 37441},
- {f: 2, c: 37446}, {f: 3, c: 37450}, {f: 3, c: 37454}, {f: 3, c: 37458},
- 37462, {f: 2, c: 37464}, {f: 2, c: 37468}, {f: 3, c: 37471},
- {f: 3, c: 37475}, {f: 5, c: 37479}, {f: 6, c: 37486}, {f: 3, c: 37493},
- 37497, {f: 3, c: 37500}, {f: 2, c: 37505}, 37508, {f: 8, c: 37510},
- {f: 2, c: 37519}, 37522, {f: 2, c: 37524}, 37527, 37529, 37531,
- {f: 3, c: 37533}, {f: 2, c: 37537}, 37540, 37543, 37549, {f: 2, c: 37551},
- {f: 5, c: 37554}, 37560, 37562, {f: 4, c: 37565}, 37570, 37572, 37574,
- {f: 3, c: 37577}, {f: 2, c: 37581}, {f: 2, c: 37584}, {f: 10, c: 37587},
- 37598, {f: 3, c: 37600}, 37607, 37609, {f: 2, c: 37611}, {f: 4, c: 37618},
- 37623, {f: 3, c: 37625}, {f: 4, c: 37629}, {f: 4, c: 37634},
- {f: 7, c: 37641}, 37649, {f: 2, c: 37651}, {f: 2, c: 37654},
- {f: 3, c: 37660}, 37665, {f: 3, c: 37667}, 37671, {f: 2, c: 37673},
- {f: 2, c: 37676}, {f: 2, c: 37680}, {f: 2, c: 37684}, 37687,
- {f: 5, c: 37689}, 37695, 37698, {f: 2, c: 37700}, {f: 3, c: 37704}, 37708,
- {f: 6, c: 37710}, {f: 3, c: 37717}, {f: 2, c: 37721}, {f: 8, c: 37724},
- {f: 3, c: 37734}, 37739, {f: 3, c: 37741}, {f: 4, c: 37745},
- {f: 3, c: 37751}, {f: 3, c: 37755}, {f: 3, c: 37759}, 37763,
- {f: 2, c: 37765}, {f: 2, c: 37768}, {f: 4, c: 37771}, {f: 6, c: 37776},
- 37783, {f: 9, c: 37785}, {f: 2, c: 37796}, 37800, 37803, 37805, 37807,
- {f: 2, c: 37809}, 37812, {f: 2, c: 37814}, {f: 6, c: 37817},
- {f: 3, c: 37824}, {f: 3, c: 37828}, 37833, 37835, {f: 3, c: 37838},
- {f: 4, c: 37842}, {f: 3, c: 37849}, 37856, 37859, {f: 3, c: 37861},
- {f: 12, c: 37865}, 37878, 37880, {f: 9, c: 37882}, {f: 7, c: 37892},
- {f: 4, c: 37900}, 37905, {f: 3, c: 37909}, {f: 3, c: 37914},
- {f: 2, c: 37918}, {f: 5, c: 37921}, {f: 5, c: 37929}, {f: 3, c: 37935},
- 37940, {f: 2, c: 37942}, 37945, {f: 3, c: 37947}, {f: 4, c: 37952},
- {f: 5, c: 37957}, 37963, {f: 5, c: 37965}, 37971, {f: 11, c: 37973},
- {f: 2, c: 37985}, 37988, {f: 5, c: 37990}, 37996, {f: 2, c: 37998}, 38001,
- {f: 4, c: 38003}, 38008, {f: 2, c: 38010}, {f: 5, c: 38016}, 38033, 38038,
- 38040, 38087, 38095, {f: 2, c: 38099}, 38106, 38118, 38139, 38172, 38176,
- 38183, 38195, 38205, 38211, 38216, 38219, 38229, 38234, 38240, 38254,
- {f: 2, c: 38260}, {f: 7, c: 38264}, 38273, {f: 2, c: 38276},
- {f: 2, c: 38279}, 38282, 38285, 38288, 38290, {f: 3, c: 38293},
- {f: 8, c: 38297}, 38306, {f: 2, c: 38310}, 38314, {f: 4, c: 38318},
- {f: 3, c: 38323}, {f: 2, c: 38327}, 38330, {f: 3, c: 38336},
- {f: 2, c: 38340}, 38343, 38345, {f: 3, c: 38349}, {f: 3, c: 38353},
- {f: 5, c: 38359}, 38365, {f: 2, c: 38367}, {f: 2, c: 38371},
- {f: 2, c: 38374}, 38380, 38399, 38407, 38419, 38424, 38427, 38430, 38432,
- {f: 7, c: 38435}, {f: 3, c: 38443}, {f: 2, c: 38447}, {f: 4, c: 38455},
- 38462, 38465, 38467, 38474, {f: 2, c: 38478}, {f: 3, c: 38481},
- {f: 2, c: 38486}, {f: 2, c: 38489}, 38492, 38494, 38496, {f: 2, c: 38501},
- 38507, {f: 3, c: 38509}, 38513, {f: 4, c: 38521}, {f: 7, c: 38526}, 38535,
- 38537, 38540, {f: 3, c: 38545}, 38550, 38554, {f: 10, c: 38557}, 38569,
- {f: 5, c: 38571}, 38578, 38581, 38583, 38586, 38591, {f: 2, c: 38594},
- 38600, {f: 2, c: 38602}, {f: 2, c: 38608}, {f: 2, c: 38611},
- {f: 2, c: 38615}, 38618, {f: 3, c: 38621}, 38625, {f: 4, c: 38628},
- {f: 4, c: 38635}, {f: 2, c: 38640}, {f: 2, c: 38644}, 38648, 38650,
- {f: 2, c: 38652}, 38655, {f: 2, c: 38658}, 38661, {f: 3, c: 38666},
- {f: 3, c: 38672}, {f: 2, c: 38676}, {f: 5, c: 38679}, 38685,
- {f: 8, c: 38687}, {f: 2, c: 38696}, {f: 2, c: 38699}, {f: 2, c: 38702},
- 38705, {f: 5, c: 38707}, {f: 3, c: 38714}, {f: 3, c: 38719}, 38723,
- {f: 3, c: 38725}, {f: 8, c: 38729}, [12205, 38737], {f: 2, c: 38740},
- {f: 2, c: 38743}, {f: 2, c: 38748}, 38751, {f: 2, c: 38755},
- {f: 2, c: 38758}, {f: 9, c: 38762}, 38773, {f: 5, c: 38775},
- {f: 8, c: 38781}, {f: 5, c: 38790}, 38796, 38798, 38800, 38803,
- {f: 3, c: 38805}, {f: 7, c: 38809}, {f: 2, c: 38817}, {f: 2, c: 38820},
- {f: 4, c: 38823}, 38828, 38830, {f: 2, c: 38832}, 38835, {f: 8, c: 38837},
- {f: 5, c: 38846}, {f: 2, c: 38852}, {f: 2, c: 38855}, 38858,
- {f: 6, c: 38861}, {f: 5, c: 38868}, {f: 2, c: 38874}, 38877,
- {f: 7, c: 38879}, 38888, {f: 5, c: 38894}, 38900, {f: 8, c: 38903}, 38912,
- 38916, 38921, 38923, 38925, {f: 3, c: 38932}, {f: 3, c: 38937},
- {f: 4, c: 38941}, {f: 2, c: 38946}, 38949, {f: 6, c: 38951},
- {f: 2, c: 38958}, {f: 6, c: 38961}, {f: 2, c: 38969}, 38972,
- {f: 8, c: 38974}, {f: 5, c: 38983}, {f: 4, c: 38991}, {f: 3, c: 38997},
- 39002, {f: 2, c: 39004}, {f: 3, c: 39007}, {f: 2, c: 39011}, 39014,
- {f: 3, c: 39016}, {f: 2, c: 39021}, 39026, 39051, 39054, 39058, 39061,
- 39065, 39075, {f: 5, c: 39081}, 39088, 39090, {f: 2, c: 39092},
- {f: 5, c: 39095}, {f: 7, c: 39101}, 39109, 39111, {f: 5, c: 39113},
- {f: 2, c: 39119}, 39124, {f: 2, c: 39126}, {f: 2, c: 39132}, 39137,
- {f: 4, c: 39139}, 39148, 39150, {f: 2, c: 39152}, 39155, {f: 7, c: 39157},
- {f: 4, c: 39167}, 39172, {f: 3, c: 39174}, 39179, {f: 2, c: 39182},
- {f: 4, c: 39188}, {f: 2, c: 39193}, {f: 2, c: 39196}, {f: 2, c: 39199},
- {f: 6, c: 39202}, {f: 5, c: 39209}, {f: 4, c: 39215}, {f: 3, c: 39220},
- {f: 4, c: 39224}, 39229, {f: 3, c: 39232}, 39236, {f: 2, c: 39238},
- {f: 4, c: 39245}, 39251, 39254, {f: 4, c: 39256}, 39261, {f: 3, c: 39263},
- 39268, 39270, 39283, {f: 2, c: 39288}, 39291, 39294, {f: 2, c: 39298},
- 39305, 39308, 39310, {f: 11, c: 39322}, {f: 2, c: 39334}, {f: 3, c: 39337},
- {f: 2, c: 39343}, 39346, {f: 12, c: 39349}, {f: 14, c: 39362}, 39379,
- {f: 2, c: 39382}, 39386, 39388, 39390, 39392, {f: 10, c: 39395},
- {f: 3, c: 39406}, {f: 13, c: 39410}, 39424, {f: 3, c: 39426},
- {f: 7, c: 39430}, {f: 6, c: 39440}, {f: 2, c: 39447}, {f: 17, c: 39450},
- 39468, 39471, {f: 5, c: 39473}, {f: 5, c: 39481}, 39487, {f: 4, c: 39494},
- {f: 2, c: 39499}, 39502, {f: 5, c: 39504}, 39510, {f: 2, c: 39512},
- {f: 3, c: 39516}, {f: 2, c: 39520}, 39523, {f: 4, c: 39526}, 39531, 39538,
- 39555, 39561, {f: 2, c: 39565}, {f: 2, c: 39572}, 39577, 39590,
- {f: 6, c: 39593}, {f: 4, c: 39602}, 39609, 39611, {f: 3, c: 39613},
- {f: 2, c: 39619}, {f: 5, c: 39622}, {f: 2, c: 39629}, 39632, 39639,
- {f: 6, c: 39641}, 39648, {f: 4, c: 39650}, {f: 4, c: 39655}, 39660,
- {f: 9, c: 39664}, 39674, {f: 7, c: 39676}, {f: 2, c: 39684}, 39687,
- {f: 4, c: 39689}, 39694, {f: 3, c: 39696}, {f: 6, c: 39700},
- {f: 4, c: 39707}, {f: 2, c: 39712}, 39716, 39718, 39720, {f: 4, c: 39722},
- 39728, {f: 8, c: 39731}, {f: 4, c: 39741}, 39750, {f: 3, c: 39754}, 39760,
- {f: 2, c: 39762}, {f: 3, c: 39765}, 39769, {f: 20, c: 39771},
- {f: 4, c: 39792}, {f: 2, c: 39797}, {f: 9, c: 39800}, 39810,
- {f: 10, c: 39812}, 39823, {f: 7, c: 39827}, {f: 2, c: 39835},
- {f: 11, c: 39839}, 39852, {f: 17, c: 39855}, {f: 5, c: 39874}, 39880,
- {f: 9, c: 39883}, 39893, {f: 4, c: 39895}, 39900, {f: 3, c: 39902}, 39907,
- {f: 2, c: 39909}, 39913, {f: 4, c: 39916}, {f: 3, c: 39921},
- {f: 8, c: 39925}, 39934, {f: 8, c: 39936}, {f: 3, c: 39946},
- {f: 2, c: 39950}, 39953, {f: 12, c: 39956}, {f: 2, c: 39969}, 39972,
- {f: 2, c: 39974}, {f: 3, c: 39978}, {f: 3, c: 39982}, 39988, 39990, 39992,
- 39994, {f: 2, c: 39996}, {f: 6, c: 39999}, {f: 2, c: 40006},
- {f: 8, c: 40010}, 40019, 40021, {f: 4, c: 40025}, 40030, {f: 7, c: 40032},
- {f: 5, c: 40040}, {f: 10, c: 40046}, 40057, 40059, {f: 2, c: 40061}, 40064,
- {f: 2, c: 40067}, {f: 2, c: 40073}, 40076, 40079, 40083, {f: 4, c: 40086},
- 40093, 40106, 40108, 40111, 40121, {f: 5, c: 40126}, {f: 2, c: 40136},
- {f: 2, c: 40145}, {f: 2, c: 40154}, {f: 2, c: 40160}, {f: 2, c: 40163},
- {f: 3, c: 40166}, {f: 2, c: 40170}, {f: 6, c: 40173}, 40181,
- {f: 15, c: 40183}, 40200, {f: 11, c: 40202}, {f: 5, c: 40214}, 40220,
- 40222, {f: 3, c: 40224}, {f: 2, c: 40228}, 40231, {f: 6, c: 40233},
- {f: 10, c: 40241}, {f: 3, c: 40252}, {f: 2, c: 40256}, {f: 14, c: 40259},
- {f: 8, c: 40276}, {f: 2, c: 40286}, {f: 8, c: 40290}, 40299,
- {f: 2, c: 40301}, {f: 2, c: 40304}, {f: 20, c: 40307}, 40328,
- {f: 9, c: 40330}, {f: 4, c: 40340}, 40345, {f: 10, c: 40347},
- {f: 3, c: 40358}, {f: 5, c: 40362}, {f: 4, c: 40368}, {f: 6, c: 40373},
- {f: 3, c: 40381}, 40385, 40387, {f: 14, c: 40389}, {f: 3, c: 40404}, 40408,
- {f: 10, c: 40411}, {f: 8, c: 40423}, {f: 2, c: 40432}, {f: 4, c: 40436},
- {f: 17, c: 40443}, {f: 8, c: 40461}, {f: 4, c: 40470}, 40476, 40484, 40487,
- 40494, 40496, 40500, {f: 2, c: 40507}, 40512, 40525, 40528,
- {f: 3, c: 40530}, 40534, 40537, 40541, {f: 4, c: 40543}, 40549,
- {f: 2, c: 40558}, 40562, 40564, {f: 3, c: 40566}, 40571, {f: 2, c: 40576},
- {f: 4, c: 40579}, {f: 2, c: 40585}, {f: 6, c: 40588}, {f: 3, c: 40596},
- {f: 5, c: 40600}, 40606, {f: 5, c: 40608}, {f: 2, c: 40615},
- {f: 5, c: 40618}, {f: 4, c: 40624}, {f: 2, c: 40630}, {f: 2, c: 40633},
- 40636, {f: 4, c: 40639}, [12232, 40643], {f: 4, c: 40645},
- {f: 2, c: 40650}, 40656, {f: 2, c: 40658}, {f: 3, c: 40661},
- {f: 2, c: 40665}, 40673, {f: 2, c: 40675}, 40678, {f: 4, c: 40683},
- {f: 2, c: 40688}, 40691, {f: 2, c: 40693}, 40696, 40698, {f: 9, c: 40704},
- 40714, 40716, 40719, {f: 2, c: 40721}, 40724, 40726, 40728,
- {f: 6, c: 40730}, 40737, {f: 9, c: 40739}, {f: 2, c: 40749},
- {f: 7, c: 40752}, 40760, 40762, 40764, {f: 5, c: 40767}, {f: 5, c: 40773},
- {f: 3, c: 40780}, 40787, {f: 4, c: 40789}, {f: 2, c: 40794},
- {f: 2, c: 40797}, 40802, {f: 2, c: 40804}, {f: 3, c: 40807}, 40811,
- {f: 5, c: 40813}, {f: 4, c: 40819}, {f: 7, c: 40824}, {f: 2, c: 40833},
- {f: 2, c: 40846}, {f: 3, c: 40849}, {f: 3, c: 40854}, {f: 2, c: 40861},
- {f: 5, c: 40865}, 63788, {f: 3, c: 64013}, 64017, {f: 2, c: 64019}, 64024,
- {f: 3, c: 64031}, {f: 2, c: 64035}, {f: 3, c: 64039}, 11905,
- [59414, 131207], [59415, 131209], [59416, 131276], 11908, 13427, 13383,
- 11912, 11915, 59422, 13726, 13850, 13838, 11916, 11927, 14702, 14616,
- 59430, 14799, 14815, 14963, 14800, {f: 2, c: 59435}, 15182, 15470, 15584,
- 11943, [59441, 136663], 59442, 11946, 16470, 16735, 11950, 17207, 11955,
- {f: 2, c: 11958}, [59451, 141711], 17329, 17324, 11963, 17373, 17622,
- 18017, 17996, [59459, 132361], 18211, 18217, 18300, 18317, 11978, 18759,
- 18810, 18813, {f: 2, c: 18818}, {f: 2, c: 18821}, 18847, 18843, 18871,
- 18870, [59476, 133533], [59477, 147966], 19619, {f: 3, c: 19615}, 19575,
- 19618, {f: 7, c: 19731}, 19886, 59492, {s: 226}, 8364, 165, 0, 0, 12351,
- {s: 17}, 12436, {s: 14}, 12535, 12537, 12536, 12538, 0, {f: 3, c: 12339},
- {f: 3, c: 12344}, {f: 3, c: 12586}, {f: 24, c: 12704}, 11904,
- {f: 2, c: 11906}, {f: 3, c: 11909}, {f: 2, c: 11913}, {f: 10, c: 11917},
- {f: 2, c: 11928}, {f: 12, c: 11931}, {f: 2, c: 11944}, {f: 3, c: 11947},
- {f: 4, c: 11951}, {f: 2, c: 11956}, {f: 3, c: 11960}, {f: 14, c: 11964},
- {f: 41, c: 11979}, {f: 71, c: 13312}, {f: 43, c: 13384},
- {f: 298, c: 13428}, {f: 111, c: 13727}, {f: 11, c: 13839},
- {f: 765, c: 13851}, {f: 85, c: 14617}, {f: 96, c: 14703},
- {f: 14, c: 14801}, {f: 147, c: 14816}, {f: 218, c: 14964},
- {f: 287, c: 15183}, {f: 113, c: 15471}, {f: 885, c: 15585},
- {f: 264, c: 16471}, {f: 471, c: 16736}, {f: 116, c: 17208},
- {f: 4, c: 17325}, {f: 43, c: 17330}, {f: 248, c: 17374},
- {f: 373, c: 17623}, {f: 20, c: 17997}, {f: 193, c: 18018},
- {f: 5, c: 18212}, {f: 82, c: 18218}, {f: 16, c: 18301}, {f: 441, c: 18318},
- {f: 50, c: 18760}, {f: 2, c: 18811}, {f: 4, c: 18814}, 18820,
- {f: 20, c: 18823}, {f: 3, c: 18844}, {f: 22, c: 18848}, {f: 703, c: 18872},
- {f: 39, c: 19576}, {f: 111, c: 19620}, {f: 148, c: 19738},
- {f: 7, c: 19887}]
-};
+var DEFAULT_ICON_SIZE = 22; // px
+var SUPPORTED_TYPES = ['Link', 'Text', 'Widget'];
+var Annotation = (function AnnotationClosure() {
+ // 12.5.5: Algorithm: Appearance streams
+ function getTransformMatrix(rect, bbox, matrix) {
+ var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
+ var minX = bounds[0];
+ var minY = bounds[1];
+ var maxX = bounds[2];
+ var maxY = bounds[3];
+
+ if (minX === maxX || minY === maxY) {
+ // From real-life file, bbox was [0, 0, 0, 0]. In this case,
+ // just apply the transform for rect
+ return [1, 0, 0, 1, rect[0], rect[1]];
+ }
+
+ var xRatio = (rect[2] - rect[0]) / (maxX - minX);
+ var yRatio = (rect[3] - rect[1]) / (maxY - minY);
+ return [
+ xRatio,
+ 0,
+ 0,
+ yRatio,
+ rect[0] - minX * xRatio,
+ rect[1] - minY * yRatio
+ ];
+ }
+
+ function getDefaultAppearance(dict) {
+ var appearanceState = dict.get('AP');
+ if (!isDict(appearanceState)) {
+ return;
+ }
+
+ var appearance;
+ var appearances = appearanceState.get('N');
+ if (isDict(appearances)) {
+ var as = dict.get('AS');
+ if (as && appearances.has(as.name)) {
+ appearance = appearances.get(as.name);
+ }
+ } else {
+ appearance = appearances;
+ }
+ return appearance;
+ }
+
+ function Annotation(params) {
+ var dict = params.dict;
+ var data = this.data = {};
+
+ data.subtype = dict.get('Subtype').name;
+ var rect = dict.get('Rect') || [0, 0, 0, 0];
+ data.rect = Util.normalizeRect(rect);
+ data.annotationFlags = dict.get('F');
+
+ var color = dict.get('C');
+ if (isArray(color) && color.length === 3) {
+ // TODO(mack): currently only supporting rgb; need support different
+ // colorspaces
+ data.color = color;
+ } else {
+ data.color = [0, 0, 0];
+ }
+
+ // Some types of annotations have border style dict which has more
+ // info than the border array
+ if (dict.has('BS')) {
+ var borderStyle = dict.get('BS');
+ data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
+ } else {
+ var borderArray = dict.get('Border') || [0, 0, 1];
+ data.borderWidth = borderArray[2] || 0;
+
+ // TODO: implement proper support for annotations with line dash patterns.
+ var dashArray = borderArray[3];
+ if (data.borderWidth > 0 && dashArray) {
+ if (!isArray(dashArray)) {
+ // Ignore the border if dashArray is not actually an array,
+ // this is consistent with the behaviour in Adobe Reader.
+ data.borderWidth = 0;
+ } else {
+ var dashArrayLength = dashArray.length;
+ if (dashArrayLength > 0) {
+ // According to the PDF specification: the elements in a dashArray
+ // shall be numbers that are nonnegative and not all equal to zero.
+ var isInvalid = false;
+ var numPositive = 0;
+ for (var i = 0; i < dashArrayLength; i++) {
+ var validNumber = (+dashArray[i] >= 0);
+ if (!validNumber) {
+ isInvalid = true;
+ break;
+ } else if (dashArray[i] > 0) {
+ numPositive++;
+ }
+ }
+ if (isInvalid || numPositive === 0) {
+ data.borderWidth = 0;
+ }
+ }
+ }
+ }
+ }
+
+ this.appearance = getDefaultAppearance(dict);
+ data.hasAppearance = !!this.appearance;
+ data.id = params.ref.num;
+ }
+
+ Annotation.prototype = {
+
+ getData: function Annotation_getData() {
+ return this.data;
+ },
+
+ isInvisible: function Annotation_isInvisible() {
+ var data = this.data;
+ if (data && SUPPORTED_TYPES.indexOf(data.subtype) !== -1) {
+ return false;
+ } else {
+ return !!(data &&
+ data.annotationFlags && // Default: not invisible
+ data.annotationFlags & 0x1); // Invisible
+ }
+ },
+
+ isViewable: function Annotation_isViewable() {
+ var data = this.data;
+ return !!(!this.isInvisible() &&
+ data &&
+ (!data.annotationFlags ||
+ !(data.annotationFlags & 0x22)) && // Hidden or NoView
+ data.rect); // rectangle is necessary
+ },
+
+ isPrintable: function Annotation_isPrintable() {
+ var data = this.data;
+ return !!(!this.isInvisible() &&
+ data &&
+ data.annotationFlags && // Default: not printable
+ data.annotationFlags & 0x4 && // Print
+ !(data.annotationFlags & 0x2) && // Hidden
+ data.rect); // rectangle is necessary
+ },
+
+ loadResources: function Annotation_loadResources(keys) {
+ return new Promise(function (resolve, reject) {
+ this.appearance.dict.getAsync('Resources').then(function (resources) {
+ if (!resources) {
+ resolve();
+ return;
+ }
+ var objectLoader = new ObjectLoader(resources.map,
+ keys,
+ resources.xref);
+ objectLoader.load().then(function() {
+ resolve(resources);
+ }, reject);
+ }, reject);
+ }.bind(this));
+ },
+
+ getOperatorList: function Annotation_getOperatorList(evaluator) {
+
+ if (!this.appearance) {
+ return Promise.resolve(new OperatorList());
+ }
+
+ var data = this.data;
+
+ var appearanceDict = this.appearance.dict;
+ var resourcesPromise = this.loadResources([
+ 'ExtGState',
+ 'ColorSpace',
+ 'Pattern',
+ 'Shading',
+ 'XObject',
+ 'Font'
+ // ProcSet
+ // Properties
+ ]);
+ var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
+ var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
+ var transform = getTransformMatrix(data.rect, bbox, matrix);
+ var self = this;
+
+ return resourcesPromise.then(function(resources) {
+ var opList = new OperatorList();
+ opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
+ return evaluator.getOperatorList(self.appearance, resources, opList).
+ then(function () {
+ opList.addOp(OPS.endAnnotation, []);
+ self.appearance.reset();
+ return opList;
+ });
+ });
+ }
+ };
+
+ Annotation.getConstructor =
+ function Annotation_getConstructor(subtype, fieldType) {
+
+ if (!subtype) {
+ return;
+ }
+
+ // TODO(mack): Implement FreeText annotations
+ if (subtype === 'Link') {
+ return LinkAnnotation;
+ } else if (subtype === 'Text') {
+ return TextAnnotation;
+ } else if (subtype === 'Widget') {
+ if (!fieldType) {
+ return;
+ }
+
+ if (fieldType === 'Tx') {
+ return TextWidgetAnnotation;
+ } else {
+ return WidgetAnnotation;
+ }
+ } else {
+ return Annotation;
+ }
+ };
+
+ Annotation.fromRef = function Annotation_fromRef(xref, ref) {
+
+ var dict = xref.fetchIfRef(ref);
+ if (!isDict(dict)) {
+ return;
+ }
+
+ var subtype = dict.get('Subtype');
+ subtype = isName(subtype) ? subtype.name : '';
+ if (!subtype) {
+ return;
+ }
+
+ var fieldType = Util.getInheritableProperty(dict, 'FT');
+ fieldType = isName(fieldType) ? fieldType.name : '';
+
+ var Constructor = Annotation.getConstructor(subtype, fieldType);
+ if (!Constructor) {
+ return;
+ }
+
+ var params = {
+ dict: dict,
+ ref: ref,
+ };
+
+ var annotation = new Constructor(params);
+
+ if (annotation.isViewable() || annotation.isPrintable()) {
+ return annotation;
+ } else {
+ if (SUPPORTED_TYPES.indexOf(subtype) === -1) {
+ warn('unimplemented annotation type: ' + subtype);
+ }
+ }
+ };
+
+ Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
+ annotations, opList, pdfManager, partialEvaluator, intent) {
+
+ function reject(e) {
+ annotationsReadyCapability.reject(e);
+ }
+
+ var annotationsReadyCapability = createPromiseCapability();
+
+ var annotationPromises = [];
+ for (var i = 0, n = annotations.length; i < n; ++i) {
+ if (intent === 'display' && annotations[i].isViewable() ||
+ intent === 'print' && annotations[i].isPrintable()) {
+ annotationPromises.push(
+ annotations[i].getOperatorList(partialEvaluator));
+ }
+ }
+ Promise.all(annotationPromises).then(function(datas) {
+ opList.addOp(OPS.beginAnnotations, []);
+ for (var i = 0, n = datas.length; i < n; ++i) {
+ var annotOpList = datas[i];
+ opList.addOpList(annotOpList);
+ }
+ opList.addOp(OPS.endAnnotations, []);
+ annotationsReadyCapability.resolve();
+ }, reject);
+
+ return annotationsReadyCapability.promise;
+ };
+
+ return Annotation;
+})();
+
+var WidgetAnnotation = (function WidgetAnnotationClosure() {
+
+ function WidgetAnnotation(params) {
+ Annotation.call(this, params);
+
+ var dict = params.dict;
+ var data = this.data;
+
+ data.fieldValue = stringToPDFString(
+ Util.getInheritableProperty(dict, 'V') || '');
+ data.alternativeText = stringToPDFString(dict.get('TU') || '');
+ data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
+ var fieldType = Util.getInheritableProperty(dict, 'FT');
+ data.fieldType = isName(fieldType) ? fieldType.name : '';
+ data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
+ this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
+
+ // Building the full field name by collecting the field and
+ // its ancestors 'T' data and joining them using '.'.
+ var fieldName = [];
+ var namedItem = dict;
+ var ref = params.ref;
+ while (namedItem) {
+ var parent = namedItem.get('Parent');
+ var parentRef = namedItem.getRaw('Parent');
+ var name = namedItem.get('T');
+ if (name) {
+ fieldName.unshift(stringToPDFString(name));
+ } else {
+ // The field name is absent, that means more than one field
+ // with the same name may exist. Replacing the empty name
+ // with the '`' plus index in the parent's 'Kids' array.
+ // This is not in the PDF spec but necessary to id the
+ // the input controls.
+ var kids = parent.get('Kids');
+ var j, jj;
+ for (j = 0, jj = kids.length; j < jj; j++) {
+ var kidRef = kids[j];
+ if (kidRef.num === ref.num && kidRef.gen === ref.gen) {
+ break;
+ }
+ }
+ fieldName.unshift('`' + j);
+ }
+ namedItem = parent;
+ ref = parentRef;
+ }
+ data.fullName = fieldName.join('.');
+ }
+
+ var parent = Annotation.prototype;
+ Util.inherit(WidgetAnnotation, Annotation, {
+ isViewable: function WidgetAnnotation_isViewable() {
+ if (this.data.fieldType === 'Sig') {
+ warn('unimplemented annotation type: Widget signature');
+ return false;
+ }
+
+ return parent.isViewable.call(this);
+ }
+ });
+
+ return WidgetAnnotation;
+})();
+
+var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
+ function TextWidgetAnnotation(params) {
+ WidgetAnnotation.call(this, params);
+
+ this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
+ this.data.annotationType = AnnotationType.WIDGET;
+ this.data.hasHtml = !this.data.hasAppearance && !!this.data.fieldValue;
+ }
+
+ Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
+ getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
+ if (this.appearance) {
+ return Annotation.prototype.getOperatorList.call(this, evaluator);
+ }
+
+ var opList = new OperatorList();
+ var data = this.data;
+
+ // Even if there is an appearance stream, ignore it. This is the
+ // behaviour used by Adobe Reader.
+ if (!data.defaultAppearance) {
+ return Promise.resolve(opList);
+ }
+
+ var stream = new Stream(stringToBytes(data.defaultAppearance));
+ return evaluator.getOperatorList(stream, this.fieldResources, opList).
+ then(function () {
+ return opList;
+ });
+ }
+ });
+
+ return TextWidgetAnnotation;
+})();
+
+var InteractiveAnnotation = (function InteractiveAnnotationClosure() {
+ function InteractiveAnnotation(params) {
+ Annotation.call(this, params);
+
+ this.data.hasHtml = true;
+ }
+
+ Util.inherit(InteractiveAnnotation, Annotation, { });
+
+ return InteractiveAnnotation;
+})();
+
+var TextAnnotation = (function TextAnnotationClosure() {
+ function TextAnnotation(params) {
+ InteractiveAnnotation.call(this, params);
+
+ var dict = params.dict;
+ var data = this.data;
+
+ var content = dict.get('Contents');
+ var title = dict.get('T');
+ data.annotationType = AnnotationType.TEXT;
+ data.content = stringToPDFString(content || '');
+ data.title = stringToPDFString(title || '');
+
+ if (data.hasAppearance) {
+ data.name = 'NoIcon';
+ } else {
+ data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
+ data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
+ data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
+ }
+
+ if (dict.has('C')) {
+ data.hasBgColor = true;
+ }
+ }
+
+ Util.inherit(TextAnnotation, InteractiveAnnotation, { });
+
+ return TextAnnotation;
+})();
+
+var LinkAnnotation = (function LinkAnnotationClosure() {
+ function LinkAnnotation(params) {
+ InteractiveAnnotation.call(this, params);
+
+ var dict = params.dict;
+ var data = this.data;
+ data.annotationType = AnnotationType.LINK;
+
+ var action = dict.get('A');
+ if (action) {
+ var linkType = action.get('S').name;
+ if (linkType === 'URI') {
+ var url = action.get('URI');
+ if (isName(url)) {
+ // Some bad PDFs do not put parentheses around relative URLs.
+ url = '/' + url.name;
+ } else if (url) {
+ url = addDefaultProtocolToUrl(url);
+ }
+ // TODO: pdf spec mentions urls can be relative to a Base
+ // entry in the dictionary.
+ if (!isValidUrl(url, false)) {
+ url = '';
+ }
+ data.url = url;
+ } else if (linkType === 'GoTo') {
+ data.dest = action.get('D');
+ } else if (linkType === 'GoToR') {
+ var urlDict = action.get('F');
+ if (isDict(urlDict)) {
+ // We assume that the 'url' is a Filspec dictionary
+ // and fetch the url without checking any further
+ url = urlDict.get('F') || '';
+ }
+
+ // TODO: pdf reference says that GoToR
+ // can also have 'NewWindow' attribute
+ if (!isValidUrl(url, false)) {
+ url = '';
+ }
+ data.url = url;
+ data.dest = action.get('D');
+ } else if (linkType === 'Named') {
+ data.action = action.get('N').name;
+ } else {
+ warn('unrecognized link type: ' + linkType);
+ }
+ } else if (dict.has('Dest')) {
+ // simple destination link
+ var dest = dict.get('Dest');
+ data.dest = isName(dest) ? dest.name : dest;
+ }
+ }
+
+ // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
+ function addDefaultProtocolToUrl(url) {
+ if (url && url.indexOf('www.') === 0) {
+ return ('http://' + url);
+ }
+ return url;
+ }
+
+ Util.inherit(LinkAnnotation, InteractiveAnnotation, {
+ hasOperatorList: function LinkAnnotation_hasOperatorList() {
+ return false;
+ }
+ });
+
+ return LinkAnnotation;
+})();
+
+
+var PDFFunction = (function PDFFunctionClosure() {
+ var CONSTRUCT_SAMPLED = 0;
+ var CONSTRUCT_INTERPOLATED = 2;
+ var CONSTRUCT_STICHED = 3;
+ var CONSTRUCT_POSTSCRIPT = 4;
+
+ return {
+ getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
+ str) {
+ var i, ii;
+ var length = 1;
+ for (i = 0, ii = size.length; i < ii; i++) {
+ length *= size[i];
+ }
+ length *= outputSize;
+
+ var array = new Array(length);
+ var codeSize = 0;
+ var codeBuf = 0;
+ // 32 is a valid bps so shifting won't work
+ var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
+
+ var strBytes = str.getBytes((length * bps + 7) / 8);
+ var strIdx = 0;
+ for (i = 0; i < length; i++) {
+ while (codeSize < bps) {
+ codeBuf <<= 8;
+ codeBuf |= strBytes[strIdx++];
+ codeSize += 8;
+ }
+ codeSize -= bps;
+ array[i] = (codeBuf >> codeSize) * sampleMul;
+ codeBuf &= (1 << codeSize) - 1;
+ }
+ return array;
+ },
+
+ getIR: function PDFFunction_getIR(xref, fn) {
+ var dict = fn.dict;
+ if (!dict) {
+ dict = fn;
+ }
+
+ var types = [this.constructSampled,
+ null,
+ this.constructInterpolated,
+ this.constructStiched,
+ this.constructPostScript];
+
+ var typeNum = dict.get('FunctionType');
+ var typeFn = types[typeNum];
+ if (!typeFn) {
+ error('Unknown type of function');
+ }
+
+ return typeFn.call(this, fn, dict, xref);
+ },
+
+ fromIR: function PDFFunction_fromIR(IR) {
+ var type = IR[0];
+ switch (type) {
+ case CONSTRUCT_SAMPLED:
+ return this.constructSampledFromIR(IR);
+ case CONSTRUCT_INTERPOLATED:
+ return this.constructInterpolatedFromIR(IR);
+ case CONSTRUCT_STICHED:
+ return this.constructStichedFromIR(IR);
+ //case CONSTRUCT_POSTSCRIPT:
+ default:
+ return this.constructPostScriptFromIR(IR);
+ }
+ },
+
+ parse: function PDFFunction_parse(xref, fn) {
+ var IR = this.getIR(xref, fn);
+ return this.fromIR(IR);
+ },
+
+ parseArray: function PDFFunction_parseArray(xref, fnObj) {
+ if (!isArray(fnObj)) {
+ // not an array -- parsing as regular function
+ return this.parse(xref, fnObj);
+ }
+
+ var fnArray = [];
+ for (var j = 0, jj = fnObj.length; j < jj; j++) {
+ var obj = xref.fetchIfRef(fnObj[j]);
+ fnArray.push(PDFFunction.parse(xref, obj));
+ }
+ return function (src, srcOffset, dest, destOffset) {
+ for (var i = 0, ii = fnArray.length; i < ii; i++) {
+ fnArray[i](src, srcOffset, dest, destOffset + i);
+ }
+ };
+ },
+
+ constructSampled: function PDFFunction_constructSampled(str, dict) {
+ function toMultiArray(arr) {
+ var inputLength = arr.length;
+ var out = [];
+ var index = 0;
+ for (var i = 0; i < inputLength; i += 2) {
+ out[index] = [arr[i], arr[i + 1]];
+ ++index;
+ }
+ return out;
+ }
+ var domain = dict.get('Domain');
+ var range = dict.get('Range');
+
+ if (!domain || !range) {
+ error('No domain or range');
+ }
+
+ var inputSize = domain.length / 2;
+ var outputSize = range.length / 2;
+
+ domain = toMultiArray(domain);
+ range = toMultiArray(range);
+
+ var size = dict.get('Size');
+ var bps = dict.get('BitsPerSample');
+ var order = dict.get('Order') || 1;
+ if (order !== 1) {
+ // No description how cubic spline interpolation works in PDF32000:2008
+ // As in poppler, ignoring order, linear interpolation may work as good
+ info('No support for cubic spline interpolation: ' + order);
+ }
+
+ var encode = dict.get('Encode');
+ if (!encode) {
+ encode = [];
+ for (var i = 0; i < inputSize; ++i) {
+ encode.push(0);
+ encode.push(size[i] - 1);
+ }
+ }
+ encode = toMultiArray(encode);
+
+ var decode = dict.get('Decode');
+ if (!decode) {
+ decode = range;
+ } else {
+ decode = toMultiArray(decode);
+ }
+
+ var samples = this.getSampleArray(size, outputSize, bps, str);
+
+ return [
+ CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
+ outputSize, Math.pow(2, bps) - 1, range
+ ];
+ },
+
+ constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
+ // See chapter 3, page 109 of the PDF reference
+ function interpolate(x, xmin, xmax, ymin, ymax) {
+ return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
+ }
+
+ return function constructSampledFromIRResult(src, srcOffset,
+ dest, destOffset) {
+ // See chapter 3, page 110 of the PDF reference.
+ var m = IR[1];
+ var domain = IR[2];
+ var encode = IR[3];
+ var decode = IR[4];
+ var samples = IR[5];
+ var size = IR[6];
+ var n = IR[7];
+ //var mask = IR[8];
+ var range = IR[9];
+
+ // Building the cube vertices: its part and sample index
+ // http://rjwagner49.com/Mathematics/Interpolation.pdf
+ var cubeVertices = 1 << m;
+ var cubeN = new Float64Array(cubeVertices);
+ var cubeVertex = new Uint32Array(cubeVertices);
+ var i, j;
+ for (j = 0; j < cubeVertices; j++) {
+ cubeN[j] = 1;
+ }
+
+ var k = n, pos = 1;
+ // Map x_i to y_j for 0 <= i < m using the sampled function.
+ for (i = 0; i < m; ++i) {
+ // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
+ var domain_2i = domain[i][0];
+ var domain_2i_1 = domain[i][1];
+ var xi = Math.min(Math.max(src[srcOffset +i], domain_2i),
+ domain_2i_1);
+
+ // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
+ // Encode_2i, Encode_2i+1)
+ var e = interpolate(xi, domain_2i, domain_2i_1,
+ encode[i][0], encode[i][1]);
+
+ // e_i' = min(max(e_i, 0), Size_i - 1)
+ var size_i = size[i];
+ e = Math.min(Math.max(e, 0), size_i - 1);
+
+ // Adjusting the cube: N and vertex sample index
+ var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
+ var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
+ var n1 = e - e0; // (e - e0) / (e1 - e0);
+ var offset0 = e0 * k;
+ var offset1 = offset0 + k; // e1 * k
+ for (j = 0; j < cubeVertices; j++) {
+ if (j & pos) {
+ cubeN[j] *= n1;
+ cubeVertex[j] += offset1;
+ } else {
+ cubeN[j] *= n0;
+ cubeVertex[j] += offset0;
+ }
+ }
+
+ k *= size_i;
+ pos <<= 1;
+ }
+
+ for (j = 0; j < n; ++j) {
+ // Sum all cube vertices' samples portions
+ var rj = 0;
+ for (i = 0; i < cubeVertices; i++) {
+ rj += samples[cubeVertex[i] + j] * cubeN[i];
+ }
+
+ // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
+ // Decode_2j, Decode_2j+1)
+ rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
+
+ // y_j = min(max(r_j, range_2j), range_2j+1)
+ dest[destOffset + j] = Math.min(Math.max(rj, range[j][0]),
+ range[j][1]);
+ }
+ };
+ },
+
+ constructInterpolated: function PDFFunction_constructInterpolated(str,
+ dict) {
+ var c0 = dict.get('C0') || [0];
+ var c1 = dict.get('C1') || [1];
+ var n = dict.get('N');
+
+ if (!isArray(c0) || !isArray(c1)) {
+ error('Illegal dictionary for interpolated function');
+ }
+
+ var length = c0.length;
+ var diff = [];
+ for (var i = 0; i < length; ++i) {
+ diff.push(c1[i] - c0[i]);
+ }
+
+ return [CONSTRUCT_INTERPOLATED, c0, diff, n];
+ },
+
+ constructInterpolatedFromIR:
+ function PDFFunction_constructInterpolatedFromIR(IR) {
+ var c0 = IR[1];
+ var diff = IR[2];
+ var n = IR[3];
+
+ var length = diff.length;
+
+ return function constructInterpolatedFromIRResult(src, srcOffset,
+ dest, destOffset) {
+ var x = n === 1 ? src[srcOffset] : Math.pow(src[srcOffset], n);
+
+ for (var j = 0; j < length; ++j) {
+ dest[destOffset + j] = c0[j] + (x * diff[j]);
+ }
+ };
+ },
+
+ constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
+ var domain = dict.get('Domain');
+
+ if (!domain) {
+ error('No domain');
+ }
+
+ var inputSize = domain.length / 2;
+ if (inputSize !== 1) {
+ error('Bad domain for stiched function');
+ }
+
+ var fnRefs = dict.get('Functions');
+ var fns = [];
+ for (var i = 0, ii = fnRefs.length; i < ii; ++i) {
+ fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
+ }
+
+ var bounds = dict.get('Bounds');
+ var encode = dict.get('Encode');
+
+ return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
+ },
+
+ constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
+ var domain = IR[1];
+ var bounds = IR[2];
+ var encode = IR[3];
+ var fnsIR = IR[4];
+ var fns = [];
+ var tmpBuf = new Float32Array(1);
+
+ for (var i = 0, ii = fnsIR.length; i < ii; i++) {
+ fns.push(PDFFunction.fromIR(fnsIR[i]));
+ }
+
+ return function constructStichedFromIRResult(src, srcOffset,
+ dest, destOffset) {
+ var clip = function constructStichedFromIRClip(v, min, max) {
+ if (v > max) {
+ v = max;
+ } else if (v < min) {
+ v = min;
+ }
+ return v;
+ };
+
+ // clip to domain
+ var v = clip(src[srcOffset], domain[0], domain[1]);
+ // calulate which bound the value is in
+ for (var i = 0, ii = bounds.length; i < ii; ++i) {
+ if (v < bounds[i]) {
+ break;
+ }
+ }
+
+ // encode value into domain of function
+ var dmin = domain[0];
+ if (i > 0) {
+ dmin = bounds[i - 1];
+ }
+ var dmax = domain[1];
+ if (i < bounds.length) {
+ dmax = bounds[i];
+ }
+
+ var rmin = encode[2 * i];
+ var rmax = encode[2 * i + 1];
+
+ tmpBuf[0] = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
+
+ // call the appropriate function
+ fns[i](tmpBuf, 0, dest, destOffset);
+ };
+ },
+
+ constructPostScript: function PDFFunction_constructPostScript(fn, dict,
+ xref) {
+ var domain = dict.get('Domain');
+ var range = dict.get('Range');
+
+ if (!domain) {
+ error('No domain.');
+ }
+
+ if (!range) {
+ error('No range.');
+ }
+
+ var lexer = new PostScriptLexer(fn);
+ var parser = new PostScriptParser(lexer);
+ var code = parser.parse();
+
+ return [CONSTRUCT_POSTSCRIPT, domain, range, code];
+ },
+
+ constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
+ IR) {
+ var domain = IR[1];
+ var range = IR[2];
+ var code = IR[3];
+
+ var compiled = (new PostScriptCompiler()).compile(code, domain, range);
+ if (compiled) {
+ // Compiled function consists of simple expressions such as addition,
+ // subtraction, Math.max, and also contains 'var' and 'return'
+ // statements. See the generation in the PostScriptCompiler below.
+ /*jshint -W054 */
+ return new Function('src', 'srcOffset', 'dest', 'destOffset', compiled);
+ }
+
+ info('Unable to compile PS function');
+
+ var numOutputs = range.length >> 1;
+ var numInputs = domain.length >> 1;
+ var evaluator = new PostScriptEvaluator(code);
+ // Cache the values for a big speed up, the cache size is limited though
+ // since the number of possible values can be huge from a PS function.
+ var cache = {};
+ // The MAX_CACHE_SIZE is set to ~4x the maximum number of distinct values
+ // seen in our tests.
+ var MAX_CACHE_SIZE = 2048 * 4;
+ var cache_available = MAX_CACHE_SIZE;
+ var tmpBuf = new Float32Array(numInputs);
+
+ return function constructPostScriptFromIRResult(src, srcOffset,
+ dest, destOffset) {
+ var i, value;
+ var key = '';
+ var input = tmpBuf;
+ for (i = 0; i < numInputs; i++) {
+ value = src[srcOffset + i];
+ input[i] = value;
+ key += value + '_';
+ }
+
+ var cachedValue = cache[key];
+ if (cachedValue !== undefined) {
+ cachedValue.set(dest, destOffset);
+ return;
+ }
+
+ var output = new Float32Array(numOutputs);
+ var stack = evaluator.execute(input);
+ var stackIndex = stack.length - numOutputs;
+ for (i = 0; i < numOutputs; i++) {
+ value = stack[stackIndex + i];
+ var bound = range[i * 2];
+ if (value < bound) {
+ value = bound;
+ } else {
+ bound = range[i * 2 +1];
+ if (value > bound) {
+ value = bound;
+ }
+ }
+ output[i] = value;
+ }
+ if (cache_available > 0) {
+ cache_available--;
+ cache[key] = output;
+ }
+ output.set(dest, destOffset);
+ };
+ }
+ };
+})();
+
+function isPDFFunction(v) {
+ var fnDict;
+ if (typeof v !== 'object') {
+ return false;
+ } else if (isDict(v)) {
+ fnDict = v;
+ } else if (isStream(v)) {
+ fnDict = v.dict;
+ } else {
+ return false;
+ }
+ return fnDict.has('FunctionType');
+}
+
+var PostScriptStack = (function PostScriptStackClosure() {
+ var MAX_STACK_SIZE = 100;
+ function PostScriptStack(initialStack) {
+ this.stack = !initialStack ? [] :
+ Array.prototype.slice.call(initialStack, 0);
+ }
+
+ PostScriptStack.prototype = {
+ push: function PostScriptStack_push(value) {
+ if (this.stack.length >= MAX_STACK_SIZE) {
+ error('PostScript function stack overflow.');
+ }
+ this.stack.push(value);
+ },
+ pop: function PostScriptStack_pop() {
+ if (this.stack.length <= 0) {
+ error('PostScript function stack underflow.');
+ }
+ return this.stack.pop();
+ },
+ copy: function PostScriptStack_copy(n) {
+ if (this.stack.length + n >= MAX_STACK_SIZE) {
+ error('PostScript function stack overflow.');
+ }
+ var stack = this.stack;
+ for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++) {
+ stack.push(stack[i]);
+ }
+ },
+ index: function PostScriptStack_index(n) {
+ this.push(this.stack[this.stack.length - n - 1]);
+ },
+ // rotate the last n stack elements p times
+ roll: function PostScriptStack_roll(n, p) {
+ var stack = this.stack;
+ var l = stack.length - n;
+ var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
+ for (i = l, j = r; i < j; i++, j--) {
+ t = stack[i]; stack[i] = stack[j]; stack[j] = t;
+ }
+ for (i = l, j = c - 1; i < j; i++, j--) {
+ t = stack[i]; stack[i] = stack[j]; stack[j] = t;
+ }
+ for (i = c, j = r; i < j; i++, j--) {
+ t = stack[i]; stack[i] = stack[j]; stack[j] = t;
+ }
+ }
+ };
+ return PostScriptStack;
+})();
+var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
+ function PostScriptEvaluator(operators) {
+ this.operators = operators;
+ }
+ PostScriptEvaluator.prototype = {
+ execute: function PostScriptEvaluator_execute(initialStack) {
+ var stack = new PostScriptStack(initialStack);
+ var counter = 0;
+ var operators = this.operators;
+ var length = operators.length;
+ var operator, a, b;
+ while (counter < length) {
+ operator = operators[counter++];
+ if (typeof operator === 'number') {
+ // Operator is really an operand and should be pushed to the stack.
+ stack.push(operator);
+ continue;
+ }
+ switch (operator) {
+ // non standard ps operators
+ case 'jz': // jump if false
+ b = stack.pop();
+ a = stack.pop();
+ if (!a) {
+ counter = b;
+ }
+ break;
+ case 'j': // jump
+ a = stack.pop();
+ counter = a;
+ break;
+
+ // all ps operators in alphabetical order (excluding if/ifelse)
+ case 'abs':
+ a = stack.pop();
+ stack.push(Math.abs(a));
+ break;
+ case 'add':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a + b);
+ break;
+ case 'and':
+ b = stack.pop();
+ a = stack.pop();
+ if (isBool(a) && isBool(b)) {
+ stack.push(a && b);
+ } else {
+ stack.push(a & b);
+ }
+ break;
+ case 'atan':
+ a = stack.pop();
+ stack.push(Math.atan(a));
+ break;
+ case 'bitshift':
+ b = stack.pop();
+ a = stack.pop();
+ if (a > 0) {
+ stack.push(a << b);
+ } else {
+ stack.push(a >> b);
+ }
+ break;
+ case 'ceiling':
+ a = stack.pop();
+ stack.push(Math.ceil(a));
+ break;
+ case 'copy':
+ a = stack.pop();
+ stack.copy(a);
+ break;
+ case 'cos':
+ a = stack.pop();
+ stack.push(Math.cos(a));
+ break;
+ case 'cvi':
+ a = stack.pop() | 0;
+ stack.push(a);
+ break;
+ case 'cvr':
+ // noop
+ break;
+ case 'div':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a / b);
+ break;
+ case 'dup':
+ stack.copy(1);
+ break;
+ case 'eq':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a === b);
+ break;
+ case 'exch':
+ stack.roll(2, 1);
+ break;
+ case 'exp':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(Math.pow(a, b));
+ break;
+ case 'false':
+ stack.push(false);
+ break;
+ case 'floor':
+ a = stack.pop();
+ stack.push(Math.floor(a));
+ break;
+ case 'ge':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a >= b);
+ break;
+ case 'gt':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a > b);
+ break;
+ case 'idiv':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push((a / b) | 0);
+ break;
+ case 'index':
+ a = stack.pop();
+ stack.index(a);
+ break;
+ case 'le':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a <= b);
+ break;
+ case 'ln':
+ a = stack.pop();
+ stack.push(Math.log(a));
+ break;
+ case 'log':
+ a = stack.pop();
+ stack.push(Math.log(a) / Math.LN10);
+ break;
+ case 'lt':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a < b);
+ break;
+ case 'mod':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a % b);
+ break;
+ case 'mul':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a * b);
+ break;
+ case 'ne':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a !== b);
+ break;
+ case 'neg':
+ a = stack.pop();
+ stack.push(-a);
+ break;
+ case 'not':
+ a = stack.pop();
+ if (isBool(a)) {
+ stack.push(!a);
+ } else {
+ stack.push(~a);
+ }
+ break;
+ case 'or':
+ b = stack.pop();
+ a = stack.pop();
+ if (isBool(a) && isBool(b)) {
+ stack.push(a || b);
+ } else {
+ stack.push(a | b);
+ }
+ break;
+ case 'pop':
+ stack.pop();
+ break;
+ case 'roll':
+ b = stack.pop();
+ a = stack.pop();
+ stack.roll(a, b);
+ break;
+ case 'round':
+ a = stack.pop();
+ stack.push(Math.round(a));
+ break;
+ case 'sin':
+ a = stack.pop();
+ stack.push(Math.sin(a));
+ break;
+ case 'sqrt':
+ a = stack.pop();
+ stack.push(Math.sqrt(a));
+ break;
+ case 'sub':
+ b = stack.pop();
+ a = stack.pop();
+ stack.push(a - b);
+ break;
+ case 'true':
+ stack.push(true);
+ break;
+ case 'truncate':
+ a = stack.pop();
+ a = a < 0 ? Math.ceil(a) : Math.floor(a);
+ stack.push(a);
+ break;
+ case 'xor':
+ b = stack.pop();
+ a = stack.pop();
+ if (isBool(a) && isBool(b)) {
+ stack.push(a !== b);
+ } else {
+ stack.push(a ^ b);
+ }
+ break;
+ default:
+ error('Unknown operator ' + operator);
+ break;
+ }
+ }
+ return stack.stack;
+ }
+ };
+ return PostScriptEvaluator;
+})();
+
+// Most of the PDFs functions consist of simple operations such as:
+// roll, exch, sub, cvr, pop, index, dup, mul, if, gt, add.
+//
+// We can compile most of such programs, and at the same moment, we can
+// optimize some expressions using basic math properties. Keeping track of
+// min/max values will allow us to avoid extra Math.min/Math.max calls.
+var PostScriptCompiler = (function PostScriptCompilerClosure() {
+ function AstNode(type) {
+ this.type = type;
+ }
+ AstNode.prototype.visit = function (visitor) {
+ throw new Error('abstract method');
+ };
+
+ function AstArgument(index, min, max) {
+ AstNode.call(this, 'args');
+ this.index = index;
+ this.min = min;
+ this.max = max;
+ }
+ AstArgument.prototype = Object.create(AstNode.prototype);
+ AstArgument.prototype.visit = function (visitor) {
+ visitor.visitArgument(this);
+ };
+
+ function AstLiteral(number) {
+ AstNode.call(this, 'literal');
+ this.number = number;
+ this.min = number;
+ this.max = number;
+ }
+ AstLiteral.prototype = Object.create(AstNode.prototype);
+ AstLiteral.prototype.visit = function (visitor) {
+ visitor.visitLiteral(this);
+ };
+
+ function AstBinaryOperation(op, arg1, arg2, min, max) {
+ AstNode.call(this, 'binary');
+ this.op = op;
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.min = min;
+ this.max = max;
+ }
+ AstBinaryOperation.prototype = Object.create(AstNode.prototype);
+ AstBinaryOperation.prototype.visit = function (visitor) {
+ visitor.visitBinaryOperation(this);
+ };
+
+ function AstMin(arg, max) {
+ AstNode.call(this, 'max');
+ this.arg = arg;
+ this.min = arg.min;
+ this.max = max;
+ }
+ AstMin.prototype = Object.create(AstNode.prototype);
+ AstMin.prototype.visit = function (visitor) {
+ visitor.visitMin(this);
+ };
+
+ function AstVariable(index, min, max) {
+ AstNode.call(this, 'var');
+ this.index = index;
+ this.min = min;
+ this.max = max;
+ }
+ AstVariable.prototype = Object.create(AstNode.prototype);
+ AstVariable.prototype.visit = function (visitor) {
+ visitor.visitVariable(this);
+ };
+
+ function AstVariableDefinition(variable, arg) {
+ AstNode.call(this, 'definition');
+ this.variable = variable;
+ this.arg = arg;
+ }
+ AstVariableDefinition.prototype = Object.create(AstNode.prototype);
+ AstVariableDefinition.prototype.visit = function (visitor) {
+ visitor.visitVariableDefinition(this);
+ };
+
+ function ExpressionBuilderVisitor() {
+ this.parts = [];
+ }
+ ExpressionBuilderVisitor.prototype = {
+ visitArgument: function (arg) {
+ this.parts.push('Math.max(', arg.min, ', Math.min(',
+ arg.max, ', src[srcOffset + ', arg.index, ']))');
+ },
+ visitVariable: function (variable) {
+ this.parts.push('v', variable.index);
+ },
+ visitLiteral: function (literal) {
+ this.parts.push(literal.number);
+ },
+ visitBinaryOperation: function (operation) {
+ this.parts.push('(');
+ operation.arg1.visit(this);
+ this.parts.push(' ', operation.op, ' ');
+ operation.arg2.visit(this);
+ this.parts.push(')');
+ },
+ visitVariableDefinition: function (definition) {
+ this.parts.push('var ');
+ definition.variable.visit(this);
+ this.parts.push(' = ');
+ definition.arg.visit(this);
+ this.parts.push(';');
+ },
+ visitMin: function (max) {
+ this.parts.push('Math.min(');
+ max.arg.visit(this);
+ this.parts.push(', ', max.max, ')');
+ },
+ toString: function () {
+ return this.parts.join('');
+ }
+ };
+
+ function buildAddOperation(num1, num2) {
+ if (num2.type === 'literal' && num2.number === 0) {
+ // optimization: second operand is 0
+ return num1;
+ }
+ if (num1.type === 'literal' && num1.number === 0) {
+ // optimization: first operand is 0
+ return num2;
+ }
+ if (num2.type === 'literal' && num1.type === 'literal') {
+ // optimization: operands operand are literals
+ return new AstLiteral(num1.number + num2.number);
+ }
+ return new AstBinaryOperation('+', num1, num2,
+ num1.min + num2.min, num1.max + num2.max);
+ }
+
+ function buildMulOperation(num1, num2) {
+ if (num2.type === 'literal') {
+ // optimization: second operands is a literal...
+ if (num2.number === 0) {
+ return new AstLiteral(0); // and it's 0
+ } else if (num2.number === 1) {
+ return num1; // and it's 1
+ } else if (num1.type === 'literal') {
+ // ... and first operands is a literal too
+ return new AstLiteral(num1.number * num2.number);
+ }
+ }
+ if (num1.type === 'literal') {
+ // optimization: first operands is a literal...
+ if (num1.number === 0) {
+ return new AstLiteral(0); // and it's 0
+ } else if (num1.number === 1) {
+ return num2; // and it's 1
+ }
+ }
+ var min = Math.min(num1.min * num2.min, num1.min * num2.max,
+ num1.max * num2.min, num1.max * num2.max);
+ var max = Math.max(num1.min * num2.min, num1.min * num2.max,
+ num1.max * num2.min, num1.max * num2.max);
+ return new AstBinaryOperation('*', num1, num2, min, max);
+ }
+
+ function buildSubOperation(num1, num2) {
+ if (num2.type === 'literal') {
+ // optimization: second operands is a literal...
+ if (num2.number === 0) {
+ return num1; // ... and it's 0
+ } else if (num1.type === 'literal') {
+ // ... and first operands is a literal too
+ return new AstLiteral(num1.number - num2.number);
+ }
+ }
+ if (num2.type === 'binary' && num2.op === '-' &&
+ num1.type === 'literal' && num1.number === 1 &&
+ num2.arg1.type === 'literal' && num2.arg1.number === 1) {
+ // optimization for case: 1 - (1 - x)
+ return num2.arg2;
+ }
+ return new AstBinaryOperation('-', num1, num2,
+ num1.min - num2.max, num1.max - num2.min);
+ }
+
+ function buildMinOperation(num1, max) {
+ if (num1.min >= max) {
+ // optimization: num1 min value is not less than required max
+ return new AstLiteral(max); // just returning max
+ } else if (num1.max <= max) {
+ // optimization: num1 max value is not greater than required max
+ return num1; // just returning an argument
+ }
+ return new AstMin(num1, max);
+ }
+
+ function PostScriptCompiler() {}
+ PostScriptCompiler.prototype = {
+ compile: function PostScriptCompiler_compile(code, domain, range) {
+ var stack = [];
+ var i, ii;
+ var instructions = [];
+ var inputSize = domain.length >> 1, outputSize = range.length >> 1;
+ var lastRegister = 0;
+ var n, j, min, max;
+ var num1, num2, ast1, ast2, tmpVar, item;
+ for (i = 0; i < inputSize; i++) {
+ stack.push(new AstArgument(i, domain[i * 2], domain[i * 2 + 1]));
+ }
+
+ for (i = 0, ii = code.length; i < ii; i++) {
+ item = code[i];
+ if (typeof item === 'number') {
+ stack.push(new AstLiteral(item));
+ continue;
+ }
+
+ switch (item) {
+ case 'add':
+ if (stack.length < 2) {
+ return null;
+ }
+ num2 = stack.pop();
+ num1 = stack.pop();
+ stack.push(buildAddOperation(num1, num2));
+ break;
+ case 'cvr':
+ if (stack.length < 1) {
+ return null;
+ }
+ break;
+ case 'mul':
+ if (stack.length < 2) {
+ return null;
+ }
+ num2 = stack.pop();
+ num1 = stack.pop();
+ stack.push(buildMulOperation(num1, num2));
+ break;
+ case 'sub':
+ if (stack.length < 2) {
+ return null;
+ }
+ num2 = stack.pop();
+ num1 = stack.pop();
+ stack.push(buildSubOperation(num1, num2));
+ break;
+ case 'exch':
+ if (stack.length < 2) {
+ return null;
+ }
+ ast1 = stack.pop(); ast2 = stack.pop();
+ stack.push(ast1, ast2);
+ break;
+ case 'pop':
+ if (stack.length < 1) {
+ return null;
+ }
+ stack.pop();
+ break;
+ case 'index':
+ if (stack.length < 1) {
+ return null;
+ }
+ num1 = stack.pop();
+ if (num1.type !== 'literal') {
+ return null;
+ }
+ n = num1.number;
+ if (n < 0 || (n|0) !== n || stack.length < n) {
+ return null;
+ }
+ ast1 = stack[stack.length - n - 1];
+ if (ast1.type === 'literal' || ast1.type === 'var') {
+ stack.push(ast1);
+ break;
+ }
+ tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
+ stack[stack.length - n - 1] = tmpVar;
+ stack.push(tmpVar);
+ instructions.push(new AstVariableDefinition(tmpVar, ast1));
+ break;
+ case 'dup':
+ if (stack.length < 1) {
+ return null;
+ }
+ if (typeof code[i + 1] === 'number' && code[i + 2] === 'gt' &&
+ code[i + 3] === i + 7 && code[i + 4] === 'jz' &&
+ code[i + 5] === 'pop' && code[i + 6] === code[i + 1]) {
+ // special case of the commands sequence for the min operation
+ num1 = stack.pop();
+ stack.push(buildMinOperation(num1, code[i + 1]));
+ i += 6;
+ break;
+ }
+ ast1 = stack[stack.length - 1];
+ if (ast1.type === 'literal' || ast1.type === 'var') {
+ // we don't have to save into intermediate variable a literal or
+ // variable.
+ stack.push(ast1);
+ break;
+ }
+ tmpVar = new AstVariable(lastRegister++, ast1.min, ast1.max);
+ stack[stack.length - 1] = tmpVar;
+ stack.push(tmpVar);
+ instructions.push(new AstVariableDefinition(tmpVar, ast1));
+ break;
+ case 'roll':
+ if (stack.length < 2) {
+ return null;
+ }
+ num2 = stack.pop();
+ num1 = stack.pop();
+ if (num2.type !== 'literal' || num1.type !== 'literal') {
+ // both roll operands must be numbers
+ return null;
+ }
+ j = num2.number;
+ n = num1.number;
+ if (n <= 0 || (n|0) !== n || (j|0) !== j || stack.length < n) {
+ // ... and integers
+ return null;
+ }
+ j = ((j % n) + n) % n;
+ if (j === 0) {
+ break; // just skipping -- there are nothing to rotate
+ }
+ Array.prototype.push.apply(stack,
+ stack.splice(stack.length - n, n - j));
+ break;
+ default:
+ return null; // unsupported operator
+ }
+ }
+
+ if (stack.length !== outputSize) {
+ return null;
+ }
+
+ var result = [];
+ instructions.forEach(function (instruction) {
+ var statementBuilder = new ExpressionBuilderVisitor();
+ instruction.visit(statementBuilder);
+ result.push(statementBuilder.toString());
+ });
+ stack.forEach(function (expr, i) {
+ var statementBuilder = new ExpressionBuilderVisitor();
+ expr.visit(statementBuilder);
+ var min = range[i * 2], max = range[i * 2 + 1];
+ var out = [statementBuilder.toString()];
+ if (min > expr.min) {
+ out.unshift('Math.max(', min, ', ');
+ out.push(')');
+ }
+ if (max < expr.max) {
+ out.unshift('Math.min(', max, ', ');
+ out.push(')');
+ }
+ out.unshift('dest[destOffset + ', i, '] = ');
+ out.push(';');
+ result.push(out.join(''));
+ });
+ return result.join('\n');
+ }
+ };
+
+ return PostScriptCompiler;
+})();
+
+
+var ColorSpace = (function ColorSpaceClosure() {
+ // Constructor should define this.numComps, this.defaultColor, this.name
+ function ColorSpace() {
+ error('should not call ColorSpace constructor');
+ }
+
+ ColorSpace.prototype = {
+ /**
+ * Converts the color value to the RGB color. The color components are
+ * located in the src array starting from the srcOffset. Returns the array
+ * of the rgb components, each value ranging from [0,255].
+ */
+ getRgb: function ColorSpace_getRgb(src, srcOffset) {
+ var rgb = new Uint8Array(3);
+ this.getRgbItem(src, srcOffset, rgb, 0);
+ return rgb;
+ },
+ /**
+ * Converts the color value to the RGB color, similar to the getRgb method.
+ * The result placed into the dest array starting from the destOffset.
+ */
+ getRgbItem: function ColorSpace_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ error('Should not call ColorSpace.getRgbItem');
+ },
+ /**
+ * Converts the specified number of the color values to the RGB colors.
+ * The colors are located in the src array starting from the srcOffset.
+ * The result is placed into the dest array starting from the destOffset.
+ * The src array items shall be in [0,2^bits) range, the dest array items
+ * will be in [0,255] range. alpha01 indicates how many alpha components
+ * there are in the dest array; it will be either 0 (RGB array) or 1 (RGBA
+ * array).
+ */
+ getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ error('Should not call ColorSpace.getRgbBuffer');
+ },
+ /**
+ * Determines the number of bytes required to store the result of the
+ * conversion done by the getRgbBuffer method. As in getRgbBuffer,
+ * |alpha01| is either 0 (RGB output) or 1 (RGBA output).
+ */
+ getOutputLength: function ColorSpace_getOutputLength(inputLength,
+ alpha01) {
+ error('Should not call ColorSpace.getOutputLength');
+ },
+ /**
+ * Returns true if source data will be equal the result/output data.
+ */
+ isPassthrough: function ColorSpace_isPassthrough(bits) {
+ return false;
+ },
+ /**
+ * Fills in the RGB colors in the destination buffer. alpha01 indicates
+ * how many alpha components there are in the dest array; it will be either
+ * 0 (RGB array) or 1 (RGBA array).
+ */
+ fillRgb: function ColorSpace_fillRgb(dest, originalWidth,
+ originalHeight, width, height,
+ actualHeight, bpc, comps, alpha01) {
+ var count = originalWidth * originalHeight;
+ var rgbBuf = null;
+ var numComponentColors = 1 << bpc;
+ var needsResizing = originalHeight !== height || originalWidth !== width;
+ var i, ii;
+
+ if (this.isPassthrough(bpc)) {
+ rgbBuf = comps;
+ } else if (this.numComps === 1 && count > numComponentColors &&
+ this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
+ // Optimization: create a color map when there is just one component and
+ // we are converting more colors than the size of the color map. We
+ // don't build the map if the colorspace is gray or rgb since those
+ // methods are faster than building a map. This mainly offers big speed
+ // ups for indexed and alternate colorspaces.
+ //
+ // TODO it may be worth while to cache the color map. While running
+ // testing I never hit a cache so I will leave that out for now (perhaps
+ // we are reparsing colorspaces too much?).
+ var allColors = bpc <= 8 ? new Uint8Array(numComponentColors) :
+ new Uint16Array(numComponentColors);
+ var key;
+ for (i = 0; i < numComponentColors; i++) {
+ allColors[i] = i;
+ }
+ var colorMap = new Uint8Array(numComponentColors * 3);
+ this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bpc,
+ /* alpha01 = */ 0);
+
+ var destPos, rgbPos;
+ if (!needsResizing) {
+ // Fill in the RGB values directly into |dest|.
+ destPos = 0;
+ for (i = 0; i < count; ++i) {
+ key = comps[i] * 3;
+ dest[destPos++] = colorMap[key];
+ dest[destPos++] = colorMap[key + 1];
+ dest[destPos++] = colorMap[key + 2];
+ destPos += alpha01;
+ }
+ } else {
+ rgbBuf = new Uint8Array(count * 3);
+ rgbPos = 0;
+ for (i = 0; i < count; ++i) {
+ key = comps[i] * 3;
+ rgbBuf[rgbPos++] = colorMap[key];
+ rgbBuf[rgbPos++] = colorMap[key + 1];
+ rgbBuf[rgbPos++] = colorMap[key + 2];
+ }
+ }
+ } else {
+ if (!needsResizing) {
+ // Fill in the RGB values directly into |dest|.
+ this.getRgbBuffer(comps, 0, width * actualHeight, dest, 0, bpc,
+ alpha01);
+ } else {
+ rgbBuf = new Uint8Array(count * 3);
+ this.getRgbBuffer(comps, 0, count, rgbBuf, 0, bpc,
+ /* alpha01 = */ 0);
+ }
+ }
+
+ if (rgbBuf) {
+ if (needsResizing) {
+ PDFImage.resize(rgbBuf, bpc, 3, originalWidth, originalHeight, width,
+ height, dest, alpha01);
+ } else {
+ rgbPos = 0;
+ destPos = 0;
+ for (i = 0, ii = width * actualHeight; i < ii; i++) {
+ dest[destPos++] = rgbBuf[rgbPos++];
+ dest[destPos++] = rgbBuf[rgbPos++];
+ dest[destPos++] = rgbBuf[rgbPos++];
+ destPos += alpha01;
+ }
+ }
+ }
+ },
+ /**
+ * True if the colorspace has components in the default range of [0, 1].
+ * This should be true for all colorspaces except for lab color spaces
+ * which are [0,100], [-128, 127], [-128, 127].
+ */
+ usesZeroToOneRange: true
+ };
+
+ ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
+ var IR = ColorSpace.parseToIR(cs, xref, res);
+ if (IR instanceof AlternateCS) {
+ return IR;
+ }
+ return ColorSpace.fromIR(IR);
+ };
+
+ ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
+ var name = isArray(IR) ? IR[0] : IR;
+ var whitePoint, blackPoint, gamma;
+
+ switch (name) {
+ case 'DeviceGrayCS':
+ return this.singletons.gray;
+ case 'DeviceRgbCS':
+ return this.singletons.rgb;
+ case 'DeviceCmykCS':
+ return this.singletons.cmyk;
+ case 'CalGrayCS':
+ whitePoint = IR[1].WhitePoint;
+ blackPoint = IR[1].BlackPoint;
+ gamma = IR[1].Gamma;
+ return new CalGrayCS(whitePoint, blackPoint, gamma);
+ case 'CalRGBCS':
+ whitePoint = IR[1].WhitePoint;
+ blackPoint = IR[1].BlackPoint;
+ gamma = IR[1].Gamma;
+ var matrix = IR[1].Matrix;
+ return new CalRGBCS(whitePoint, blackPoint, gamma, matrix);
+ case 'PatternCS':
+ var basePatternCS = IR[1];
+ if (basePatternCS) {
+ basePatternCS = ColorSpace.fromIR(basePatternCS);
+ }
+ return new PatternCS(basePatternCS);
+ case 'IndexedCS':
+ var baseIndexedCS = IR[1];
+ var hiVal = IR[2];
+ var lookup = IR[3];
+ return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
+ case 'AlternateCS':
+ var numComps = IR[1];
+ var alt = IR[2];
+ var tintFnIR = IR[3];
+
+ return new AlternateCS(numComps, ColorSpace.fromIR(alt),
+ PDFFunction.fromIR(tintFnIR));
+ case 'LabCS':
+ whitePoint = IR[1].WhitePoint;
+ blackPoint = IR[1].BlackPoint;
+ var range = IR[1].Range;
+ return new LabCS(whitePoint, blackPoint, range);
+ default:
+ error('Unknown name ' + name);
+ }
+ return null;
+ };
+
+ ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
+ if (isName(cs)) {
+ var colorSpaces = res.get('ColorSpace');
+ if (isDict(colorSpaces)) {
+ var refcs = colorSpaces.get(cs.name);
+ if (refcs) {
+ cs = refcs;
+ }
+ }
+ }
+
+ cs = xref.fetchIfRef(cs);
+ var mode;
+
+ if (isName(cs)) {
+ mode = cs.name;
+ this.mode = mode;
+
+ switch (mode) {
+ case 'DeviceGray':
+ case 'G':
+ return 'DeviceGrayCS';
+ case 'DeviceRGB':
+ case 'RGB':
+ return 'DeviceRgbCS';
+ case 'DeviceCMYK':
+ case 'CMYK':
+ return 'DeviceCmykCS';
+ case 'Pattern':
+ return ['PatternCS', null];
+ default:
+ error('unrecognized colorspace ' + mode);
+ }
+ } else if (isArray(cs)) {
+ mode = cs[0].name;
+ this.mode = mode;
+ var numComps, params;
+
+ switch (mode) {
+ case 'DeviceGray':
+ case 'G':
+ return 'DeviceGrayCS';
+ case 'DeviceRGB':
+ case 'RGB':
+ return 'DeviceRgbCS';
+ case 'DeviceCMYK':
+ case 'CMYK':
+ return 'DeviceCmykCS';
+ case 'CalGray':
+ params = cs[1].getAll();
+ return ['CalGrayCS', params];
+ case 'CalRGB':
+ params = cs[1].getAll();
+ return ['CalRGBCS', params];
+ case 'ICCBased':
+ var stream = xref.fetchIfRef(cs[1]);
+ var dict = stream.dict;
+ numComps = dict.get('N');
+ if (numComps === 1) {
+ return 'DeviceGrayCS';
+ } else if (numComps === 3) {
+ return 'DeviceRgbCS';
+ } else if (numComps === 4) {
+ return 'DeviceCmykCS';
+ }
+ break;
+ case 'Pattern':
+ var basePatternCS = cs[1];
+ if (basePatternCS) {
+ basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
+ }
+ return ['PatternCS', basePatternCS];
+ case 'Indexed':
+ case 'I':
+ var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
+ var hiVal = cs[2] + 1;
+ var lookup = xref.fetchIfRef(cs[3]);
+ if (isStream(lookup)) {
+ lookup = lookup.getBytes();
+ }
+ return ['IndexedCS', baseIndexedCS, hiVal, lookup];
+ case 'Separation':
+ case 'DeviceN':
+ var name = cs[1];
+ numComps = 1;
+ if (isName(name)) {
+ numComps = 1;
+ } else if (isArray(name)) {
+ numComps = name.length;
+ }
+ var alt = ColorSpace.parseToIR(cs[2], xref, res);
+ var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
+ return ['AlternateCS', numComps, alt, tintFnIR];
+ case 'Lab':
+ params = cs[1].getAll();
+ return ['LabCS', params];
+ default:
+ error('unimplemented color space object "' + mode + '"');
+ }
+ } else {
+ error('unrecognized color space object: "' + cs + '"');
+ }
+ return null;
+ };
+ /**
+ * Checks if a decode map matches the default decode map for a color space.
+ * This handles the general decode maps where there are two values per
+ * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
+ * This does not handle Lab, Indexed, or Pattern decode maps since they are
+ * slightly different.
+ * @param {Array} decode Decode map (usually from an image).
+ * @param {Number} n Number of components the color space has.
+ */
+ ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
+ if (!decode) {
+ return true;
+ }
+
+ if (n * 2 !== decode.length) {
+ warn('The decode map is not the correct length');
+ return true;
+ }
+ for (var i = 0, ii = decode.length; i < ii; i += 2) {
+ if (decode[i] !== 0 || decode[i + 1] !== 1) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ ColorSpace.singletons = {
+ get gray() {
+ return shadow(this, 'gray', new DeviceGrayCS());
+ },
+ get rgb() {
+ return shadow(this, 'rgb', new DeviceRgbCS());
+ },
+ get cmyk() {
+ return shadow(this, 'cmyk', new DeviceCmykCS());
+ }
+ };
+
+ return ColorSpace;
+})();
+
+/**
+ * Alternate color space handles both Separation and DeviceN color spaces. A
+ * Separation color space is actually just a DeviceN with one color component.
+ * Both color spaces use a tinting function to convert colors to a base color
+ * space.
+ */
+var AlternateCS = (function AlternateCSClosure() {
+ function AlternateCS(numComps, base, tintFn) {
+ this.name = 'Alternate';
+ this.numComps = numComps;
+ this.defaultColor = new Float32Array(numComps);
+ for (var i = 0; i < numComps; ++i) {
+ this.defaultColor[i] = 1;
+ }
+ this.base = base;
+ this.tintFn = tintFn;
+ this.tmpBuf = new Float32Array(base.numComps);
+ }
+
+ AlternateCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var tmpBuf = this.tmpBuf;
+ this.tintFn(src, srcOffset, tmpBuf, 0);
+ this.base.getRgbItem(tmpBuf, 0, dest, destOffset);
+ },
+ getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var tintFn = this.tintFn;
+ var base = this.base;
+ var scale = 1 / ((1 << bits) - 1);
+ var baseNumComps = base.numComps;
+ var usesZeroToOneRange = base.usesZeroToOneRange;
+ var isPassthrough = (base.isPassthrough(8) || !usesZeroToOneRange) &&
+ alpha01 === 0;
+ var pos = isPassthrough ? destOffset : 0;
+ var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
+ var numComps = this.numComps;
+
+ var scaled = new Float32Array(numComps);
+ var tinted = new Float32Array(baseNumComps);
+ var i, j;
+ if (usesZeroToOneRange) {
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < numComps; j++) {
+ scaled[j] = src[srcOffset++] * scale;
+ }
+ tintFn(scaled, 0, tinted, 0);
+ for (j = 0; j < baseNumComps; j++) {
+ baseBuf[pos++] = tinted[j] * 255;
+ }
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < numComps; j++) {
+ scaled[j] = src[srcOffset++] * scale;
+ }
+ tintFn(scaled, 0, tinted, 0);
+ base.getRgbItem(tinted, 0, baseBuf, pos);
+ pos += baseNumComps;
+ }
+ }
+ if (!isPassthrough) {
+ base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8, alpha01);
+ }
+ },
+ getOutputLength: function AlternateCS_getOutputLength(inputLength,
+ alpha01) {
+ return this.base.getOutputLength(inputLength *
+ this.base.numComps / this.numComps,
+ alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+
+ return AlternateCS;
+})();
+
+var PatternCS = (function PatternCSClosure() {
+ function PatternCS(baseCS) {
+ this.name = 'Pattern';
+ this.base = baseCS;
+ }
+ PatternCS.prototype = {};
+
+ return PatternCS;
+})();
+
+var IndexedCS = (function IndexedCSClosure() {
+ function IndexedCS(base, highVal, lookup) {
+ this.name = 'Indexed';
+ this.numComps = 1;
+ this.defaultColor = new Uint8Array([0]);
+ this.base = base;
+ this.highVal = highVal;
+
+ var baseNumComps = base.numComps;
+ var length = baseNumComps * highVal;
+ var lookupArray;
+
+ if (isStream(lookup)) {
+ lookupArray = new Uint8Array(length);
+ var bytes = lookup.getBytes(length);
+ lookupArray.set(bytes);
+ } else if (isString(lookup)) {
+ lookupArray = new Uint8Array(length);
+ for (var i = 0; i < length; ++i) {
+ lookupArray[i] = lookup.charCodeAt(i);
+ }
+ } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
+ lookupArray = lookup;
+ } else {
+ error('Unrecognized lookup table: ' + lookup);
+ }
+ this.lookup = lookupArray;
+ }
+
+ IndexedCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var numComps = this.base.numComps;
+ var start = src[srcOffset] * numComps;
+ this.base.getRgbItem(this.lookup, start, dest, destOffset);
+ },
+ getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var base = this.base;
+ var numComps = base.numComps;
+ var outputDelta = base.getOutputLength(numComps, alpha01);
+ var lookup = this.lookup;
+
+ for (var i = 0; i < count; ++i) {
+ var lookupPos = src[srcOffset++] * numComps;
+ base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8, alpha01);
+ destOffset += outputDelta;
+ }
+ },
+ getOutputLength: function IndexedCS_getOutputLength(inputLength, alpha01) {
+ return this.base.getOutputLength(inputLength * this.base.numComps,
+ alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
+ // indexed color maps shouldn't be changed
+ return true;
+ },
+ usesZeroToOneRange: true
+ };
+ return IndexedCS;
+})();
+
+var DeviceGrayCS = (function DeviceGrayCSClosure() {
+ function DeviceGrayCS() {
+ this.name = 'DeviceGray';
+ this.numComps = 1;
+ this.defaultColor = new Float32Array([0]);
+ }
+
+ DeviceGrayCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var c = (src[srcOffset] * 255) | 0;
+ c = c < 0 ? 0 : c > 255 ? 255 : c;
+ dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
+ },
+ getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 255 / ((1 << bits) - 1);
+ var j = srcOffset, q = destOffset;
+ for (var i = 0; i < count; ++i) {
+ var c = (scale * src[j++]) | 0;
+ dest[q++] = c;
+ dest[q++] = c;
+ dest[q++] = c;
+ q += alpha01;
+ }
+ },
+ getOutputLength: function DeviceGrayCS_getOutputLength(inputLength,
+ alpha01) {
+ return inputLength * (3 + alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return DeviceGrayCS;
+})();
+
+var DeviceRgbCS = (function DeviceRgbCSClosure() {
+ function DeviceRgbCS() {
+ this.name = 'DeviceRGB';
+ this.numComps = 3;
+ this.defaultColor = new Float32Array([0, 0, 0]);
+ }
+ DeviceRgbCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ var r = (src[srcOffset] * 255) | 0;
+ var g = (src[srcOffset + 1] * 255) | 0;
+ var b = (src[srcOffset + 2] * 255) | 0;
+ dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
+ dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
+ dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
+ },
+ getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ if (bits === 8 && alpha01 === 0) {
+ dest.set(src.subarray(srcOffset, srcOffset + count * 3), destOffset);
+ return;
+ }
+ var scale = 255 / ((1 << bits) - 1);
+ var j = srcOffset, q = destOffset;
+ for (var i = 0; i < count; ++i) {
+ dest[q++] = (scale * src[j++]) | 0;
+ dest[q++] = (scale * src[j++]) | 0;
+ dest[q++] = (scale * src[j++]) | 0;
+ q += alpha01;
+ }
+ },
+ getOutputLength: function DeviceRgbCS_getOutputLength(inputLength,
+ alpha01) {
+ return (inputLength * (3 + alpha01) / 3) | 0;
+ },
+ isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
+ return bits === 8;
+ },
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return DeviceRgbCS;
+})();
+
+var DeviceCmykCS = (function DeviceCmykCSClosure() {
+ // The coefficients below was found using numerical analysis: the method of
+ // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
+ // where color_value is the tabular value from the table of sampled RGB colors
+ // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
+ // CMYK color conversion using the estimation below:
+ // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
+ function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
+ var c = src[srcOffset + 0] * srcScale;
+ var m = src[srcOffset + 1] * srcScale;
+ var y = src[srcOffset + 2] * srcScale;
+ var k = src[srcOffset + 3] * srcScale;
+
+ var r =
+ (c * (-4.387332384609988 * c + 54.48615194189176 * m +
+ 18.82290502165302 * y + 212.25662451639585 * k +
+ -285.2331026137004) +
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y +
+ -17.873870861415444 * k - 5.497006427196366) +
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+ 17.5119270841813) +
+ k * (-21.86122147463605 * k - 189.48180835922747) + 255) | 0;
+ var g =
+ (c * (8.841041422036149 * c + 60.118027045597366 * m +
+ 6.871425592049007 * y + 31.159100130055922 * k +
+ -79.2970844816548) +
+ m * (-15.310361306967817 * m + 17.575251261109482 * y +
+ 131.35250912493976 * k - 190.9453302588951) +
+ y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
+ k * (-20.737325471181034 * k - 187.80453709719578) + 255) | 0;
+ var b =
+ (c * (0.8842522430003296 * c + 8.078677503112928 * m +
+ 30.89978309703729 * y - 0.23883238689178934 * k +
+ -14.183576799673286) +
+ m * (10.49593273432072 * m + 63.02378494754052 * y +
+ 50.606957656360734 * k - 112.23884253719248) +
+ y * (0.03296041114873217 * y + 115.60384449646641 * k +
+ -193.58209356861505) +
+ k * (-22.33816807309886 * k - 180.12613974708367) + 255) | 0;
+
+ dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
+ dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
+ dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
+ }
+
+ function DeviceCmykCS() {
+ this.name = 'DeviceCMYK';
+ this.numComps = 4;
+ this.defaultColor = new Float32Array([0, 0, 0, 1]);
+ }
+ DeviceCmykCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ convertToRgb(src, srcOffset, 1, dest, destOffset);
+ },
+ getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 1 / ((1 << bits) - 1);
+ for (var i = 0; i < count; i++) {
+ convertToRgb(src, srcOffset, scale, dest, destOffset);
+ srcOffset += 4;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function DeviceCmykCS_getOutputLength(inputLength,
+ alpha01) {
+ return (inputLength / 4 * (3 + alpha01)) | 0;
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+
+ return DeviceCmykCS;
+})();
+
+//
+// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
+//
+var CalGrayCS = (function CalGrayCSClosure() {
+ function CalGrayCS(whitePoint, blackPoint, gamma) {
+ this.name = 'CalGray';
+ this.numComps = 1;
+ this.defaultColor = new Float32Array([0]);
+
+ if (!whitePoint) {
+ error('WhitePoint missing - required for color space CalGray');
+ }
+ blackPoint = blackPoint || [0, 0, 0];
+ gamma = gamma || 1;
+
+ // Translate arguments to spec variables.
+ this.XW = whitePoint[0];
+ this.YW = whitePoint[1];
+ this.ZW = whitePoint[2];
+
+ this.XB = blackPoint[0];
+ this.YB = blackPoint[1];
+ this.ZB = blackPoint[2];
+
+ this.G = gamma;
+
+ // Validate variables as per spec.
+ if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
+ error('Invalid WhitePoint components for ' + this.name +
+ ', no fallback available');
+ }
+
+ if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
+ info('Invalid BlackPoint for ' + this.name + ', falling back to default');
+ this.XB = this.YB = this.ZB = 0;
+ }
+
+ if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
+ warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
+ ', ZB: ' + this.ZB + ', only default values are supported.');
+ }
+
+ if (this.G < 1) {
+ info('Invalid Gamma: ' + this.G + ' for ' + this.name +
+ ', falling back to default');
+ this.G = 1;
+ }
+ }
+
+ function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
+ // A represents a gray component of a calibrated gray space.
+ // A <---> AG in the spec
+ var A = src[srcOffset] * scale;
+ var AG = Math.pow(A, cs.G);
+
+ // Computes L as per spec. ( = cs.YW * AG )
+ // Except if other than default BlackPoint values are used.
+ var L = cs.YW * AG;
+ // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
+ // Convert values to rgb range [0, 255].
+ var val = Math.max(295.8 * Math.pow(L, 0.333333333333333333) - 40.8, 0) | 0;
+ dest[destOffset] = val;
+ dest[destOffset + 1] = val;
+ dest[destOffset + 2] = val;
+ }
+
+ CalGrayCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ convertToRgb(this, src, srcOffset, dest, destOffset, 1);
+ },
+ getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 1 / ((1 << bits) - 1);
+
+ for (var i = 0; i < count; ++i) {
+ convertToRgb(this, src, srcOffset, dest, destOffset, scale);
+ srcOffset += 1;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function CalGrayCS_getOutputLength(inputLength, alpha01) {
+ return inputLength * (3 + alpha01);
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return CalGrayCS;
+})();
+
+//
+// CalRGBCS: Based on "PDF Reference, Sixth Ed", p.247
+//
+var CalRGBCS = (function CalRGBCSClosure() {
+
+ // See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html for these
+ // matrices.
+ var BRADFORD_SCALE_MATRIX = new Float32Array([
+ 0.8951, 0.2664, -0.1614,
+ -0.7502, 1.7135, 0.0367,
+ 0.0389, -0.0685, 1.0296]);
+
+ var BRADFORD_SCALE_INVERSE_MATRIX = new Float32Array([
+ 0.9869929, -0.1470543, 0.1599627,
+ 0.4323053, 0.5183603, 0.0492912,
+ -0.0085287, 0.0400428, 0.9684867]);
+
+ // See http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html.
+ var SRGB_D65_XYZ_TO_RGB_MATRIX = new Float32Array([
+ 3.2404542, -1.5371385, -0.4985314,
+ -0.9692660, 1.8760108, 0.0415560,
+ 0.0556434, -0.2040259, 1.0572252]);
+
+ var FLAT_WHITEPOINT_MATRIX = new Float32Array([1, 1, 1]);
+
+ var tempNormalizeMatrix = new Float32Array(3);
+ var tempConvertMatrix1 = new Float32Array(3);
+ var tempConvertMatrix2 = new Float32Array(3);
+
+ var DECODE_L_CONSTANT = Math.pow(((8 + 16) / 116), 3) / 8.0;
+
+ function CalRGBCS(whitePoint, blackPoint, gamma, matrix) {
+ this.name = 'CalRGB';
+ this.numComps = 3;
+ this.defaultColor = new Float32Array(3);
+
+ if (!whitePoint) {
+ error('WhitePoint missing - required for color space CalRGB');
+ }
+ blackPoint = blackPoint || new Float32Array(3);
+ gamma = gamma || new Float32Array([1, 1, 1]);
+ matrix = matrix || new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]);
+
+ // Translate arguments to spec variables.
+ var XW = whitePoint[0];
+ var YW = whitePoint[1];
+ var ZW = whitePoint[2];
+ this.whitePoint = whitePoint;
+
+ var XB = blackPoint[0];
+ var YB = blackPoint[1];
+ var ZB = blackPoint[2];
+ this.blackPoint = blackPoint;
+
+ this.GR = gamma[0];
+ this.GG = gamma[1];
+ this.GB = gamma[2];
+
+ this.MXA = matrix[0];
+ this.MYA = matrix[1];
+ this.MZA = matrix[2];
+ this.MXB = matrix[3];
+ this.MYB = matrix[4];
+ this.MZB = matrix[5];
+ this.MXC = matrix[6];
+ this.MYC = matrix[7];
+ this.MZC = matrix[8];
+
+ // Validate variables as per spec.
+ if (XW < 0 || ZW < 0 || YW !== 1) {
+ error('Invalid WhitePoint components for ' + this.name +
+ ', no fallback available');
+ }
+
+ if (XB < 0 || YB < 0 || ZB < 0) {
+ info('Invalid BlackPoint for ' + this.name + ' [' + XB + ', ' + YB +
+ ', ' + ZB + '], falling back to default');
+ this.blackPoint = new Float32Array(3);
+ }
+
+ if (this.GR < 0 || this.GG < 0 || this.GB < 0) {
+ info('Invalid Gamma [' + this.GR + ', ' + this.GG + ', ' + this.GB +
+ '] for ' + this.name + ', falling back to default');
+ this.GR = this.GG = this.GB = 1;
+ }
+
+ if (this.MXA < 0 || this.MYA < 0 || this.MZA < 0 ||
+ this.MXB < 0 || this.MYB < 0 || this.MZB < 0 ||
+ this.MXC < 0 || this.MYC < 0 || this.MZC < 0) {
+ info('Invalid Matrix for ' + this.name + ' [' +
+ this.MXA + ', ' + this.MYA + ', ' + this.MZA +
+ this.MXB + ', ' + this.MYB + ', ' + this.MZB +
+ this.MXC + ', ' + this.MYC + ', ' + this.MZC +
+ '], falling back to default');
+ this.MXA = this.MYB = this.MZC = 1;
+ this.MXB = this.MYA = this.MZA = this.MXC = this.MYC = this.MZB = 0;
+ }
+ }
+
+ function matrixProduct(a, b, result) {
+ result[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+ result[1] = a[3] * b[0] + a[4] * b[1] + a[5] * b[2];
+ result[2] = a[6] * b[0] + a[7] * b[1] + a[8] * b[2];
+ }
+
+ function convertToFlat(sourceWhitePoint, LMS, result) {
+ result[0] = LMS[0] * 1 / sourceWhitePoint[0];
+ result[1] = LMS[1] * 1 / sourceWhitePoint[1];
+ result[2] = LMS[2] * 1 / sourceWhitePoint[2];
+ }
+
+ function convertToD65(sourceWhitePoint, LMS, result) {
+ var D65X = 0.95047;
+ var D65Y = 1;
+ var D65Z = 1.08883;
+
+ result[0] = LMS[0] * D65X / sourceWhitePoint[0];
+ result[1] = LMS[1] * D65Y / sourceWhitePoint[1];
+ result[2] = LMS[2] * D65Z / sourceWhitePoint[2];
+ }
+
+ function sRGBTransferFunction(color) {
+ // See http://en.wikipedia.org/wiki/SRGB.
+ if (color <= 0.0031308){
+ return adjustToRange(0, 1, 12.92 * color);
+ }
+
+ return adjustToRange(0, 1, (1 + 0.055) * Math.pow(color, 1 / 2.4) - 0.055);
+ }
+
+ function adjustToRange(min, max, value) {
+ return Math.max(min, Math.min(max, value));
+ }
+
+ function decodeL(L) {
+ if (L < 0) {
+ return -decodeL(-L);
+ }
+
+ if (L > 8.0) {
+ return Math.pow(((L + 16) / 116), 3);
+ }
+
+ return L * DECODE_L_CONSTANT;
+ }
+
+ function compensateBlackPoint(sourceBlackPoint, XYZ_Flat, result) {
+
+ // In case the blackPoint is already the default blackPoint then there is
+ // no need to do compensation.
+ if (sourceBlackPoint[0] === 0 &&
+ sourceBlackPoint[1] === 0 &&
+ sourceBlackPoint[2] === 0) {
+ result[0] = XYZ_Flat[0];
+ result[1] = XYZ_Flat[1];
+ result[2] = XYZ_Flat[2];
+ return;
+ }
+
+ // For the blackPoint calculation details, please see
+ // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/
+ // AdobeBPC.pdf.
+ // The destination blackPoint is the default blackPoint [0, 0, 0].
+ var zeroDecodeL = decodeL(0);
+
+ var X_DST = zeroDecodeL;
+ var X_SRC = decodeL(sourceBlackPoint[0]);
+
+ var Y_DST = zeroDecodeL;
+ var Y_SRC = decodeL(sourceBlackPoint[1]);
+
+ var Z_DST = zeroDecodeL;
+ var Z_SRC = decodeL(sourceBlackPoint[2]);
+
+ var X_Scale = (1 - X_DST) / (1 - X_SRC);
+ var X_Offset = 1 - X_Scale;
+
+ var Y_Scale = (1 - Y_DST) / (1 - Y_SRC);
+ var Y_Offset = 1 - Y_Scale;
+
+ var Z_Scale = (1 - Z_DST) / (1 - Z_SRC);
+ var Z_Offset = 1 - Z_Scale;
+
+ result[0] = XYZ_Flat[0] * X_Scale + X_Offset;
+ result[1] = XYZ_Flat[1] * Y_Scale + Y_Offset;
+ result[2] = XYZ_Flat[2] * Z_Scale + Z_Offset;
+ }
+
+ function normalizeWhitePointToFlat(sourceWhitePoint, XYZ_In, result) {
+
+ // In case the whitePoint is already flat then there is no need to do
+ // normalization.
+ if (sourceWhitePoint[0] === 1 && sourceWhitePoint[2] === 1) {
+ result[0] = XYZ_In[0];
+ result[1] = XYZ_In[1];
+ result[2] = XYZ_In[2];
+ return;
+ }
+
+ var LMS = result;
+ matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
+
+ var LMS_Flat = tempNormalizeMatrix;
+ convertToFlat(sourceWhitePoint, LMS, LMS_Flat);
+
+ matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_Flat, result);
+ }
+
+ function normalizeWhitePointToD65(sourceWhitePoint, XYZ_In, result) {
+
+ var LMS = result;
+ matrixProduct(BRADFORD_SCALE_MATRIX, XYZ_In, LMS);
+
+ var LMS_D65 = tempNormalizeMatrix;
+ convertToD65(sourceWhitePoint, LMS, LMS_D65);
+
+ matrixProduct(BRADFORD_SCALE_INVERSE_MATRIX, LMS_D65, result);
+ }
+
+ function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
+ // A, B and C represent a red, green and blue components of a calibrated
+ // rgb space.
+ var A = adjustToRange(0, 1, src[srcOffset] * scale);
+ var B = adjustToRange(0, 1, src[srcOffset + 1] * scale);
+ var C = adjustToRange(0, 1, src[srcOffset + 2] * scale);
+
+ // A <---> AGR in the spec
+ // B <---> BGG in the spec
+ // C <---> CGB in the spec
+ var AGR = Math.pow(A, cs.GR);
+ var BGG = Math.pow(B, cs.GG);
+ var CGB = Math.pow(C, cs.GB);
+
+ // Computes intermediate variables L, M, N as per spec.
+ // To decode X, Y, Z values map L, M, N directly to them.
+ var X = cs.MXA * AGR + cs.MXB * BGG + cs.MXC * CGB;
+ var Y = cs.MYA * AGR + cs.MYB * BGG + cs.MYC * CGB;
+ var Z = cs.MZA * AGR + cs.MZB * BGG + cs.MZC * CGB;
+
+ // The following calculations are based on this document:
+ // http://www.adobe.com/content/dam/Adobe/en/devnet/photoshop/sdk/
+ // AdobeBPC.pdf.
+ var XYZ = tempConvertMatrix1;
+ XYZ[0] = X;
+ XYZ[1] = Y;
+ XYZ[2] = Z;
+ var XYZ_Flat = tempConvertMatrix2;
+
+ normalizeWhitePointToFlat(cs.whitePoint, XYZ, XYZ_Flat);
+
+ var XYZ_Black = tempConvertMatrix1;
+ compensateBlackPoint(cs.blackPoint, XYZ_Flat, XYZ_Black);
+
+ var XYZ_D65 = tempConvertMatrix2;
+ normalizeWhitePointToD65(FLAT_WHITEPOINT_MATRIX, XYZ_Black, XYZ_D65);
+
+ var SRGB = tempConvertMatrix1;
+ matrixProduct(SRGB_D65_XYZ_TO_RGB_MATRIX, XYZ_D65, SRGB);
+
+ var sR = sRGBTransferFunction(SRGB[0]);
+ var sG = sRGBTransferFunction(SRGB[1]);
+ var sB = sRGBTransferFunction(SRGB[2]);
+
+ // Convert the values to rgb range [0, 255].
+ dest[destOffset] = Math.round(sR * 255);
+ dest[destOffset + 1] = Math.round(sG * 255);
+ dest[destOffset + 2] = Math.round(sB * 255);
+ }
+
+ CalRGBCS.prototype = {
+ getRgb: function CalRGBCS_getRgb(src, srcOffset) {
+ var rgb = new Uint8Array(3);
+ this.getRgbItem(src, srcOffset, rgb, 0);
+ return rgb;
+ },
+ getRgbItem: function CalRGBCS_getRgbItem(src, srcOffset,
+ dest, destOffset) {
+ convertToRgb(this, src, srcOffset, dest, destOffset, 1);
+ },
+ getRgbBuffer: function CalRGBCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var scale = 1 / ((1 << bits) - 1);
+
+ for (var i = 0; i < count; ++i) {
+ convertToRgb(this, src, srcOffset, dest, destOffset, scale);
+ srcOffset += 3;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function CalRGBCS_getOutputLength(inputLength, alpha01) {
+ return (inputLength * (3 + alpha01) / 3) | 0;
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function CalRGBCS_isDefaultDecode(decodeMap) {
+ return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
+ },
+ usesZeroToOneRange: true
+ };
+ return CalRGBCS;
+})();
+
+//
+// LabCS: Based on "PDF Reference, Sixth Ed", p.250
+//
+var LabCS = (function LabCSClosure() {
+ function LabCS(whitePoint, blackPoint, range) {
+ this.name = 'Lab';
+ this.numComps = 3;
+ this.defaultColor = new Float32Array([0, 0, 0]);
+
+ if (!whitePoint) {
+ error('WhitePoint missing - required for color space Lab');
+ }
+ blackPoint = blackPoint || [0, 0, 0];
+ range = range || [-100, 100, -100, 100];
+
+ // Translate args to spec variables
+ this.XW = whitePoint[0];
+ this.YW = whitePoint[1];
+ this.ZW = whitePoint[2];
+ this.amin = range[0];
+ this.amax = range[1];
+ this.bmin = range[2];
+ this.bmax = range[3];
+
+ // These are here just for completeness - the spec doesn't offer any
+ // formulas that use BlackPoint in Lab
+ this.XB = blackPoint[0];
+ this.YB = blackPoint[1];
+ this.ZB = blackPoint[2];
+
+ // Validate vars as per spec
+ if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
+ error('Invalid WhitePoint components, no fallback available');
+ }
+
+ if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
+ info('Invalid BlackPoint, falling back to default');
+ this.XB = this.YB = this.ZB = 0;
+ }
+
+ if (this.amin > this.amax || this.bmin > this.bmax) {
+ info('Invalid Range, falling back to defaults');
+ this.amin = -100;
+ this.amax = 100;
+ this.bmin = -100;
+ this.bmax = 100;
+ }
+ }
+
+ // Function g(x) from spec
+ function fn_g(x) {
+ if (x >= 6 / 29) {
+ return x * x * x;
+ } else {
+ return (108 / 841) * (x - 4 / 29);
+ }
+ }
+
+ function decode(value, high1, low2, high2) {
+ return low2 + (value) * (high2 - low2) / (high1);
+ }
+
+ // If decoding is needed maxVal should be 2^bits per component - 1.
+ function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
+ // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
+ // not the usual [0, 1]. If a command like setFillColor is used the src
+ // values will already be within the correct range. However, if we are
+ // converting an image we have to map the values to the correct range given
+ // above.
+ // Ls,as,bs <---> L*,a*,b* in the spec
+ var Ls = src[srcOffset];
+ var as = src[srcOffset + 1];
+ var bs = src[srcOffset + 2];
+ if (maxVal !== false) {
+ Ls = decode(Ls, maxVal, 0, 100);
+ as = decode(as, maxVal, cs.amin, cs.amax);
+ bs = decode(bs, maxVal, cs.bmin, cs.bmax);
+ }
+
+ // Adjust limits of 'as' and 'bs'
+ as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
+ bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
+
+ // Computes intermediate variables X,Y,Z as per spec
+ var M = (Ls + 16) / 116;
+ var L = M + (as / 500);
+ var N = M - (bs / 200);
+
+ var X = cs.XW * fn_g(L);
+ var Y = cs.YW * fn_g(M);
+ var Z = cs.ZW * fn_g(N);
+
+ var r, g, b;
+ // Using different conversions for D50 and D65 white points,
+ // per http://www.color.org/srgb.pdf
+ if (cs.ZW < 1) {
+ // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
+ r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
+ g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
+ b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
+ } else {
+ // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
+ r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
+ g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
+ b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
+ }
+ // clamp color values to [0,1] range then convert to [0,255] range.
+ dest[destOffset] = r <= 0 ? 0 : r >= 1 ? 255 : Math.sqrt(r) * 255 | 0;
+ dest[destOffset + 1] = g <= 0 ? 0 : g >= 1 ? 255 : Math.sqrt(g) * 255 | 0;
+ dest[destOffset + 2] = b <= 0 ? 0 : b >= 1 ? 255 : Math.sqrt(b) * 255 | 0;
+ }
+
+ LabCS.prototype = {
+ getRgb: ColorSpace.prototype.getRgb,
+ getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
+ convertToRgb(this, src, srcOffset, false, dest, destOffset);
+ },
+ getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
+ dest, destOffset, bits,
+ alpha01) {
+ var maxVal = (1 << bits) - 1;
+ for (var i = 0; i < count; i++) {
+ convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
+ srcOffset += 3;
+ destOffset += 3 + alpha01;
+ }
+ },
+ getOutputLength: function LabCS_getOutputLength(inputLength, alpha01) {
+ return (inputLength * (3 + alpha01) / 3) | 0;
+ },
+ isPassthrough: ColorSpace.prototype.isPassthrough,
+ fillRgb: ColorSpace.prototype.fillRgb,
+ isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
+ // XXX: Decoding is handled with the lab conversion because of the strange
+ // ranges that are used.
+ return true;
+ },
+ usesZeroToOneRange: false
+ };
+ return LabCS;
+})();
var ARCFourCipher = (function ARCFourCipherClosure() {
@@ -13889,8 +7722,9 @@ var ARCFourCipher = (function ARCFourCipherClosure() {
this.b = 0;
var s = new Uint8Array(256);
var i, j = 0, tmp, keyLength = key.length;
- for (i = 0; i < 256; ++i)
+ for (i = 0; i < 256; ++i) {
s[i] = i;
+ }
for (i = 0; i < 256; ++i) {
tmp = s[i];
j = (j + tmp + key[i % keyLength]) & 0xFF;
@@ -13950,12 +7784,14 @@ var calculateMD5 = (function calculateMD5Closure() {
var paddedLength = (length + 72) & ~63; // data + 9 extra bytes
var padded = new Uint8Array(paddedLength);
var i, j, n;
- for (i = 0; i < length; ++i)
+ for (i = 0; i < length; ++i) {
padded[i] = data[offset++];
+ }
padded[i++] = 0x80;
n = paddedLength - 8;
- while (i < n)
+ while (i < n) {
padded[i++] = 0;
+ }
padded[i++] = (length << 3) & 0xFF;
padded[i++] = (length >> 5) & 0xFF;
padded[i++] = (length >> 13) & 0xFF;
@@ -13964,13 +7800,11 @@ var calculateMD5 = (function calculateMD5Closure() {
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
- // chunking
- // TODO ArrayBuffer ?
var w = new Int32Array(16);
for (i = 0; i < paddedLength;) {
for (j = 0; j < 16; ++j, i += 4) {
w[j] = (padded[i] | (padded[i + 1] << 8) |
- (padded[i + 2] << 16) | (padded[i + 3] << 24));
+ (padded[i + 2] << 16) | (padded[i + 3] << 24));
}
var a = h0, b = h1, c = h2, d = h3, f, g;
for (j = 0; j < 64; ++j) {
@@ -13999,15 +7833,487 @@ var calculateMD5 = (function calculateMD5Closure() {
h3 = (h3 + d) | 0;
}
return new Uint8Array([
- h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF,
- h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF,
- h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF,
- h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF
+ h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF,
+ h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF,
+ h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF,
+ h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF
]);
}
+
+ return hash;
+})();
+var Word64 = (function Word64Closure() {
+ function Word64(highInteger, lowInteger) {
+ this.high = highInteger | 0;
+ this.low = lowInteger | 0;
+ }
+ Word64.prototype = {
+ and: function Word64_and(word) {
+ this.high &= word.high;
+ this.low &= word.low;
+ },
+ xor: function Word64_xor(word) {
+ this.high ^= word.high;
+ this.low ^= word.low;
+ },
+
+ or: function Word64_or(word) {
+ this.high |= word.high;
+ this.low |= word.low;
+ },
+
+ shiftRight: function Word64_shiftRight(places) {
+ if (places >= 32) {
+ this.low = (this.high >>> (places - 32)) | 0;
+ this.high = 0;
+ } else {
+ this.low = (this.low >>> places) | (this.high << (32 - places));
+ this.high = (this.high >>> places) | 0;
+ }
+ },
+
+ shiftLeft: function Word64_shiftLeft(places) {
+ if (places >= 32) {
+ this.high = this.low << (places - 32);
+ this.low = 0;
+ } else {
+ this.high = (this.high << places) | (this.low >>> (32 - places));
+ this.low = this.low << places;
+ }
+ },
+
+ rotateRight: function Word64_rotateRight(places) {
+ var low, high;
+ if (places & 32) {
+ high = this.low;
+ low = this.high;
+ } else {
+ low = this.low;
+ high = this.high;
+ }
+ places &= 31;
+ this.low = (low >>> places) | (high << (32 - places));
+ this.high = (high >>> places) | (low << (32 - places));
+ },
+
+ not: function Word64_not() {
+ this.high = ~this.high;
+ this.low = ~this.low;
+ },
+
+ add: function Word64_add(word) {
+ var lowAdd = (this.low >>> 0) + (word.low >>> 0);
+ var highAdd = (this.high >>> 0) + (word.high >>> 0);
+ if (lowAdd > 0xFFFFFFFF) {
+ highAdd += 1;
+ }
+ this.low = lowAdd | 0;
+ this.high = highAdd | 0;
+ },
+
+ copyTo: function Word64_copyTo(bytes, offset) {
+ bytes[offset] = (this.high >>> 24) & 0xFF;
+ bytes[offset + 1] = (this.high >> 16) & 0xFF;
+ bytes[offset + 2] = (this.high >> 8) & 0xFF;
+ bytes[offset + 3] = this.high & 0xFF;
+ bytes[offset + 4] = (this.low >>> 24) & 0xFF;
+ bytes[offset + 5] = (this.low >> 16) & 0xFF;
+ bytes[offset + 6] = (this.low >> 8) & 0xFF;
+ bytes[offset + 7] = this.low & 0xFF;
+ },
+
+ assign: function Word64_assign(word) {
+ this.high = word.high;
+ this.low = word.low;
+ }
+ };
+ return Word64;
+})();
+
+var calculateSHA256 = (function calculateSHA256Closure() {
+ function rotr(x, n) {
+ return (x >>> n) | (x << 32 - n);
+ }
+
+ function ch(x, y, z) {
+ return (x & y) ^ (~x & z);
+ }
+
+ function maj(x, y, z) {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ function sigma(x) {
+ return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
+ }
+
+ function sigmaPrime(x) {
+ return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
+ }
+
+ function littleSigma(x) {
+ return rotr(x, 7) ^ rotr(x, 18) ^ x >>> 3;
+ }
+
+ function littleSigmaPrime(x) {
+ return rotr(x, 17) ^ rotr(x, 19) ^ x >>> 10;
+ }
+
+ var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2];
+
+ function hash(data, offset, length) {
+ // initial hash values
+ var h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372,
+ h3 = 0xa54ff53a, h4 = 0x510e527f, h5 = 0x9b05688c,
+ h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
+ // pre-processing
+ var paddedLength = Math.ceil((length + 9) / 64) * 64;
+ var padded = new Uint8Array(paddedLength);
+ var i, j, n;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ n = paddedLength - 8;
+ while (i < n) {
+ padded[i++] = 0;
+ }
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = (length >>> 29) & 0xFF;
+ padded[i++] = (length >> 21) & 0xFF;
+ padded[i++] = (length >> 13) & 0xFF;
+ padded[i++] = (length >> 5) & 0xFF;
+ padded[i++] = (length << 3) & 0xFF;
+ var w = new Uint32Array(64);
+ // for each 512 bit block
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 16; ++j) {
+ w[j] = (padded[i] << 24 | (padded[i + 1] << 16) |
+ (padded[i + 2] << 8) | (padded[i + 3]));
+ i += 4;
+ }
+
+ for (j = 16; j < 64; ++j) {
+ w[j] = littleSigmaPrime(w[j - 2]) + w[j - 7] +
+ littleSigma(w[j - 15]) + w[j - 16] | 0;
+ }
+ var a = h0, b = h1, c = h2, d = h3, e = h4,
+ f = h5, g = h6, h = h7, t1, t2;
+ for (j = 0; j < 64; ++j) {
+ t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];
+ t2 = sigma(a) + maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = (d + t1) | 0;
+ d = c;
+ c = b;
+ b = a;
+ a = (t1 + t2) | 0;
+ }
+ h0 = (h0 + a) | 0;
+ h1 = (h1 + b) | 0;
+ h2 = (h2 + c) | 0;
+ h3 = (h3 + d) | 0;
+ h4 = (h4 + e) | 0;
+ h5 = (h5 + f) | 0;
+ h6 = (h6 + g) | 0;
+ h7 = (h7 + h) | 0;
+ }
+ return new Uint8Array([
+ (h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF,
+ (h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF,
+ (h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF,
+ (h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF,
+ (h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF,
+ (h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF,
+ (h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF,
+ (h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF
+ ]);
+ }
+
return hash;
})();
+var calculateSHA512 = (function calculateSHA512Closure() {
+ function ch(result, x, y, z, tmp) {
+ result.assign(x);
+ result.and(y);
+ tmp.assign(x);
+ tmp.not();
+ tmp.and(z);
+ result.xor(tmp);
+ }
+
+ function maj(result, x, y, z, tmp) {
+ result.assign(x);
+ result.and(y);
+ tmp.assign(x);
+ tmp.and(z);
+ result.xor(tmp);
+ tmp.assign(y);
+ tmp.and(z);
+ result.xor(tmp);
+ }
+
+ function sigma(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(28);
+ tmp.assign(x);
+ tmp.rotateRight(34);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.rotateRight(39);
+ result.xor(tmp);
+ }
+
+ function sigmaPrime(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(14);
+ tmp.assign(x);
+ tmp.rotateRight(18);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.rotateRight(41);
+ result.xor(tmp);
+ }
+
+ function littleSigma(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(1);
+ tmp.assign(x);
+ tmp.rotateRight(8);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.shiftRight(7);
+ result.xor(tmp);
+ }
+
+ function littleSigmaPrime(result, x, tmp) {
+ result.assign(x);
+ result.rotateRight(19);
+ tmp.assign(x);
+ tmp.rotateRight(61);
+ result.xor(tmp);
+ tmp.assign(x);
+ tmp.shiftRight(6);
+ result.xor(tmp);
+ }
+
+ var k = [
+ new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd),
+ new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc),
+ new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019),
+ new Word64(0x923f82a4, 0xaf194f9b), new Word64(0xab1c5ed5, 0xda6d8118),
+ new Word64(0xd807aa98, 0xa3030242), new Word64(0x12835b01, 0x45706fbe),
+ new Word64(0x243185be, 0x4ee4b28c), new Word64(0x550c7dc3, 0xd5ffb4e2),
+ new Word64(0x72be5d74, 0xf27b896f), new Word64(0x80deb1fe, 0x3b1696b1),
+ new Word64(0x9bdc06a7, 0x25c71235), new Word64(0xc19bf174, 0xcf692694),
+ new Word64(0xe49b69c1, 0x9ef14ad2), new Word64(0xefbe4786, 0x384f25e3),
+ new Word64(0x0fc19dc6, 0x8b8cd5b5), new Word64(0x240ca1cc, 0x77ac9c65),
+ new Word64(0x2de92c6f, 0x592b0275), new Word64(0x4a7484aa, 0x6ea6e483),
+ new Word64(0x5cb0a9dc, 0xbd41fbd4), new Word64(0x76f988da, 0x831153b5),
+ new Word64(0x983e5152, 0xee66dfab), new Word64(0xa831c66d, 0x2db43210),
+ new Word64(0xb00327c8, 0x98fb213f), new Word64(0xbf597fc7, 0xbeef0ee4),
+ new Word64(0xc6e00bf3, 0x3da88fc2), new Word64(0xd5a79147, 0x930aa725),
+ new Word64(0x06ca6351, 0xe003826f), new Word64(0x14292967, 0x0a0e6e70),
+ new Word64(0x27b70a85, 0x46d22ffc), new Word64(0x2e1b2138, 0x5c26c926),
+ new Word64(0x4d2c6dfc, 0x5ac42aed), new Word64(0x53380d13, 0x9d95b3df),
+ new Word64(0x650a7354, 0x8baf63de), new Word64(0x766a0abb, 0x3c77b2a8),
+ new Word64(0x81c2c92e, 0x47edaee6), new Word64(0x92722c85, 0x1482353b),
+ new Word64(0xa2bfe8a1, 0x4cf10364), new Word64(0xa81a664b, 0xbc423001),
+ new Word64(0xc24b8b70, 0xd0f89791), new Word64(0xc76c51a3, 0x0654be30),
+ new Word64(0xd192e819, 0xd6ef5218), new Word64(0xd6990624, 0x5565a910),
+ new Word64(0xf40e3585, 0x5771202a), new Word64(0x106aa070, 0x32bbd1b8),
+ new Word64(0x19a4c116, 0xb8d2d0c8), new Word64(0x1e376c08, 0x5141ab53),
+ new Word64(0x2748774c, 0xdf8eeb99), new Word64(0x34b0bcb5, 0xe19b48a8),
+ new Word64(0x391c0cb3, 0xc5c95a63), new Word64(0x4ed8aa4a, 0xe3418acb),
+ new Word64(0x5b9cca4f, 0x7763e373), new Word64(0x682e6ff3, 0xd6b2b8a3),
+ new Word64(0x748f82ee, 0x5defb2fc), new Word64(0x78a5636f, 0x43172f60),
+ new Word64(0x84c87814, 0xa1f0ab72), new Word64(0x8cc70208, 0x1a6439ec),
+ new Word64(0x90befffa, 0x23631e28), new Word64(0xa4506ceb, 0xde82bde9),
+ new Word64(0xbef9a3f7, 0xb2c67915), new Word64(0xc67178f2, 0xe372532b),
+ new Word64(0xca273ece, 0xea26619c), new Word64(0xd186b8c7, 0x21c0c207),
+ new Word64(0xeada7dd6, 0xcde0eb1e), new Word64(0xf57d4f7f, 0xee6ed178),
+ new Word64(0x06f067aa, 0x72176fba), new Word64(0x0a637dc5, 0xa2c898a6),
+ new Word64(0x113f9804, 0xbef90dae), new Word64(0x1b710b35, 0x131c471b),
+ new Word64(0x28db77f5, 0x23047d84), new Word64(0x32caab7b, 0x40c72493),
+ new Word64(0x3c9ebe0a, 0x15c9bebc), new Word64(0x431d67c4, 0x9c100d4c),
+ new Word64(0x4cc5d4be, 0xcb3e42b6), new Word64(0x597f299c, 0xfc657e2a),
+ new Word64(0x5fcb6fab, 0x3ad6faec), new Word64(0x6c44198c, 0x4a475817)];
+
+ function hash(data, offset, length, mode384) {
+ mode384 = !!mode384;
+ // initial hash values
+ var h0, h1, h2, h3, h4, h5, h6, h7;
+ if (!mode384) {
+ h0 = new Word64(0x6a09e667, 0xf3bcc908);
+ h1 = new Word64(0xbb67ae85, 0x84caa73b);
+ h2 = new Word64(0x3c6ef372, 0xfe94f82b);
+ h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
+ h4 = new Word64(0x510e527f, 0xade682d1);
+ h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
+ h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
+ h7 = new Word64(0x5be0cd19, 0x137e2179);
+ }
+ else {
+ // SHA384 is exactly the same
+ // except with different starting values and a trimmed result
+ h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
+ h1 = new Word64(0x629a292a, 0x367cd507);
+ h2 = new Word64(0x9159015a, 0x3070dd17);
+ h3 = new Word64(0x152fecd8, 0xf70e5939);
+ h4 = new Word64(0x67332667, 0xffc00b31);
+ h5 = new Word64(0x8eb44a87, 0x68581511);
+ h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
+ h7 = new Word64(0x47b5481d, 0xbefa4fa4);
+ }
+
+ // pre-processing
+ var paddedLength = Math.ceil((length + 17) / 128) * 128;
+ var padded = new Uint8Array(paddedLength);
+ var i, j, n;
+ for (i = 0; i < length; ++i) {
+ padded[i] = data[offset++];
+ }
+ padded[i++] = 0x80;
+ n = paddedLength - 16;
+ while (i < n) {
+ padded[i++] = 0;
+ }
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = 0;
+ padded[i++] = (length >>> 29) & 0xFF;
+ padded[i++] = (length >> 21) & 0xFF;
+ padded[i++] = (length >> 13) & 0xFF;
+ padded[i++] = (length >> 5) & 0xFF;
+ padded[i++] = (length << 3) & 0xFF;
+
+ var w = new Array(80);
+ for (i = 0; i < 80; i++) {
+ w[i] = new Word64(0, 0);
+ }
+ var a = new Word64(0, 0), b = new Word64(0, 0), c = new Word64(0, 0);
+ var d = new Word64(0, 0), e = new Word64(0, 0), f = new Word64(0, 0);
+ var g = new Word64(0, 0), h = new Word64(0, 0);
+ var t1 = new Word64(0, 0), t2 = new Word64(0, 0);
+ var tmp1 = new Word64(0, 0), tmp2 = new Word64(0, 0), tmp3;
+
+ // for each 1024 bit block
+ for (i = 0; i < paddedLength;) {
+ for (j = 0; j < 16; ++j) {
+ w[j].high = (padded[i] << 24) | (padded[i + 1] << 16) |
+ (padded[i + 2] << 8) | (padded[i + 3]);
+ w[j].low = (padded[i + 4]) << 24 | (padded[i + 5]) << 16 |
+ (padded[i + 6]) << 8 | (padded[i + 7]);
+ i += 8;
+ }
+ for (j = 16; j < 80; ++j) {
+ tmp3 = w[j];
+ littleSigmaPrime(tmp3, w[j - 2], tmp2);
+ tmp3.add(w[j - 7]);
+ littleSigma(tmp1, w[j - 15], tmp2);
+ tmp3.add(tmp1);
+ tmp3.add(w[j - 16]);
+ }
+
+ a.assign(h0); b.assign(h1); c.assign(h2); d.assign(h3);
+ e.assign(h4); f.assign(h5); g.assign(h6); h.assign(h7);
+ for (j = 0; j < 80; ++j) {
+ t1.assign(h);
+ sigmaPrime(tmp1, e, tmp2);
+ t1.add(tmp1);
+ ch(tmp1, e, f, g, tmp2);
+ t1.add(tmp1);
+ t1.add(k[j]);
+ t1.add(w[j]);
+
+ sigma(t2, a, tmp2);
+ maj(tmp1, a, b, c, tmp2);
+ t2.add(tmp1);
+
+ tmp3 = h;
+ h = g;
+ g = f;
+ f = e;
+ d.add(t1);
+ e = d;
+ d = c;
+ c = b;
+ b = a;
+ tmp3.assign(t1);
+ tmp3.add(t2);
+ a = tmp3;
+ }
+ h0.add(a);
+ h1.add(b);
+ h2.add(c);
+ h3.add(d);
+ h4.add(e);
+ h5.add(f);
+ h6.add(g);
+ h7.add(h);
+ }
+
+ var result;
+ if (!mode384) {
+ result = new Uint8Array(64);
+ h0.copyTo(result,0);
+ h1.copyTo(result,8);
+ h2.copyTo(result,16);
+ h3.copyTo(result,24);
+ h4.copyTo(result,32);
+ h5.copyTo(result,40);
+ h6.copyTo(result,48);
+ h7.copyTo(result,56);
+ }
+ else {
+ result = new Uint8Array(48);
+ h0.copyTo(result,0);
+ h1.copyTo(result,8);
+ h2.copyTo(result,16);
+ h3.copyTo(result,24);
+ h4.copyTo(result,32);
+ h5.copyTo(result,40);
+ }
+ return result;
+ }
+
+ return hash;
+})();
+var calculateSHA384 = (function calculateSHA384Closure() {
+ function hash(data, offset, length) {
+ return calculateSHA512(data, offset, length, true);
+ }
+
+ return hash;
+})();
var NullCipher = (function NullCipherClosure() {
function NullCipher() {
}
@@ -14093,7 +8399,14 @@ var AES128Cipher = (function AES128CipherClosure() {
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d]);
-
+ var mixCol = new Uint8Array(256);
+ for (var i = 0; i < 256; i++) {
+ if (i < 128) {
+ mixCol[i] = i << 1;
+ } else {
+ mixCol[i] = (i << 1) ^ 0x1b;
+ }
+ }
var mix = new Uint32Array([
0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
@@ -14147,14 +8460,21 @@ var AES128Cipher = (function AES128CipherClosure() {
var t1 = result[j - 3], t2 = result[j - 2],
t3 = result[j - 1], t4 = result[j - 4];
// SubWord
- t1 = s[t1]; t2 = s[t2]; t3 = s[t3]; t4 = s[t4];
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
// Rcon
t1 = t1 ^ rcon[i];
for (var n = 0; n < 4; ++n) {
- result[j] = (t1 ^= result[j - 16]); j++;
- result[j] = (t2 ^= result[j - 16]); j++;
- result[j] = (t3 ^= result[j - 16]); j++;
- result[j] = (t4 ^= result[j - 16]); j++;
+ result[j] = (t1 ^= result[j - 16]);
+ j++;
+ result[j] = (t2 ^= result[j - 16]);
+ j++;
+ result[j] = (t3 ^= result[j - 16]);
+ j++;
+ result[j] = (t4 ^= result[j - 16]);
+ j++;
}
}
return result;
@@ -14166,28 +8486,43 @@ var AES128Cipher = (function AES128CipherClosure() {
var i, j, k;
var t, u, v;
// AddRoundKey
- for (j = 0, k = 160; j < 16; ++j, ++k)
+ for (j = 0, k = 160; j < 16; ++j, ++k) {
state[j] ^= key[k];
+ }
for (i = 9; i >= 1; --i) {
// InvShiftRows
- t = state[13]; state[13] = state[9]; state[9] = state[5];
- state[5] = state[1]; state[1] = t;
- t = state[14]; u = state[10]; state[14] = state[6];
- state[10] = state[2]; state[6] = t; state[2] = u;
- t = state[15]; u = state[11]; v = state[7]; state[15] = state[3];
- state[11] = t; state[7] = u; state[3] = v;
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
// InvSubBytes
- for (j = 0; j < 16; ++j)
+ for (j = 0; j < 16; ++j) {
state[j] = inv_s[state[j]];
+ }
// AddRoundKey
- for (j = 0, k = i * 16; j < 16; ++j, ++k)
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
state[j] ^= key[k];
+ }
// InvMixColumns
for (j = 0; j < 16; j += 4) {
var s0 = mix[state[j]], s1 = mix[state[j + 1]],
- s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
+ s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
- (s3 >>> 24) ^ (s3 << 8));
+ (s3 >>> 24) ^ (s3 << 8));
state[j] = (t >>> 24) & 0xFF;
state[j + 1] = (t >> 16) & 0xFF;
state[j + 2] = (t >> 8) & 0xFF;
@@ -14195,12 +8530,24 @@ var AES128Cipher = (function AES128CipherClosure() {
}
}
// InvShiftRows
- t = state[13]; state[13] = state[9]; state[9] = state[5];
- state[5] = state[1]; state[1] = t;
- t = state[14]; u = state[10]; state[14] = state[6];
- state[10] = state[2]; state[6] = t; state[2] = u;
- t = state[15]; u = state[11]; v = state[7]; state[15] = state[3];
- state[11] = t; state[7] = u; state[3] = v;
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
for (j = 0; j < 16; ++j) {
// InvSubBytes
state[j] = inv_s[state[j]];
@@ -14210,6 +8557,85 @@ var AES128Cipher = (function AES128CipherClosure() {
return state;
}
+ function encrypt128(input, key) {
+ var t, u, v, k;
+ var state = new Uint8Array(16);
+ state.set(input);
+ for (j = 0; j < 16; ++j) {
+ // AddRoundKey
+ state[j] ^= key[j];
+ }
+
+ for (i = 1; i < 10; i++) {
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //MixColumns
+ for (var j = 0; j < 16; j += 4) {
+ var s0 = state[j + 0], s1 = state[j + 1];
+ var s2 = state[j + 2], s3 = state[j + 3];
+ t = s0 ^ s1 ^ s2 ^ s3;
+ state[j + 0] ^= t ^ mixCol[s0 ^ s1];
+ state[j + 1] ^= t ^ mixCol[s1 ^ s2];
+ state[j + 2] ^= t ^ mixCol[s2 ^ s3];
+ state[j + 3] ^= t ^ mixCol[s3 ^ s0];
+ }
+ //AddRoundKey
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ }
+
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //AddRoundKey
+ for (j = 0, k = 160; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ return state;
+ }
+
function AES128Cipher(key) {
this.key = expandKey128(key);
this.buffer = new Uint8Array(16);
@@ -14223,13 +8649,15 @@ var AES128Cipher = (function AES128CipherClosure() {
for (i = 0; i < sourceLength; ++i) {
buffer[bufferLength] = data[i];
++bufferLength;
- if (bufferLength < 16)
+ if (bufferLength < 16) {
continue;
+ }
// buffer is full, decrypting
var plain = decrypt128(buffer, this.key);
// xor-ing the IV vector to get plain text
- for (j = 0; j < 16; ++j)
+ for (j = 0; j < 16; ++j) {
plain[j] ^= iv[j];
+ }
iv = buffer;
result.push(plain);
buffer = new Uint8Array(16);
@@ -14247,12 +8675,23 @@ var AES128Cipher = (function AES128CipherClosure() {
if (finalize) {
// undo a padding that is described in RFC 2898
var lastBlock = result[result.length - 1];
- outputLength -= lastBlock[15];
- result[result.length - 1] = lastBlock.subarray(0, 16 - lastBlock[15]);
+ var psLen = lastBlock[15];
+ if (psLen <= 16) {
+ for (i = 15, ii = 16 - psLen; i >= ii; --i) {
+ if (lastBlock[i] !== psLen) {
+ // Invalid padding, assume that the block has no padding.
+ psLen = 0;
+ break;
+ }
+ }
+ outputLength -= psLen;
+ result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
+ }
}
var output = new Uint8Array(outputLength);
- for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16)
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
output.set(result[i], j);
+ }
return output;
}
@@ -14261,8 +8700,9 @@ var AES128Cipher = (function AES128CipherClosure() {
var i, sourceLength = data.length;
var buffer = this.buffer, bufferLength = this.bufferPosition;
// waiting for IV values -- they are at the start of the stream
- for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength)
+ for (i = 0; bufferLength < 16 && i < sourceLength; ++i, ++bufferLength) {
buffer[bufferLength] = data[i];
+ }
if (bufferLength < 16) {
// need more data
this.bufferLength = bufferLength;
@@ -14274,21 +8714,707 @@ var AES128Cipher = (function AES128CipherClosure() {
// starting decryption
this.decryptBlock = decryptBlock2;
return this.decryptBlock(data.subarray(16), finalize);
+ },
+ encrypt: function AES128Cipher_encrypt(data, iv) {
+ var i, j, ii, sourceLength = data.length,
+ buffer = this.buffer, bufferLength = this.bufferPosition,
+ result = [];
+ if (!iv) {
+ iv = new Uint8Array(16);
+ }
+ for (i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ for (j = 0; j < 16; ++j) {
+ buffer[j] ^= iv[j];
+ }
+
+ // buffer is full, encrypting
+ var cipher = encrypt128(buffer, this.key);
+ iv = cipher;
+ result.push(cipher);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ // saving incomplete buffer
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array([]);
+ }
+ // combining plain text blocks into one
+ var outputLength = 16 * result.length;
+ var output = new Uint8Array(outputLength);
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
}
};
return AES128Cipher;
})();
+var AES256Cipher = (function AES256CipherClosure() {
+ var rcon = new Uint8Array([
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+ 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+ 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,
+ 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72,
+ 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
+ 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10,
+ 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e,
+ 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5,
+ 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
+ 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02,
+ 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
+ 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d,
+ 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
+ 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb,
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
+ 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
+ 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+ 0x74, 0xe8, 0xcb, 0x8d]);
+
+ var s = new Uint8Array([
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
+ 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
+ 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
+ 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
+ 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
+ 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
+ 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
+ 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
+ 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
+ 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
+ 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
+ 0xb0, 0x54, 0xbb, 0x16]);
+
+ var inv_s = new Uint8Array([
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
+ 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
+ 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
+ 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
+ 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
+ 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
+ 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
+ 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
+ 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
+ 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0c, 0x7d]);
+
+ var mixCol = new Uint8Array(256);
+ for (var i = 0; i < 256; i++) {
+ if (i < 128) {
+ mixCol[i] = i << 1;
+ } else {
+ mixCol[i] = (i << 1) ^ 0x1b;
+ }
+ }
+ var mix = new Uint32Array([
+ 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
+ 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
+ 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
+ 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381,
+ 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf,
+ 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66,
+ 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28,
+ 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012,
+ 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec,
+ 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e,
+ 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd,
+ 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7,
+ 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89,
+ 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b,
+ 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815,
+ 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f,
+ 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa,
+ 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8,
+ 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36,
+ 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c,
+ 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742,
+ 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea,
+ 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4,
+ 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e,
+ 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360,
+ 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502,
+ 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87,
+ 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd,
+ 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3,
+ 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621,
+ 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f,
+ 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55,
+ 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26,
+ 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844,
+ 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba,
+ 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480,
+ 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce,
+ 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67,
+ 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929,
+ 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713,
+ 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed,
+ 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f,
+ 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3]);
+
+ function expandKey256(cipherKey) {
+ var b = 240, result = new Uint8Array(b);
+ var r = 1;
+
+ result.set(cipherKey);
+ for (var j = 32, i = 1; j < b; ++i) {
+ if (j % 32 === 16) {
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ } else if (j % 32 === 0) {
+ // RotWord
+ var t1 = result[j - 3], t2 = result[j - 2],
+ t3 = result[j - 1], t4 = result[j - 4];
+ // SubWord
+ t1 = s[t1];
+ t2 = s[t2];
+ t3 = s[t3];
+ t4 = s[t4];
+ // Rcon
+ t1 = t1 ^ r;
+ if ((r <<= 1) >= 256) {
+ r = (r ^ 0x1b) & 0xFF;
+ }
+ }
+
+ for (var n = 0; n < 4; ++n) {
+ result[j] = (t1 ^= result[j - 32]);
+ j++;
+ result[j] = (t2 ^= result[j - 32]);
+ j++;
+ result[j] = (t3 ^= result[j - 32]);
+ j++;
+ result[j] = (t4 ^= result[j - 32]);
+ j++;
+ }
+ }
+ return result;
+ }
+
+ function decrypt256(input, key) {
+ var state = new Uint8Array(16);
+ state.set(input);
+ var i, j, k;
+ var t, u, v;
+ // AddRoundKey
+ for (j = 0, k = 224; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ for (i = 13; i >= 1; --i) {
+ // InvShiftRows
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
+ // InvSubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = inv_s[state[j]];
+ }
+ // AddRoundKey
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ // InvMixColumns
+ for (j = 0; j < 16; j += 4) {
+ var s0 = mix[state[j]], s1 = mix[state[j + 1]],
+ s2 = mix[state[j + 2]], s3 = mix[state[j + 3]];
+ t = (s0 ^ (s1 >>> 8) ^ (s1 << 24) ^ (s2 >>> 16) ^ (s2 << 16) ^
+ (s3 >>> 24) ^ (s3 << 8));
+ state[j] = (t >>> 24) & 0xFF;
+ state[j + 1] = (t >> 16) & 0xFF;
+ state[j + 2] = (t >> 8) & 0xFF;
+ state[j + 3] = t & 0xFF;
+ }
+ }
+ // InvShiftRows
+ t = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = t;
+ t = state[14];
+ u = state[10];
+ state[14] = state[6];
+ state[10] = state[2];
+ state[6] = t;
+ state[2] = u;
+ t = state[15];
+ u = state[11];
+ v = state[7];
+ state[15] = state[3];
+ state[11] = t;
+ state[7] = u;
+ state[3] = v;
+ for (j = 0; j < 16; ++j) {
+ // InvSubBytes
+ state[j] = inv_s[state[j]];
+ // AddRoundKey
+ state[j] ^= key[j];
+ }
+ return state;
+ }
+
+ function encrypt256(input, key) {
+ var t, u, v, k;
+ var state = new Uint8Array(16);
+ state.set(input);
+ for (j = 0; j < 16; ++j) {
+ // AddRoundKey
+ state[j] ^= key[j];
+ }
+
+ for (i = 1; i < 14; i++) {
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //MixColumns
+ for (var j = 0; j < 16; j += 4) {
+ var s0 = state[j + 0], s1 = state[j + 1];
+ var s2 = state[j + 2], s3 = state[j + 3];
+ t = s0 ^ s1 ^ s2 ^ s3;
+ state[j + 0] ^= t ^ mixCol[s0 ^ s1];
+ state[j + 1] ^= t ^ mixCol[s1 ^ s2];
+ state[j + 2] ^= t ^ mixCol[s2 ^ s3];
+ state[j + 3] ^= t ^ mixCol[s3 ^ s0];
+ }
+ //AddRoundKey
+ for (j = 0, k = i * 16; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+ }
+
+ //SubBytes
+ for (j = 0; j < 16; ++j) {
+ state[j] = s[state[j]];
+ }
+ //ShiftRows
+ v = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = v;
+ v = state[2];
+ u = state[6];
+ state[2] = state[10];
+ state[6] = state[14];
+ state[10] = v;
+ state[14] = u;
+ v = state[3];
+ u = state[7];
+ t = state[11];
+ state[3] = state[15];
+ state[7] = v;
+ state[11] = u;
+ state[15] = t;
+ //AddRoundKey
+ for (j = 0, k = 224; j < 16; ++j, ++k) {
+ state[j] ^= key[k];
+ }
+
+ return state;
+
+ }
+
+ function AES256Cipher(key) {
+ this.key = expandKey256(key);
+ this.buffer = new Uint8Array(16);
+ this.bufferPosition = 0;
+ }
+
+ function decryptBlock2(data, finalize) {
+ var i, j, ii, sourceLength = data.length,
+ buffer = this.buffer, bufferLength = this.bufferPosition,
+ result = [], iv = this.iv;
+
+ for (i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ // buffer is full, decrypting
+ var plain = decrypt256(buffer, this.key);
+ // xor-ing the IV vector to get plain text
+ for (j = 0; j < 16; ++j) {
+ plain[j] ^= iv[j];
+ }
+ iv = buffer;
+ result.push(plain);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ // saving incomplete buffer
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array([]);
+ }
+ // combining plain text blocks into one
+ var outputLength = 16 * result.length;
+ if (finalize) {
+ // undo a padding that is described in RFC 2898
+ var lastBlock = result[result.length - 1];
+ var psLen = lastBlock[15];
+ if (psLen <= 16) {
+ for (i = 15, ii = 16 - psLen; i >= ii; --i) {
+ if (lastBlock[i] !== psLen) {
+ // Invalid padding, assume that the block has no padding.
+ psLen = 0;
+ break;
+ }
+ }
+ outputLength -= psLen;
+ result[result.length - 1] = lastBlock.subarray(0, 16 - psLen);
+ }
+ }
+ var output = new Uint8Array(outputLength);
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
+
+ }
+
+ AES256Cipher.prototype = {
+ decryptBlock: function AES256Cipher_decryptBlock(data, finalize, iv) {
+ var i, sourceLength = data.length;
+ var buffer = this.buffer, bufferLength = this.bufferPosition;
+ // if not supplied an IV wait for IV values
+ // they are at the start of the stream
+ if (iv) {
+ this.iv = iv;
+ } else {
+ for (i = 0; bufferLength < 16 &&
+ i < sourceLength; ++i, ++bufferLength) {
+ buffer[bufferLength] = data[i];
+ }
+ if (bufferLength < 16) {
+ //need more data
+ this.bufferLength = bufferLength;
+ return new Uint8Array([]);
+ }
+ this.iv = buffer;
+ data = data.subarray(16);
+ }
+ this.buffer = new Uint8Array(16);
+ this.bufferLength = 0;
+ // starting decryption
+ this.decryptBlock = decryptBlock2;
+ return this.decryptBlock(data, finalize);
+ },
+ encrypt: function AES256Cipher_encrypt(data, iv) {
+ var i, j, ii, sourceLength = data.length,
+ buffer = this.buffer, bufferLength = this.bufferPosition,
+ result = [];
+ if (!iv) {
+ iv = new Uint8Array(16);
+ }
+ for (i = 0; i < sourceLength; ++i) {
+ buffer[bufferLength] = data[i];
+ ++bufferLength;
+ if (bufferLength < 16) {
+ continue;
+ }
+ for (j = 0; j < 16; ++j) {
+ buffer[j] ^= iv[j];
+ }
+
+ // buffer is full, encrypting
+ var cipher = encrypt256(buffer, this.key);
+ this.iv = cipher;
+ result.push(cipher);
+ buffer = new Uint8Array(16);
+ bufferLength = 0;
+ }
+ // saving incomplete buffer
+ this.buffer = buffer;
+ this.bufferLength = bufferLength;
+ this.iv = iv;
+ if (result.length === 0) {
+ return new Uint8Array([]);
+ }
+ // combining plain text blocks into one
+ var outputLength = 16 * result.length;
+ var output = new Uint8Array(outputLength);
+ for (i = 0, j = 0, ii = result.length; i < ii; ++i, j += 16) {
+ output.set(result[i], j);
+ }
+ return output;
+ }
+ };
+
+ return AES256Cipher;
+})();
+
+var PDF17 = (function PDF17Closure() {
+
+ function compareByteArrays(array1, array2) {
+ if (array1.length !== array2.length) {
+ return false;
+ }
+ for (var i = 0; i < array1.length; i++) {
+ if (array1[i] !== array2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function PDF17() {
+ }
+
+ PDF17.prototype = {
+ checkOwnerPassword: function PDF17_checkOwnerPassword(password,
+ ownerValidationSalt,
+ userBytes,
+ ownerPassword) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerValidationSalt, password.length);
+ hashData.set(userBytes, password.length + ownerValidationSalt.length);
+ var result = calculateSHA256(hashData, 0, hashData.length);
+ return compareByteArrays(result, ownerPassword);
+ },
+ checkUserPassword: function PDF17_checkUserPassword(password,
+ userValidationSalt,
+ userPassword) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userValidationSalt, password.length);
+ var result = calculateSHA256(hashData, 0, hashData.length);
+ return compareByteArrays(result, userPassword);
+ },
+ getOwnerKey: function PDF17_getOwnerKey(password, ownerKeySalt, userBytes,
+ ownerEncryption) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerKeySalt, password.length);
+ hashData.set(userBytes, password.length + ownerKeySalt.length);
+ var key = calculateSHA256(hashData, 0, hashData.length);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(ownerEncryption,
+ false,
+ new Uint8Array(16));
+
+ },
+ getUserKey: function PDF17_getUserKey(password, userKeySalt,
+ userEncryption) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userKeySalt, password.length);
+ //key is the decryption key for the UE string
+ var key = calculateSHA256(hashData, 0, hashData.length);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(userEncryption,
+ false,
+ new Uint8Array(16));
+ }
+ };
+ return PDF17;
+})();
+
+var PDF20 = (function PDF20Closure() {
+
+ function concatArrays(array1, array2) {
+ var t = new Uint8Array(array1.length + array2.length);
+ t.set(array1, 0);
+ t.set(array2, array1.length);
+ return t;
+ }
+
+ function calculatePDF20Hash(password, input, userBytes) {
+ //This refers to Algorithm 2.B as defined in ISO 32000-2
+ var k = calculateSHA256(input, 0, input.length).subarray(0, 32);
+ var e = [0];
+ var i = 0;
+ while (i < 64 || e[e.length - 1] > i - 32) {
+ var arrayLength = password.length + k.length + userBytes.length;
+
+ var k1 = new Uint8Array(arrayLength * 64);
+ var array = concatArrays(password, k);
+ array = concatArrays(array, userBytes);
+ for (var j = 0, pos = 0; j < 64; j++, pos += arrayLength) {
+ k1.set(array, pos);
+ }
+ //AES128 CBC NO PADDING with
+ //first 16 bytes of k as the key and the second 16 as the iv.
+ var cipher = new AES128Cipher(k.subarray(0, 16));
+ e = cipher.encrypt(k1, k.subarray(16, 32));
+ //Now we have to take the first 16 bytes of an unsigned
+ //big endian integer... and compute the remainder
+ //modulo 3.... That is a fairly large number and
+ //JavaScript isn't going to handle that well...
+ //So we're using a trick that allows us to perform
+ //modulo math byte by byte
+ var remainder = 0;
+ for (var z = 0; z < 16; z++) {
+ remainder *= (256 % 3);
+ remainder %= 3;
+ remainder += ((e[z] >>> 0) % 3);
+ remainder %= 3;
+ }
+ if (remainder === 0) {
+ k = calculateSHA256(e, 0, e.length);
+ }
+ else if (remainder === 1) {
+ k = calculateSHA384(e, 0, e.length);
+ }
+ else if (remainder === 2) {
+ k = calculateSHA512(e, 0, e.length);
+ }
+ i++;
+ }
+ return k.subarray(0, 32);
+ }
+
+ function PDF20() {
+ }
+
+ function compareByteArrays(array1, array2) {
+ if (array1.length !== array2.length) {
+ return false;
+ }
+ for (var i = 0; i < array1.length; i++) {
+ if (array1[i] !== array2[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ PDF20.prototype = {
+ hash: function PDF20_hash(password, concatBytes, userBytes) {
+ return calculatePDF20Hash(password, concatBytes, userBytes);
+ },
+ checkOwnerPassword: function PDF20_checkOwnerPassword(password,
+ ownerValidationSalt,
+ userBytes,
+ ownerPassword) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerValidationSalt, password.length);
+ hashData.set(userBytes, password.length + ownerValidationSalt.length);
+ var result = calculatePDF20Hash(password, hashData, userBytes);
+ return compareByteArrays(result, ownerPassword);
+ },
+ checkUserPassword: function PDF20_checkUserPassword(password,
+ userValidationSalt,
+ userPassword) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userValidationSalt, password.length);
+ var result = calculatePDF20Hash(password, hashData, []);
+ return compareByteArrays(result, userPassword);
+ },
+ getOwnerKey: function PDF20_getOwnerKey(password, ownerKeySalt, userBytes,
+ ownerEncryption) {
+ var hashData = new Uint8Array(password.length + 56);
+ hashData.set(password, 0);
+ hashData.set(ownerKeySalt, password.length);
+ hashData.set(userBytes, password.length + ownerKeySalt.length);
+ var key = calculatePDF20Hash(password, hashData, userBytes);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(ownerEncryption,
+ false,
+ new Uint8Array(16));
+
+ },
+ getUserKey: function PDF20_getUserKey(password, userKeySalt,
+ userEncryption) {
+ var hashData = new Uint8Array(password.length + 8);
+ hashData.set(password, 0);
+ hashData.set(userKeySalt, password.length);
+ //key is the decryption key for the UE string
+ var key = calculatePDF20Hash(password, hashData, []);
+ var cipher = new AES256Cipher(key);
+ return cipher.decryptBlock(userEncryption,
+ false,
+ new Uint8Array(16));
+ }
+ };
+ return PDF20;
+})();
+
var CipherTransform = (function CipherTransformClosure() {
function CipherTransform(stringCipherConstructor, streamCipherConstructor) {
this.stringCipherConstructor = stringCipherConstructor;
this.streamCipherConstructor = streamCipherConstructor;
}
+
CipherTransform.prototype = {
- createStream: function CipherTransform_createStream(stream) {
+ createStream: function CipherTransform_createStream(stream, length) {
var cipher = new this.streamCipherConstructor();
- return new DecryptStream(stream,
+ return new DecryptStream(stream, length,
function cipherTransformDecryptStream(data, finalize) {
return cipher.decryptBlock(data, finalize);
}
@@ -14311,28 +9437,63 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]);
+ function createEncryptionKey20(revision, password, ownerPassword,
+ ownerValidationSalt, ownerKeySalt, uBytes,
+ userPassword, userValidationSalt, userKeySalt,
+ ownerEncryption, userEncryption, perms) {
+ if (password) {
+ var passwordLength = Math.min(127, password.length);
+ password = password.subarray(0, passwordLength);
+ } else {
+ password = [];
+ }
+ var pdfAlgorithm;
+ if (revision === 6) {
+ pdfAlgorithm = new PDF20();
+ } else {
+ pdfAlgorithm = new PDF17();
+ }
+
+ if (pdfAlgorithm) {
+ if (pdfAlgorithm.checkUserPassword(password, userValidationSalt,
+ userPassword)) {
+ return pdfAlgorithm.getUserKey(password, userKeySalt, userEncryption);
+ } else if (pdfAlgorithm.checkOwnerPassword(password, ownerValidationSalt,
+ uBytes,
+ ownerPassword)) {
+ return pdfAlgorithm.getOwnerKey(password, ownerKeySalt, uBytes,
+ ownerEncryption);
+ }
+ }
+
+ return null;
+ }
+
function prepareKeyData(fileId, password, ownerPassword, userPassword,
flags, revision, keyLength, encryptMetadata) {
var hashDataSize = 40 + ownerPassword.length + fileId.length;
var hashData = new Uint8Array(hashDataSize), i = 0, j, n;
if (password) {
n = Math.min(32, password.length);
- for (; i < n; ++i)
+ for (; i < n; ++i) {
hashData[i] = password[i];
+ }
}
j = 0;
while (i < 32) {
hashData[i++] = defaultPasswordBytes[j++];
}
// as now the padded password in the hashData[0..i]
- for (j = 0, n = ownerPassword.length; j < n; ++j)
+ for (j = 0, n = ownerPassword.length; j < n; ++j) {
hashData[i++] = ownerPassword[j];
+ }
hashData[i++] = flags & 0xFF;
hashData[i++] = (flags >> 8) & 0xFF;
hashData[i++] = (flags >> 16) & 0xFF;
hashData[i++] = (flags >>> 24) & 0xFF;
- for (j = 0, n = fileId.length; j < n; ++j)
+ for (j = 0, n = fileId.length; j < n; ++j) {
hashData[i++] = fileId[j];
+ }
if (revision >= 4 && !encryptMetadata) {
hashData[i++] = 0xFF;
hashData[i++] = 0xFF;
@@ -14343,46 +9504,53 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
var keyLengthInBytes = keyLength >> 3;
if (revision >= 3) {
for (j = 0; j < 50; ++j) {
- hash = calculateMD5(hash, 0, keyLengthInBytes);
+ hash = calculateMD5(hash, 0, keyLengthInBytes);
}
}
var encryptionKey = hash.subarray(0, keyLengthInBytes);
var cipher, checkData;
if (revision >= 3) {
- for (i = 0; i < 32; ++i)
+ for (i = 0; i < 32; ++i) {
hashData[i] = defaultPasswordBytes[i];
- for (j = 0, n = fileId.length; j < n; ++j)
+ }
+ for (j = 0, n = fileId.length; j < n; ++j) {
hashData[i++] = fileId[j];
+ }
cipher = new ARCFourCipher(encryptionKey);
- var checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
+ checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
n = encryptionKey.length;
var derivedKey = new Uint8Array(n), k;
for (j = 1; j <= 19; ++j) {
- for (k = 0; k < n; ++k)
+ for (k = 0; k < n; ++k) {
derivedKey[k] = encryptionKey[k] ^ j;
+ }
cipher = new ARCFourCipher(derivedKey);
checkData = cipher.encryptBlock(checkData);
}
for (j = 0, n = checkData.length; j < n; ++j) {
- if (userPassword[j] != checkData[j])
+ if (userPassword[j] !== checkData[j]) {
return null;
+ }
}
} else {
cipher = new ARCFourCipher(encryptionKey);
checkData = cipher.encryptBlock(defaultPasswordBytes);
for (j = 0, n = checkData.length; j < n; ++j) {
- if (userPassword[j] != checkData[j])
+ if (userPassword[j] !== checkData[j]) {
return null;
+ }
}
}
return encryptionKey;
}
+
function decodeUserPassword(password, ownerPassword, revision, keyLength) {
var hashData = new Uint8Array(32), i = 0, j, n;
n = Math.min(32, password.length);
- for (; i < n; ++i)
+ for (; i < n; ++i) {
hashData[i] = password[i];
+ }
j = 0;
while (i < 32) {
hashData[i++] = defaultPasswordBytes[j++];
@@ -14391,7 +9559,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
var keyLengthInBytes = keyLength >> 3;
if (revision >= 3) {
for (j = 0; j < 50; ++j) {
- hash = calculateMD5(hash, 0, hash.length);
+ hash = calculateMD5(hash, 0, hash.length);
}
}
@@ -14400,8 +9568,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
userPassword = ownerPassword;
var derivedKey = new Uint8Array(keyLengthInBytes), k;
for (j = 19; j >= 0; j--) {
- for (k = 0; k < keyLengthInBytes; ++k)
+ for (k = 0; k < keyLengthInBytes; ++k) {
derivedKey[k] = hash[k] ^ j;
+ }
cipher = new ARCFourCipher(derivedKey);
userPassword = cipher.encryptBlock(userPassword);
}
@@ -14412,39 +9581,66 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
return userPassword;
}
- var identityName = new Name('Identity');
+ var identityName = Name.get('Identity');
function CipherTransformFactory(dict, fileId, password) {
var filter = dict.get('Filter');
- if (!isName(filter) || filter.name != 'Standard')
+ if (!isName(filter) || filter.name !== 'Standard') {
error('unknown encryption method');
+ }
this.dict = dict;
var algorithm = dict.get('V');
if (!isInt(algorithm) ||
- (algorithm != 1 && algorithm != 2 && algorithm != 4))
+ (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 &&
+ algorithm !== 5)) {
error('unsupported encryption algorithm');
+ }
this.algorithm = algorithm;
var keyLength = dict.get('Length') || 40;
if (!isInt(keyLength) ||
- keyLength < 40 || (keyLength % 8) !== 0)
+ keyLength < 40 || (keyLength % 8) !== 0) {
error('invalid key length');
+ }
+
// prepare keys
var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32);
var userPassword = stringToBytes(dict.get('U')).subarray(0, 32);
var flags = dict.get('P');
var revision = dict.get('R');
- var encryptMetadata = algorithm == 4 && // meaningful when V is 4
- dict.get('EncryptMetadata') !== false; // makes true as default value
+ // meaningful when V is 4 or 5
+ var encryptMetadata = ((algorithm === 4 || algorithm === 5) &&
+ dict.get('EncryptMetadata') !== false);
this.encryptMetadata = encryptMetadata;
var fileIdBytes = stringToBytes(fileId);
var passwordBytes;
- if (password)
+ if (password) {
passwordBytes = stringToBytes(password);
+ }
- var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
- ownerPassword, userPassword, flags,
- revision, keyLength, encryptMetadata);
+ var encryptionKey;
+ if (algorithm !== 5) {
+ encryptionKey = prepareKeyData(fileIdBytes, passwordBytes,
+ ownerPassword, userPassword, flags,
+ revision, keyLength, encryptMetadata);
+ }
+ else {
+ var ownerValidationSalt = stringToBytes(dict.get('O')).subarray(32, 40);
+ var ownerKeySalt = stringToBytes(dict.get('O')).subarray(40, 48);
+ var uBytes = stringToBytes(dict.get('U')).subarray(0, 48);
+ var userValidationSalt = stringToBytes(dict.get('U')).subarray(32, 40);
+ var userKeySalt = stringToBytes(dict.get('U')).subarray(40, 48);
+ var ownerEncryption = stringToBytes(dict.get('OE'));
+ var userEncryption = stringToBytes(dict.get('UE'));
+ var perms = stringToBytes(dict.get('Perms'));
+ encryptionKey =
+ createEncryptionKey20(revision, passwordBytes,
+ ownerPassword, ownerValidationSalt,
+ ownerKeySalt, uBytes,
+ userPassword, userValidationSalt,
+ userKeySalt, ownerEncryption,
+ userEncryption, perms);
+ }
if (!encryptionKey && !password) {
throw new PasswordException('No password given',
PasswordResponses.NEED_PASSWORD);
@@ -14457,13 +9653,14 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
revision, keyLength, encryptMetadata);
}
- if (!encryptionKey)
+ if (!encryptionKey) {
throw new PasswordException('Incorrect Password',
PasswordResponses.INCORRECT_PASSWORD);
+ }
this.encryptionKey = encryptionKey;
- if (algorithm == 4) {
+ if (algorithm >= 4) {
this.cf = dict.get('CF');
this.stmf = dict.get('StmF') || identityName;
this.strf = dict.get('StrF') || identityName;
@@ -14473,8 +9670,9 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
function buildObjectKey(num, gen, encryptionKey, isAes) {
var key = new Uint8Array(encryptionKey.length + 9), i, n;
- for (i = 0, n = encryptionKey.length; i < n; ++i)
+ for (i = 0, n = encryptionKey.length; i < n; ++i) {
key[i] = encryptionKey[i];
+ }
key[i++] = num & 0xFF;
key[i++] = (num >> 8) & 0xFF;
key[i++] = (num >> 16) & 0xFF;
@@ -14493,23 +9691,27 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
function buildCipherConstructor(cf, name, num, gen, key) {
var cryptFilter = cf.get(name.name);
var cfm;
- if (cryptFilter !== null && cryptFilter !== undefined)
+ if (cryptFilter !== null && cryptFilter !== undefined) {
cfm = cryptFilter.get('CFM');
- if (!cfm || cfm.name == 'None') {
+ }
+ if (!cfm || cfm.name === 'None') {
return function cipherTransformFactoryBuildCipherConstructorNone() {
return new NullCipher();
};
}
- if ('V2' == cfm.name) {
+ if ('V2' === cfm.name) {
return function cipherTransformFactoryBuildCipherConstructorV2() {
- return new ARCFourCipher(
- buildObjectKey(num, gen, key, false));
+ return new ARCFourCipher(buildObjectKey(num, gen, key, false));
};
}
- if ('AESV2' == cfm.name) {
+ if ('AESV2' === cfm.name) {
return function cipherTransformFactoryBuildCipherConstructorAESV2() {
- return new AES128Cipher(
- buildObjectKey(num, gen, key, true));
+ return new AES128Cipher(buildObjectKey(num, gen, key, true));
+ };
+ }
+ if ('AESV3' === cfm.name) {
+ return function cipherTransformFactoryBuildCipherConstructorAESV3() {
+ return new AES256Cipher(key);
};
}
error('Unknown crypto method');
@@ -14518,12 +9720,12 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
CipherTransformFactory.prototype = {
createCipherTransform:
function CipherTransformFactory_createCipherTransform(num, gen) {
- if (this.algorithm == 4) {
+ if (this.algorithm === 4 || this.algorithm === 5) {
return new CipherTransform(
buildCipherConstructor(this.cf, this.stmf,
- num, gen, this.encryptionKey),
+ num, gen, this.encryptionKey),
buildCipherConstructor(this.cf, this.strf,
- num, gen, this.encryptionKey));
+ num, gen, this.encryptionKey));
}
// algorithms 1 and 2
var key = buildObjectKey(num, gen, this.encryptionKey, false);
@@ -14537,14 +9739,785 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
return CipherTransformFactory;
})();
+var PatternType = {
+ FUNCTION_BASED: 1,
+ AXIAL: 2,
+ RADIAL: 3,
+ FREE_FORM_MESH: 4,
+ LATTICE_FORM_MESH: 5,
+ COONS_PATCH_MESH: 6,
+ TENSOR_PATCH_MESH: 7
+};
+
+var Pattern = (function PatternClosure() {
+ // Constructor should define this.getPattern
+ function Pattern() {
+ error('should not call Pattern constructor');
+ }
+
+ Pattern.prototype = {
+ // Input: current Canvas context
+ // Output: the appropriate fillStyle or strokeStyle
+ getPattern: function Pattern_getPattern(ctx) {
+ error('Should not call Pattern.getStyle: ' + ctx);
+ }
+ };
+
+ Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
+ res) {
+
+ var dict = isStream(shading) ? shading.dict : shading;
+ var type = dict.get('ShadingType');
+
+ switch (type) {
+ case PatternType.AXIAL:
+ case PatternType.RADIAL:
+ // Both radial and axial shadings are handled by RadialAxial shading.
+ return new Shadings.RadialAxial(dict, matrix, xref, res);
+ case PatternType.FREE_FORM_MESH:
+ case PatternType.LATTICE_FORM_MESH:
+ case PatternType.COONS_PATCH_MESH:
+ case PatternType.TENSOR_PATCH_MESH:
+ return new Shadings.Mesh(shading, matrix, xref, res);
+ default:
+ UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
+ return new Shadings.Dummy();
+ }
+ };
+ return Pattern;
+})();
+
+var Shadings = {};
+
+// A small number to offset the first/last color stops so we can insert ones to
+// support extend. Number.MIN_VALUE appears to be too small and breaks the
+// extend. 1e-7 works in FF but chrome seems to use an even smaller sized number
+// internally so we have to go bigger.
+Shadings.SMALL_NUMBER = 1e-2;
+
+// Radial and axial shading have very similar implementations
+// If needed, the implementations can be broken into two classes
+Shadings.RadialAxial = (function RadialAxialClosure() {
+ function RadialAxial(dict, matrix, xref, res) {
+ this.matrix = matrix;
+ this.coordsArr = dict.get('Coords');
+ this.shadingType = dict.get('ShadingType');
+ this.type = 'Pattern';
+ var cs = dict.get('ColorSpace', 'CS');
+ cs = ColorSpace.parse(cs, xref, res);
+ this.cs = cs;
+
+ var t0 = 0.0, t1 = 1.0;
+ if (dict.has('Domain')) {
+ var domainArr = dict.get('Domain');
+ t0 = domainArr[0];
+ t1 = domainArr[1];
+ }
+
+ var extendStart = false, extendEnd = false;
+ if (dict.has('Extend')) {
+ var extendArr = dict.get('Extend');
+ extendStart = extendArr[0];
+ extendEnd = extendArr[1];
+ }
+
+ if (this.shadingType === PatternType.RADIAL &&
+ (!extendStart || !extendEnd)) {
+ // Radial gradient only currently works if either circle is fully within
+ // the other circle.
+ var x1 = this.coordsArr[0];
+ var y1 = this.coordsArr[1];
+ var r1 = this.coordsArr[2];
+ var x2 = this.coordsArr[3];
+ var y2 = this.coordsArr[4];
+ var r2 = this.coordsArr[5];
+ var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
+ if (r1 <= r2 + distance &&
+ r2 <= r1 + distance) {
+ warn('Unsupported radial gradient.');
+ }
+ }
+
+ this.extendStart = extendStart;
+ this.extendEnd = extendEnd;
+
+ var fnObj = dict.get('Function');
+ var fn = PDFFunction.parseArray(xref, fnObj);
+
+ // 10 samples seems good enough for now, but probably won't work
+ // if there are sharp color changes. Ideally, we would implement
+ // the spec faithfully and add lossless optimizations.
+ var diff = t1 - t0;
+ var step = diff / 10;
+
+ var colorStops = this.colorStops = [];
+
+ // Protect against bad domains so we don't end up in an infinte loop below.
+ if (t0 >= t1 || step <= 0) {
+ // Acrobat doesn't seem to handle these cases so we'll ignore for
+ // now.
+ info('Bad shading domain.');
+ return;
+ }
+
+ var color = new Float32Array(cs.numComps), ratio = new Float32Array(1);
+ var rgbColor;
+ for (var i = t0; i <= t1; i += step) {
+ ratio[0] = i;
+ fn(ratio, 0, color, 0);
+ rgbColor = cs.getRgb(color, 0);
+ var cssColor = Util.makeCssRgb(rgbColor);
+ colorStops.push([(i - t0) / diff, cssColor]);
+ }
+
+ var background = 'transparent';
+ if (dict.has('Background')) {
+ rgbColor = cs.getRgb(dict.get('Background'), 0);
+ background = Util.makeCssRgb(rgbColor);
+ }
+
+ if (!extendStart) {
+ // Insert a color stop at the front and offset the first real color stop
+ // so it doesn't conflict with the one we insert.
+ colorStops.unshift([0, background]);
+ colorStops[1][0] += Shadings.SMALL_NUMBER;
+ }
+ if (!extendEnd) {
+ // Same idea as above in extendStart but for the end.
+ colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
+ colorStops.push([1, background]);
+ }
+
+ this.colorStops = colorStops;
+ }
+
+ RadialAxial.prototype = {
+ getIR: function RadialAxial_getIR() {
+ var coordsArr = this.coordsArr;
+ var shadingType = this.shadingType;
+ var type, p0, p1, r0, r1;
+ if (shadingType === PatternType.AXIAL) {
+ p0 = [coordsArr[0], coordsArr[1]];
+ p1 = [coordsArr[2], coordsArr[3]];
+ r0 = null;
+ r1 = null;
+ type = 'axial';
+ } else if (shadingType === PatternType.RADIAL) {
+ p0 = [coordsArr[0], coordsArr[1]];
+ p1 = [coordsArr[3], coordsArr[4]];
+ r0 = coordsArr[2];
+ r1 = coordsArr[5];
+ type = 'radial';
+ } else {
+ error('getPattern type unknown: ' + shadingType);
+ }
+
+ var matrix = this.matrix;
+ if (matrix) {
+ p0 = Util.applyTransform(p0, matrix);
+ p1 = Util.applyTransform(p1, matrix);
+ }
+
+ return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
+ }
+ };
+
+ return RadialAxial;
+})();
+
+// All mesh shading. For now, they will be presented as set of the triangles
+// to be drawn on the canvas and rgb color for each vertex.
+Shadings.Mesh = (function MeshClosure() {
+ function MeshStreamReader(stream, context) {
+ this.stream = stream;
+ this.context = context;
+ this.buffer = 0;
+ this.bufferLength = 0;
+
+ var numComps = context.numComps;
+ this.tmpCompsBuf = new Float32Array(numComps);
+ var csNumComps = context.colorSpace;
+ this.tmpCsCompsBuf = context.colorFn ? new Float32Array(csNumComps) :
+ this.tmpCompsBuf;
+ }
+ MeshStreamReader.prototype = {
+ get hasData() {
+ if (this.stream.end) {
+ return this.stream.pos < this.stream.end;
+ }
+ if (this.bufferLength > 0) {
+ return true;
+ }
+ var nextByte = this.stream.getByte();
+ if (nextByte < 0) {
+ return false;
+ }
+ this.buffer = nextByte;
+ this.bufferLength = 8;
+ return true;
+ },
+ readBits: function MeshStreamReader_readBits(n) {
+ var buffer = this.buffer;
+ var bufferLength = this.bufferLength;
+ if (n === 32) {
+ if (bufferLength === 0) {
+ return ((this.stream.getByte() << 24) |
+ (this.stream.getByte() << 16) | (this.stream.getByte() << 8) |
+ this.stream.getByte()) >>> 0;
+ }
+ buffer = (buffer << 24) | (this.stream.getByte() << 16) |
+ (this.stream.getByte() << 8) | this.stream.getByte();
+ var nextByte = this.stream.getByte();
+ this.buffer = nextByte & ((1 << bufferLength) - 1);
+ return ((buffer << (8 - bufferLength)) |
+ ((nextByte & 0xFF) >> bufferLength)) >>> 0;
+ }
+ if (n === 8 && bufferLength === 0) {
+ return this.stream.getByte();
+ }
+ while (bufferLength < n) {
+ buffer = (buffer << 8) | this.stream.getByte();
+ bufferLength += 8;
+ }
+ bufferLength -= n;
+ this.bufferLength = bufferLength;
+ this.buffer = buffer & ((1 << bufferLength) - 1);
+ return buffer >> bufferLength;
+ },
+ align: function MeshStreamReader_align() {
+ this.buffer = 0;
+ this.bufferLength = 0;
+ },
+ readFlag: function MeshStreamReader_readFlag() {
+ return this.readBits(this.context.bitsPerFlag);
+ },
+ readCoordinate: function MeshStreamReader_readCoordinate() {
+ var bitsPerCoordinate = this.context.bitsPerCoordinate;
+ var xi = this.readBits(bitsPerCoordinate);
+ var yi = this.readBits(bitsPerCoordinate);
+ var decode = this.context.decode;
+ var scale = bitsPerCoordinate < 32 ? 1 / ((1 << bitsPerCoordinate) - 1) :
+ 2.3283064365386963e-10; // 2 ^ -32
+ return [
+ xi * scale * (decode[1] - decode[0]) + decode[0],
+ yi * scale * (decode[3] - decode[2]) + decode[2]
+ ];
+ },
+ readComponents: function MeshStreamReader_readComponents() {
+ var numComps = this.context.numComps;
+ var bitsPerComponent = this.context.bitsPerComponent;
+ var scale = bitsPerComponent < 32 ? 1 / ((1 << bitsPerComponent) - 1) :
+ 2.3283064365386963e-10; // 2 ^ -32
+ var decode = this.context.decode;
+ var components = this.tmpCompsBuf;
+ for (var i = 0, j = 4; i < numComps; i++, j += 2) {
+ var ci = this.readBits(bitsPerComponent);
+ components[i] = ci * scale * (decode[j + 1] - decode[j]) + decode[j];
+ }
+ var color = this.tmpCsCompsBuf;
+ if (this.context.colorFn) {
+ this.context.colorFn(components, 0, color, 0);
+ }
+ return this.context.colorSpace.getRgb(color, 0);
+ }
+ };
+
+ function decodeType4Shading(mesh, reader) {
+ var coords = mesh.coords;
+ var colors = mesh.colors;
+ var operators = [];
+ var ps = []; // not maintaining cs since that will match ps
+ var verticesLeft = 0; // assuming we have all data to start a new triangle
+ while (reader.hasData) {
+ var f = reader.readFlag();
+ var coord = reader.readCoordinate();
+ var color = reader.readComponents();
+ if (verticesLeft === 0) { // ignoring flags if we started a triangle
+ assert(0 <= f && f <= 2, 'Unknown type4 flag');
+ switch (f) {
+ case 0:
+ verticesLeft = 3;
+ break;
+ case 1:
+ ps.push(ps[ps.length - 2], ps[ps.length - 1]);
+ verticesLeft = 1;
+ break;
+ case 2:
+ ps.push(ps[ps.length - 3], ps[ps.length - 1]);
+ verticesLeft = 1;
+ break;
+ }
+ operators.push(f);
+ }
+ ps.push(coords.length);
+ coords.push(coord);
+ colors.push(color);
+ verticesLeft--;
+
+ reader.align();
+ }
+
+ var psPacked = new Int32Array(ps);
+
+ mesh.figures.push({
+ type: 'triangles',
+ coords: psPacked,
+ colors: psPacked
+ });
+ }
+
+ function decodeType5Shading(mesh, reader, verticesPerRow) {
+ var coords = mesh.coords;
+ var colors = mesh.colors;
+ var ps = []; // not maintaining cs since that will match ps
+ while (reader.hasData) {
+ var coord = reader.readCoordinate();
+ var color = reader.readComponents();
+ ps.push(coords.length);
+ coords.push(coord);
+ colors.push(color);
+ }
+
+ var psPacked = new Int32Array(ps);
+
+ mesh.figures.push({
+ type: 'lattice',
+ coords: psPacked,
+ colors: psPacked,
+ verticesPerRow: verticesPerRow
+ });
+ }
+
+ var MIN_SPLIT_PATCH_CHUNKS_AMOUNT = 3;
+ var MAX_SPLIT_PATCH_CHUNKS_AMOUNT = 20;
+
+ var TRIANGLE_DENSITY = 20; // count of triangles per entire mesh bounds
+
+ var getB = (function getBClosure() {
+ function buildB(count) {
+ var lut = [];
+ for (var i = 0; i <= count; i++) {
+ var t = i / count, t_ = 1 - t;
+ lut.push(new Float32Array([t_ * t_ * t_, 3 * t * t_ * t_,
+ 3 * t * t * t_, t * t * t]));
+ }
+ return lut;
+ }
+ var cache = [];
+ return function getB(count) {
+ if (!cache[count]) {
+ cache[count] = buildB(count);
+ }
+ return cache[count];
+ };
+ })();
+
+ function buildFigureFromPatch(mesh, index) {
+ var figure = mesh.figures[index];
+ assert(figure.type === 'patch', 'Unexpected patch mesh figure');
+
+ var coords = mesh.coords, colors = mesh.colors;
+ var pi = figure.coords;
+ var ci = figure.colors;
+
+ var figureMinX = Math.min(coords[pi[0]][0], coords[pi[3]][0],
+ coords[pi[12]][0], coords[pi[15]][0]);
+ var figureMinY = Math.min(coords[pi[0]][1], coords[pi[3]][1],
+ coords[pi[12]][1], coords[pi[15]][1]);
+ var figureMaxX = Math.max(coords[pi[0]][0], coords[pi[3]][0],
+ coords[pi[12]][0], coords[pi[15]][0]);
+ var figureMaxY = Math.max(coords[pi[0]][1], coords[pi[3]][1],
+ coords[pi[12]][1], coords[pi[15]][1]);
+ var splitXBy = Math.ceil((figureMaxX - figureMinX) * TRIANGLE_DENSITY /
+ (mesh.bounds[2] - mesh.bounds[0]));
+ splitXBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
+ Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy));
+ var splitYBy = Math.ceil((figureMaxY - figureMinY) * TRIANGLE_DENSITY /
+ (mesh.bounds[3] - mesh.bounds[1]));
+ splitYBy = Math.max(MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
+ Math.min(MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy));
+
+ var verticesPerRow = splitXBy + 1;
+ var figureCoords = new Int32Array((splitYBy + 1) * verticesPerRow);
+ var figureColors = new Int32Array((splitYBy + 1) * verticesPerRow);
+ var k = 0;
+ var cl = new Uint8Array(3), cr = new Uint8Array(3);
+ var c0 = colors[ci[0]], c1 = colors[ci[1]],
+ c2 = colors[ci[2]], c3 = colors[ci[3]];
+ var bRow = getB(splitYBy), bCol = getB(splitXBy);
+ for (var row = 0; row <= splitYBy; row++) {
+ cl[0] = ((c0[0] * (splitYBy - row) + c2[0] * row) / splitYBy) | 0;
+ cl[1] = ((c0[1] * (splitYBy - row) + c2[1] * row) / splitYBy) | 0;
+ cl[2] = ((c0[2] * (splitYBy - row) + c2[2] * row) / splitYBy) | 0;
+
+ cr[0] = ((c1[0] * (splitYBy - row) + c3[0] * row) / splitYBy) | 0;
+ cr[1] = ((c1[1] * (splitYBy - row) + c3[1] * row) / splitYBy) | 0;
+ cr[2] = ((c1[2] * (splitYBy - row) + c3[2] * row) / splitYBy) | 0;
+
+ for (var col = 0; col <= splitXBy; col++, k++) {
+ if ((row === 0 || row === splitYBy) &&
+ (col === 0 || col === splitXBy)) {
+ continue;
+ }
+ var x = 0, y = 0;
+ var q = 0;
+ for (var i = 0; i <= 3; i++) {
+ for (var j = 0; j <= 3; j++, q++) {
+ var m = bRow[row][i] * bCol[col][j];
+ x += coords[pi[q]][0] * m;
+ y += coords[pi[q]][1] * m;
+ }
+ }
+ figureCoords[k] = coords.length;
+ coords.push([x, y]);
+ figureColors[k] = colors.length;
+ var newColor = new Uint8Array(3);
+ newColor[0] = ((cl[0] * (splitXBy - col) + cr[0] * col) / splitXBy) | 0;
+ newColor[1] = ((cl[1] * (splitXBy - col) + cr[1] * col) / splitXBy) | 0;
+ newColor[2] = ((cl[2] * (splitXBy - col) + cr[2] * col) / splitXBy) | 0;
+ colors.push(newColor);
+ }
+ }
+ figureCoords[0] = pi[0];
+ figureColors[0] = ci[0];
+ figureCoords[splitXBy] = pi[3];
+ figureColors[splitXBy] = ci[1];
+ figureCoords[verticesPerRow * splitYBy] = pi[12];
+ figureColors[verticesPerRow * splitYBy] = ci[2];
+ figureCoords[verticesPerRow * splitYBy + splitXBy] = pi[15];
+ figureColors[verticesPerRow * splitYBy + splitXBy] = ci[3];
+
+ mesh.figures[index] = {
+ type: 'lattice',
+ coords: figureCoords,
+ colors: figureColors,
+ verticesPerRow: verticesPerRow
+ };
+ }
+
+ function decodeType6Shading(mesh, reader) {
+ // A special case of Type 7. The p11, p12, p21, p22 automatically filled
+ var coords = mesh.coords;
+ var colors = mesh.colors;
+ var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
+ var cs = new Int32Array(4); // c00, c30, c03, c33
+ while (reader.hasData) {
+ var f = reader.readFlag();
+ assert(0 <= f && f <= 3, 'Unknown type6 flag');
+ var i, ii;
+ var pi = coords.length;
+ for (i = 0, ii = (f !== 0 ? 8 : 12); i < ii; i++) {
+ coords.push(reader.readCoordinate());
+ }
+ var ci = colors.length;
+ for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
+ colors.push(reader.readComponents());
+ }
+ var tmp1, tmp2, tmp3, tmp4;
+ switch (f) {
+ case 0:
+ ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
+ ps[ 8] = pi + 2; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
+ ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 8;
+ ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
+ cs[2] = ci + 1; cs[3] = ci + 2;
+ cs[0] = ci; cs[1] = ci + 3;
+ break;
+ case 1:
+ tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
+ ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2;
+ ps[ 8] = pi + 6; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 1;
+ ps[ 4] = pi + 7; /* calculated below */ ps[ 7] = pi;
+ ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4;
+ tmp1 = cs[2]; tmp2 = cs[3];
+ cs[2] = ci + 1; cs[3] = ci;
+ cs[0] = tmp1; cs[1] = tmp2;
+ break;
+ case 2:
+ ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5;
+ ps[ 8] = ps[11]; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 4;
+ ps[ 4] = ps[7]; /* calculated below */ ps[ 7] = pi + 3;
+ ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2;
+ cs[2] = cs[3]; cs[3] = ci + 1;
+ cs[0] = cs[1]; cs[1] = ci;
+ break;
+ case 3:
+ ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3];
+ ps[ 8] = pi; /* values for 5, 6, 9, 10 are */ ps[11] = pi + 7;
+ ps[ 4] = pi + 1; /* calculated below */ ps[ 7] = pi + 6;
+ ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5;
+ cs[2] = cs[0]; cs[3] = cs[1];
+ cs[0] = ci; cs[1] = ci + 1;
+ break;
+ }
+ // set p11, p12, p21, p22
+ ps[5] = coords.length;
+ coords.push([
+ (-4 * coords[ps[0]][0] - coords[ps[15]][0] +
+ 6 * (coords[ps[4]][0] + coords[ps[1]][0]) -
+ 2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
+ 3 * (coords[ps[13]][0] + coords[ps[7]][0])) / 9,
+ (-4 * coords[ps[0]][1] - coords[ps[15]][1] +
+ 6 * (coords[ps[4]][1] + coords[ps[1]][1]) -
+ 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
+ 3 * (coords[ps[13]][1] + coords[ps[7]][1])) / 9
+ ]);
+ ps[6] = coords.length;
+ coords.push([
+ (-4 * coords[ps[3]][0] - coords[ps[12]][0] +
+ 6 * (coords[ps[2]][0] + coords[ps[7]][0]) -
+ 2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
+ 3 * (coords[ps[4]][0] + coords[ps[14]][0])) / 9,
+ (-4 * coords[ps[3]][1] - coords[ps[12]][1] +
+ 6 * (coords[ps[2]][1] + coords[ps[7]][1]) -
+ 2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
+ 3 * (coords[ps[4]][1] + coords[ps[14]][1])) / 9
+ ]);
+ ps[9] = coords.length;
+ coords.push([
+ (-4 * coords[ps[12]][0] - coords[ps[3]][0] +
+ 6 * (coords[ps[8]][0] + coords[ps[13]][0]) -
+ 2 * (coords[ps[0]][0] + coords[ps[15]][0]) +
+ 3 * (coords[ps[11]][0] + coords[ps[1]][0])) / 9,
+ (-4 * coords[ps[12]][1] - coords[ps[3]][1] +
+ 6 * (coords[ps[8]][1] + coords[ps[13]][1]) -
+ 2 * (coords[ps[0]][1] + coords[ps[15]][1]) +
+ 3 * (coords[ps[11]][1] + coords[ps[1]][1])) / 9
+ ]);
+ ps[10] = coords.length;
+ coords.push([
+ (-4 * coords[ps[15]][0] - coords[ps[0]][0] +
+ 6 * (coords[ps[11]][0] + coords[ps[14]][0]) -
+ 2 * (coords[ps[12]][0] + coords[ps[3]][0]) +
+ 3 * (coords[ps[2]][0] + coords[ps[8]][0])) / 9,
+ (-4 * coords[ps[15]][1] - coords[ps[0]][1] +
+ 6 * (coords[ps[11]][1] + coords[ps[14]][1]) -
+ 2 * (coords[ps[12]][1] + coords[ps[3]][1]) +
+ 3 * (coords[ps[2]][1] + coords[ps[8]][1])) / 9
+ ]);
+ mesh.figures.push({
+ type: 'patch',
+ coords: new Int32Array(ps), // making copies of ps and cs
+ colors: new Int32Array(cs)
+ });
+ }
+ }
+
+ function decodeType7Shading(mesh, reader) {
+ var coords = mesh.coords;
+ var colors = mesh.colors;
+ var ps = new Int32Array(16); // p00, p10, ..., p30, p01, ..., p33
+ var cs = new Int32Array(4); // c00, c30, c03, c33
+ while (reader.hasData) {
+ var f = reader.readFlag();
+ assert(0 <= f && f <= 3, 'Unknown type7 flag');
+ var i, ii;
+ var pi = coords.length;
+ for (i = 0, ii = (f !== 0 ? 12 : 16); i < ii; i++) {
+ coords.push(reader.readCoordinate());
+ }
+ var ci = colors.length;
+ for (i = 0, ii = (f !== 0 ? 2 : 4); i < ii; i++) {
+ colors.push(reader.readComponents());
+ }
+ var tmp1, tmp2, tmp3, tmp4;
+ switch (f) {
+ case 0:
+ ps[12] = pi + 3; ps[13] = pi + 4; ps[14] = pi + 5; ps[15] = pi + 6;
+ ps[ 8] = pi + 2; ps[ 9] = pi + 13; ps[10] = pi + 14; ps[11] = pi + 7;
+ ps[ 4] = pi + 1; ps[ 5] = pi + 12; ps[ 6] = pi + 15; ps[ 7] = pi + 8;
+ ps[ 0] = pi; ps[ 1] = pi + 11; ps[ 2] = pi + 10; ps[ 3] = pi + 9;
+ cs[2] = ci + 1; cs[3] = ci + 2;
+ cs[0] = ci; cs[1] = ci + 3;
+ break;
+ case 1:
+ tmp1 = ps[12]; tmp2 = ps[13]; tmp3 = ps[14]; tmp4 = ps[15];
+ ps[12] = pi + 5; ps[13] = pi + 4; ps[14] = pi + 3; ps[15] = pi + 2;
+ ps[ 8] = pi + 6; ps[ 9] = pi + 11; ps[10] = pi + 10; ps[11] = pi + 1;
+ ps[ 4] = pi + 7; ps[ 5] = pi + 8; ps[ 6] = pi + 9; ps[ 7] = pi;
+ ps[ 0] = tmp1; ps[ 1] = tmp2; ps[ 2] = tmp3; ps[ 3] = tmp4;
+ tmp1 = cs[2]; tmp2 = cs[3];
+ cs[2] = ci + 1; cs[3] = ci;
+ cs[0] = tmp1; cs[1] = tmp2;
+ break;
+ case 2:
+ ps[12] = ps[15]; ps[13] = pi + 7; ps[14] = pi + 6; ps[15] = pi + 5;
+ ps[ 8] = ps[11]; ps[ 9] = pi + 8; ps[10] = pi + 11; ps[11] = pi + 4;
+ ps[ 4] = ps[7]; ps[ 5] = pi + 9; ps[ 6] = pi + 10; ps[ 7] = pi + 3;
+ ps[ 0] = ps[3]; ps[ 1] = pi; ps[ 2] = pi + 1; ps[ 3] = pi + 2;
+ cs[2] = cs[3]; cs[3] = ci + 1;
+ cs[0] = cs[1]; cs[1] = ci;
+ break;
+ case 3:
+ ps[12] = ps[0]; ps[13] = ps[1]; ps[14] = ps[2]; ps[15] = ps[3];
+ ps[ 8] = pi; ps[ 9] = pi + 9; ps[10] = pi + 8; ps[11] = pi + 7;
+ ps[ 4] = pi + 1; ps[ 5] = pi + 10; ps[ 6] = pi + 11; ps[ 7] = pi + 6;
+ ps[ 0] = pi + 2; ps[ 1] = pi + 3; ps[ 2] = pi + 4; ps[ 3] = pi + 5;
+ cs[2] = cs[0]; cs[3] = cs[1];
+ cs[0] = ci; cs[1] = ci + 1;
+ break;
+ }
+ mesh.figures.push({
+ type: 'patch',
+ coords: new Int32Array(ps), // making copies of ps and cs
+ colors: new Int32Array(cs)
+ });
+ }
+ }
+
+ function updateBounds(mesh) {
+ var minX = mesh.coords[0][0], minY = mesh.coords[0][1],
+ maxX = minX, maxY = minY;
+ for (var i = 1, ii = mesh.coords.length; i < ii; i++) {
+ var x = mesh.coords[i][0], y = mesh.coords[i][1];
+ minX = minX > x ? x : minX;
+ minY = minY > y ? y : minY;
+ maxX = maxX < x ? x : maxX;
+ maxY = maxY < y ? y : maxY;
+ }
+ mesh.bounds = [minX, minY, maxX, maxY];
+ }
+
+ function packData(mesh) {
+ var i, ii, j, jj;
+
+ var coords = mesh.coords;
+ var coordsPacked = new Float32Array(coords.length * 2);
+ for (i = 0, j = 0, ii = coords.length; i < ii; i++) {
+ var xy = coords[i];
+ coordsPacked[j++] = xy[0];
+ coordsPacked[j++] = xy[1];
+ }
+ mesh.coords = coordsPacked;
+
+ var colors = mesh.colors;
+ var colorsPacked = new Uint8Array(colors.length * 3);
+ for (i = 0, j = 0, ii = colors.length; i < ii; i++) {
+ var c = colors[i];
+ colorsPacked[j++] = c[0];
+ colorsPacked[j++] = c[1];
+ colorsPacked[j++] = c[2];
+ }
+ mesh.colors = colorsPacked;
+
+ var figures = mesh.figures;
+ for (i = 0, ii = figures.length; i < ii; i++) {
+ var figure = figures[i], ps = figure.coords, cs = figure.colors;
+ for (j = 0, jj = ps.length; j < jj; j++) {
+ ps[j] *= 2;
+ cs[j] *= 3;
+ }
+ }
+ }
+
+ function Mesh(stream, matrix, xref, res) {
+ assert(isStream(stream), 'Mesh data is not a stream');
+ var dict = stream.dict;
+ this.matrix = matrix;
+ this.shadingType = dict.get('ShadingType');
+ this.type = 'Pattern';
+ this.bbox = dict.get('BBox');
+ var cs = dict.get('ColorSpace', 'CS');
+ cs = ColorSpace.parse(cs, xref, res);
+ this.cs = cs;
+ this.background = dict.has('Background') ?
+ cs.getRgb(dict.get('Background'), 0) : null;
+
+ var fnObj = dict.get('Function');
+ var fn = fnObj ? PDFFunction.parseArray(xref, fnObj) : null;
+
+ this.coords = [];
+ this.colors = [];
+ this.figures = [];
+
+ var decodeContext = {
+ bitsPerCoordinate: dict.get('BitsPerCoordinate'),
+ bitsPerComponent: dict.get('BitsPerComponent'),
+ bitsPerFlag: dict.get('BitsPerFlag'),
+ decode: dict.get('Decode'),
+ colorFn: fn,
+ colorSpace: cs,
+ numComps: fn ? 1 : cs.numComps
+ };
+ var reader = new MeshStreamReader(stream, decodeContext);
+
+ var patchMesh = false;
+ switch (this.shadingType) {
+ case PatternType.FREE_FORM_MESH:
+ decodeType4Shading(this, reader);
+ break;
+ case PatternType.LATTICE_FORM_MESH:
+ var verticesPerRow = dict.get('VerticesPerRow') | 0;
+ assert(verticesPerRow >= 2, 'Invalid VerticesPerRow');
+ decodeType5Shading(this, reader, verticesPerRow);
+ break;
+ case PatternType.COONS_PATCH_MESH:
+ decodeType6Shading(this, reader);
+ patchMesh = true;
+ break;
+ case PatternType.TENSOR_PATCH_MESH:
+ decodeType7Shading(this, reader);
+ patchMesh = true;
+ break;
+ default:
+ error('Unsupported mesh type.');
+ break;
+ }
+
+ if (patchMesh) {
+ // dirty bounds calculation for determining, how dense shall be triangles
+ updateBounds(this);
+ for (var i = 0, ii = this.figures.length; i < ii; i++) {
+ buildFigureFromPatch(this, i);
+ }
+ }
+ // calculate bounds
+ updateBounds(this);
+
+ packData(this);
+ }
+
+ Mesh.prototype = {
+ getIR: function Mesh_getIR() {
+ return ['Mesh', this.shadingType, this.coords, this.colors, this.figures,
+ this.bounds, this.matrix, this.bbox, this.background];
+ }
+ };
+
+ return Mesh;
+})();
+
+Shadings.Dummy = (function DummyClosure() {
+ function Dummy() {
+ this.type = 'Pattern';
+ }
+
+ Dummy.prototype = {
+ getIR: function Dummy_getIR() {
+ return ['Dummy'];
+ }
+ };
+ return Dummy;
+})();
+
+function getTilingPatternIR(operatorList, dict, args) {
+ var matrix = dict.get('Matrix');
+ var bbox = dict.get('BBox');
+ var xstep = dict.get('XStep');
+ var ystep = dict.get('YStep');
+ var paintType = dict.get('PaintType');
+ var tilingType = dict.get('TilingType');
+
+ return [
+ 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
+ paintType, tilingType
+ ];
+}
var PartialEvaluator = (function PartialEvaluatorClosure() {
function PartialEvaluator(pdfManager, xref, handler, pageIndex,
uniquePrefix, idCounters, fontCache) {
- this.state = new EvalState();
- this.stateStack = [];
-
this.pdfManager = pdfManager;
this.xref = xref;
this.handler = handler;
@@ -14554,6 +10527,1968 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
this.fontCache = fontCache;
}
+ // Trying to minimize Date.now() usage and check every 100 time
+ var TIME_SLOT_DURATION_MS = 20;
+ var CHECK_TIME_EVERY = 100;
+ function TimeSlotManager() {
+ this.reset();
+ }
+ TimeSlotManager.prototype = {
+ check: function TimeSlotManager_check() {
+ if (++this.checked < CHECK_TIME_EVERY) {
+ return false;
+ }
+ this.checked = 0;
+ return this.endTime <= Date.now();
+ },
+ reset: function TimeSlotManager_reset() {
+ this.endTime = Date.now() + TIME_SLOT_DURATION_MS;
+ this.checked = 0;
+ }
+ };
+
+ var deferred = Promise.resolve();
+
+ var TILING_PATTERN = 1, SHADING_PATTERN = 2;
+
+ PartialEvaluator.prototype = {
+ hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
+ if (!isDict(resources)) {
+ return false;
+ }
+
+ var processed = Object.create(null);
+ if (resources.objId) {
+ processed[resources.objId] = true;
+ }
+
+ var nodes = [resources];
+ while (nodes.length) {
+ var key;
+ var node = nodes.shift();
+ // First check the current resources for blend modes.
+ var graphicStates = node.get('ExtGState');
+ if (isDict(graphicStates)) {
+ graphicStates = graphicStates.getAll();
+ for (key in graphicStates) {
+ var graphicState = graphicStates[key];
+ var bm = graphicState['BM'];
+ if (isName(bm) && bm.name !== 'Normal') {
+ return true;
+ }
+ }
+ }
+ // Descend into the XObjects to look for more resources and blend modes.
+ var xObjects = node.get('XObject');
+ if (!isDict(xObjects)) {
+ continue;
+ }
+ xObjects = xObjects.getAll();
+ for (key in xObjects) {
+ var xObject = xObjects[key];
+ if (!isStream(xObject)) {
+ continue;
+ }
+ if (xObject.dict.objId) {
+ if (processed[xObject.dict.objId]) {
+ // stream has objId and is processed already
+ continue;
+ }
+ processed[xObject.dict.objId] = true;
+ }
+ var xResources = xObject.dict.get('Resources');
+ // Checking objId to detect an infinite loop.
+ if (isDict(xResources) &&
+ (!xResources.objId || !processed[xResources.objId])) {
+ nodes.push(xResources);
+ if (xResources.objId) {
+ processed[xResources.objId] = true;
+ }
+ }
+ }
+ }
+ return false;
+ },
+
+ buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
+ xobj, smask,
+ operatorList,
+ initialState) {
+ var matrix = xobj.dict.get('Matrix');
+ var bbox = xobj.dict.get('BBox');
+ var group = xobj.dict.get('Group');
+ if (group) {
+ var groupOptions = {
+ matrix: matrix,
+ bbox: bbox,
+ smask: smask,
+ isolated: false,
+ knockout: false
+ };
+
+ var groupSubtype = group.get('S');
+ var colorSpace;
+ if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
+ groupOptions.isolated = (group.get('I') || false);
+ groupOptions.knockout = (group.get('K') || false);
+ colorSpace = (group.has('CS') ?
+ ColorSpace.parse(group.get('CS'), this.xref, resources) : null);
+ }
+
+ if (smask && smask.backdrop) {
+ colorSpace = colorSpace || ColorSpace.singletons.rgb;
+ smask.backdrop = colorSpace.getRgb(smask.backdrop, 0);
+ }
+
+ operatorList.addOp(OPS.beginGroup, [groupOptions]);
+ }
+
+ operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
+
+ return this.getOperatorList(xobj,
+ (xobj.dict.get('Resources') || resources), operatorList, initialState).
+ then(function () {
+ operatorList.addOp(OPS.paintFormXObjectEnd, []);
+
+ if (group) {
+ operatorList.addOp(OPS.endGroup, [groupOptions]);
+ }
+ });
+ },
+
+ buildPaintImageXObject:
+ function PartialEvaluator_buildPaintImageXObject(resources, image,
+ inline, operatorList,
+ cacheKey, cache) {
+ var self = this;
+ var dict = image.dict;
+ var w = dict.get('Width', 'W');
+ var h = dict.get('Height', 'H');
+
+ if (!(w && isNum(w)) || !(h && isNum(h))) {
+ warn('Image dimensions are missing, or not numbers.');
+ return;
+ }
+ if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
+ warn('Image exceeded maximum allowed size and was removed.');
+ return;
+ }
+
+ var imageMask = (dict.get('ImageMask', 'IM') || false);
+ var imgData, args;
+ if (imageMask) {
+ // This depends on a tmpCanvas being filled with the
+ // current fillStyle, such that processing the pixel
+ // data can't be done here. Instead of creating a
+ // complete PDFImage, only read the information needed
+ // for later.
+
+ var width = dict.get('Width', 'W');
+ var height = dict.get('Height', 'H');
+ var bitStrideLength = (width + 7) >> 3;
+ var imgArray = image.getBytes(bitStrideLength * height);
+ var decode = dict.get('Decode', 'D');
+ var inverseDecode = (!!decode && decode[0] > 0);
+
+ imgData = PDFImage.createMask(imgArray, width, height,
+ image instanceof DecodeStream,
+ inverseDecode);
+ imgData.cached = true;
+ args = [imgData];
+ operatorList.addOp(OPS.paintImageMaskXObject, args);
+ if (cacheKey) {
+ cache.key = cacheKey;
+ cache.fn = OPS.paintImageMaskXObject;
+ cache.args = args;
+ }
+ return;
+ }
+
+ var softMask = (dict.get('SMask', 'SM') || false);
+ var mask = (dict.get('Mask') || false);
+
+ var SMALL_IMAGE_DIMENSIONS = 200;
+ // Inlining small images into the queue as RGB data
+ if (inline && !softMask && !mask && !(image instanceof JpegStream) &&
+ (w + h) < SMALL_IMAGE_DIMENSIONS) {
+ var imageObj = new PDFImage(this.xref, resources, image,
+ inline, null, null);
+ // We force the use of RGBA_32BPP images here, because we can't handle
+ // any other kind.
+ imgData = imageObj.createImageData(/* forceRGBA = */ true);
+ operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
+ return;
+ }
+
+ // If there is no imageMask, create the PDFImage and a lot
+ // of image processing can be done here.
+ var uniquePrefix = (this.uniquePrefix || '');
+ var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
+ operatorList.addDependency(objId);
+ args = [objId, w, h];
+
+ if (!softMask && !mask && image instanceof JpegStream &&
+ image.isNativelySupported(this.xref, resources)) {
+ // These JPEGs don't need any more processing so we can just send it.
+ operatorList.addOp(OPS.paintJpegXObject, args);
+ this.handler.send('obj',
+ [objId, this.pageIndex, 'JpegStream', image.getIR()]);
+ return;
+ }
+
+ PDFImage.buildImage(self.handler, self.xref, resources, image, inline).
+ then(function(imageObj) {
+ var imgData = imageObj.createImageData(/* forceRGBA = */ false);
+ self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
+ [imgData.data.buffer]);
+ }).then(null, function (reason) {
+ warn('Unable to decode image: ' + reason);
+ self.handler.send('obj', [objId, self.pageIndex, 'Image', null]);
+ });
+
+ operatorList.addOp(OPS.paintImageXObject, args);
+ if (cacheKey) {
+ cache.key = cacheKey;
+ cache.fn = OPS.paintImageXObject;
+ cache.args = args;
+ }
+ },
+
+ handleSMask: function PartialEvaluator_handleSmask(smask, resources,
+ operatorList,
+ stateManager) {
+ var smaskContent = smask.get('G');
+ var smaskOptions = {
+ subtype: smask.get('S').name,
+ backdrop: smask.get('BC')
+ };
+ return this.buildFormXObject(resources, smaskContent, smaskOptions,
+ operatorList, stateManager.state.clone());
+ },
+
+ handleTilingType:
+ function PartialEvaluator_handleTilingType(fn, args, resources,
+ pattern, patternDict,
+ operatorList) {
+ // Create an IR of the pattern code.
+ var tilingOpList = new OperatorList();
+ return this.getOperatorList(pattern,
+ (patternDict.get('Resources') || resources), tilingOpList).
+ then(function () {
+ // Add the dependencies to the parent operator list so they are
+ // resolved before sub operator list is executed synchronously.
+ operatorList.addDependencies(tilingOpList.dependencies);
+ operatorList.addOp(fn, getTilingPatternIR({
+ fnArray: tilingOpList.fnArray,
+ argsArray: tilingOpList.argsArray
+ }, patternDict, args));
+ });
+ },
+
+ handleSetFont:
+ function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef,
+ operatorList, state) {
+ // TODO(mack): Not needed?
+ var fontName;
+ if (fontArgs) {
+ fontArgs = fontArgs.slice();
+ fontName = fontArgs[0].name;
+ }
+
+ var self = this;
+ return this.loadFont(fontName, fontRef, this.xref, resources).then(
+ function (translated) {
+ if (!translated.font.isType3Font) {
+ return translated;
+ }
+ return translated.loadType3Data(self, resources, operatorList).then(
+ function () {
+ return translated;
+ });
+ }).then(function (translated) {
+ state.font = translated.font;
+ translated.send(self.handler);
+ return translated.loadedName;
+ });
+ },
+
+ handleText: function PartialEvaluator_handleText(chars, state) {
+ var font = state.font;
+ var glyphs = font.charsToGlyphs(chars);
+ var isAddToPathSet = !!(state.textRenderingMode &
+ TextRenderingMode.ADD_TO_PATH_FLAG);
+ if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) {
+ var buildPath = function (fontChar) {
+ if (!font.renderer.hasBuiltPath(fontChar)) {
+ var path = font.renderer.getPathJs(fontChar);
+ this.handler.send('commonobj', [
+ font.loadedName + '_path_' + fontChar,
+ 'FontPath',
+ path
+ ]);
+ }
+ }.bind(this);
+
+ for (var i = 0, ii = glyphs.length; i < ii; i++) {
+ var glyph = glyphs[i];
+ if (glyph === null) {
+ continue;
+ }
+ buildPath(glyph.fontChar);
+
+ // If the glyph has an accent we need to build a path for its
+ // fontChar too, otherwise CanvasGraphics_paintChar will fail.
+ var accent = glyph.accent;
+ if (accent && accent.fontChar) {
+ buildPath(accent.fontChar);
+ }
+ }
+ }
+
+ return glyphs;
+ },
+
+ setGState: function PartialEvaluator_setGState(resources, gState,
+ operatorList, xref,
+ stateManager) {
+ // This array holds the converted/processed state data.
+ var gStateObj = [];
+ var gStateMap = gState.map;
+ var self = this;
+ var promise = Promise.resolve();
+ for (var key in gStateMap) {
+ var value = gStateMap[key];
+ switch (key) {
+ case 'Type':
+ break;
+ case 'LW':
+ case 'LC':
+ case 'LJ':
+ case 'ML':
+ case 'D':
+ case 'RI':
+ case 'FL':
+ case 'CA':
+ case 'ca':
+ gStateObj.push([key, value]);
+ break;
+ case 'Font':
+ promise = promise.then(function () {
+ return self.handleSetFont(resources, null, value[0],
+ operatorList, stateManager.state).
+ then(function (loadedName) {
+ operatorList.addDependency(loadedName);
+ gStateObj.push([key, [loadedName, value[1]]]);
+ });
+ });
+ break;
+ case 'BM':
+ gStateObj.push([key, value]);
+ break;
+ case 'SMask':
+ if (isName(value) && value.name === 'None') {
+ gStateObj.push([key, false]);
+ break;
+ }
+ var dict = xref.fetchIfRef(value);
+ if (isDict(dict)) {
+ promise = promise.then(function () {
+ return self.handleSMask(dict, resources, operatorList,
+ stateManager);
+ });
+ gStateObj.push([key, true]);
+ } else {
+ warn('Unsupported SMask type');
+ }
+
+ break;
+ // Only generate info log messages for the following since
+ // they are unlikely to have a big impact on the rendering.
+ case 'OP':
+ case 'op':
+ case 'OPM':
+ case 'BG':
+ case 'BG2':
+ case 'UCR':
+ case 'UCR2':
+ case 'TR':
+ case 'TR2':
+ case 'HT':
+ case 'SM':
+ case 'SA':
+ case 'AIS':
+ case 'TK':
+ // TODO implement these operators.
+ info('graphic state operator ' + key);
+ break;
+ default:
+ info('Unknown graphic state operator ' + key);
+ break;
+ }
+ }
+ return promise.then(function () {
+ if (gStateObj.length >= 0) {
+ operatorList.addOp(OPS.setGState, [gStateObj]);
+ }
+ });
+ },
+
+ loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
+ resources) {
+
+ function errorFont() {
+ return Promise.resolve(new TranslatedFont('g_font_error',
+ new ErrorFont('Font ' + fontName + ' is not available'), font));
+ }
+ var fontRef;
+ if (font) { // Loading by ref.
+ assert(isRef(font));
+ fontRef = font;
+ } else { // Loading by name.
+ var fontRes = resources.get('Font');
+ if (fontRes) {
+ fontRef = fontRes.getRaw(fontName);
+ } else {
+ warn('fontRes not available');
+ return errorFont();
+ }
+ }
+ if (!fontRef) {
+ warn('fontRef not available');
+ return errorFont();
+ }
+
+ if (this.fontCache.has(fontRef)) {
+ return this.fontCache.get(fontRef);
+ }
+
+ font = xref.fetchIfRef(fontRef);
+ if (!isDict(font)) {
+ return errorFont();
+ }
+
+ // We are holding font.translated references just for fontRef that are not
+ // dictionaries (Dict). See explanation below.
+ if (font.translated) {
+ return font.translated;
+ }
+
+ var fontCapability = createPromiseCapability();
+
+ var preEvaluatedFont = this.preEvaluateFont(font, xref);
+ var descriptor = preEvaluatedFont.descriptor;
+ var fontID = fontRef.num + '_' + fontRef.gen;
+ if (isDict(descriptor)) {
+ if (!descriptor.fontAliases) {
+ descriptor.fontAliases = Object.create(null);
+ }
+
+ var fontAliases = descriptor.fontAliases;
+ var hash = preEvaluatedFont.hash;
+ if (fontAliases[hash]) {
+ var aliasFontRef = fontAliases[hash].aliasRef;
+ if (aliasFontRef && this.fontCache.has(aliasFontRef)) {
+ this.fontCache.putAlias(fontRef, aliasFontRef);
+ return this.fontCache.get(fontRef);
+ }
+ }
+
+ if (!fontAliases[hash]) {
+ fontAliases[hash] = {
+ fontID: Font.getFontID()
+ };
+ }
+
+ fontAliases[hash].aliasRef = fontRef;
+ fontID = fontAliases[hash].fontID;
+ }
+
+ // Workaround for bad PDF generators that don't reference fonts
+ // properly, i.e. by not using an object identifier.
+ // Check if the fontRef is a Dict (as opposed to a standard object),
+ // in which case we don't cache the font and instead reference it by
+ // fontName in font.loadedName below.
+ var fontRefIsDict = isDict(fontRef);
+ if (!fontRefIsDict) {
+ this.fontCache.put(fontRef, fontCapability.promise);
+ }
+
+ // Keep track of each font we translated so the caller can
+ // load them asynchronously before calling display on a page.
+ font.loadedName = 'g_font_' + (fontRefIsDict ?
+ fontName.replace(/\W/g, '') : fontID);
+
+ font.translated = fontCapability.promise;
+
+ // TODO move promises into translate font
+ var translatedPromise;
+ try {
+ translatedPromise = Promise.resolve(
+ this.translateFont(preEvaluatedFont, xref));
+ } catch (e) {
+ translatedPromise = Promise.reject(e);
+ }
+
+ translatedPromise.then(function (translatedFont) {
+ if (translatedFont.fontType !== undefined) {
+ var xrefFontStats = xref.stats.fontTypes;
+ xrefFontStats[translatedFont.fontType] = true;
+ }
+
+ fontCapability.resolve(new TranslatedFont(font.loadedName,
+ translatedFont, font));
+ }, function (reason) {
+ // TODO fontCapability.reject?
+ UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
+
+ try {
+ // error, but it's still nice to have font type reported
+ var descriptor = preEvaluatedFont.descriptor;
+ var fontFile3 = descriptor && descriptor.get('FontFile3');
+ var subtype = fontFile3 && fontFile3.get('Subtype');
+ var fontType = getFontType(preEvaluatedFont.type,
+ subtype && subtype.name);
+ var xrefFontStats = xref.stats.fontTypes;
+ xrefFontStats[fontType] = true;
+ } catch (ex) { }
+
+ fontCapability.resolve(new TranslatedFont(font.loadedName,
+ new ErrorFont(reason instanceof Error ? reason.message : reason),
+ font));
+ });
+ return fontCapability.promise;
+ },
+
+ buildPath: function PartialEvaluator_buildPath(operatorList, fn, args) {
+ var lastIndex = operatorList.length - 1;
+ if (!args) {
+ args = [];
+ }
+ if (lastIndex < 0 ||
+ operatorList.fnArray[lastIndex] !== OPS.constructPath) {
+ operatorList.addOp(OPS.constructPath, [[fn], args]);
+ } else {
+ var opArgs = operatorList.argsArray[lastIndex];
+ opArgs[0].push(fn);
+ Array.prototype.push.apply(opArgs[1], args);
+ }
+ },
+
+ handleColorN: function PartialEvaluator_handleColorN(operatorList, fn, args,
+ cs, patterns, resources, xref) {
+ // compile tiling patterns
+ var patternName = args[args.length - 1];
+ // SCN/scn applies patterns along with normal colors
+ var pattern;
+ if (isName(patternName) &&
+ (pattern = patterns.get(patternName.name))) {
+ var dict = (isStream(pattern) ? pattern.dict : pattern);
+ var typeNum = dict.get('PatternType');
+
+ if (typeNum === TILING_PATTERN) {
+ var color = cs.base ? cs.base.getRgb(args, 0) : null;
+ return this.handleTilingType(fn, color, resources, pattern,
+ dict, operatorList);
+ } else if (typeNum === SHADING_PATTERN) {
+ var shading = dict.get('Shading');
+ var matrix = dict.get('Matrix');
+ pattern = Pattern.parseShading(shading, matrix, xref, resources);
+ operatorList.addOp(fn, pattern.getIR());
+ return Promise.resolve();
+ } else {
+ return Promise.reject('Unknown PatternType: ' + typeNum);
+ }
+ }
+ // TODO shall we fail here?
+ operatorList.addOp(fn, args);
+ return Promise.resolve();
+ },
+
+ getOperatorList: function PartialEvaluator_getOperatorList(stream,
+ resources,
+ operatorList,
+ initialState) {
+
+ var self = this;
+ var xref = this.xref;
+ var imageCache = {};
+
+ assert(operatorList);
+
+ resources = (resources || Dict.empty);
+ var xobjs = (resources.get('XObject') || Dict.empty);
+ var patterns = (resources.get('Pattern') || Dict.empty);
+ var stateManager = new StateManager(initialState || new EvalState());
+ var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
+ var timeSlotManager = new TimeSlotManager();
+
+ return new Promise(function next(resolve, reject) {
+ timeSlotManager.reset();
+ var stop, operation = {}, i, ii, cs;
+ while (!(stop = timeSlotManager.check())) {
+ // The arguments parsed by read() are used beyond this loop, so we
+ // cannot reuse the same array on each iteration. Therefore we pass
+ // in |null| as the initial value (see the comment on
+ // EvaluatorPreprocessor_read() for why).
+ operation.args = null;
+ if (!(preprocessor.read(operation))) {
+ break;
+ }
+ var args = operation.args;
+ var fn = operation.fn;
+
+ switch (fn | 0) {
+ case OPS.paintXObject:
+ if (args[0].code) {
+ break;
+ }
+ // eagerly compile XForm objects
+ var name = args[0].name;
+ if (imageCache.key === name) {
+ operatorList.addOp(imageCache.fn, imageCache.args);
+ args = null;
+ continue;
+ }
+
+ var xobj = xobjs.get(name);
+ if (xobj) {
+ assert(isStream(xobj), 'XObject should be a stream');
+
+ var type = xobj.dict.get('Subtype');
+ assert(isName(type),
+ 'XObject should have a Name subtype');
+
+ if (type.name === 'Form') {
+ stateManager.save();
+ return self.buildFormXObject(resources, xobj, null,
+ operatorList,
+ stateManager.state.clone()).
+ then(function () {
+ stateManager.restore();
+ next(resolve, reject);
+ }, reject);
+ } else if (type.name === 'Image') {
+ self.buildPaintImageXObject(resources, xobj, false,
+ operatorList, name, imageCache);
+ args = null;
+ continue;
+ } else if (type.name === 'PS') {
+ // PostScript XObjects are unused when viewing documents.
+ // See section 4.7.1 of Adobe's PDF reference.
+ info('Ignored XObject subtype PS');
+ continue;
+ } else {
+ error('Unhandled XObject subtype ' + type.name);
+ }
+ }
+ break;
+ case OPS.setFont:
+ var fontSize = args[1];
+ // eagerly collect all fonts
+ return self.handleSetFont(resources, args, null,
+ operatorList, stateManager.state).
+ then(function (loadedName) {
+ operatorList.addDependency(loadedName);
+ operatorList.addOp(OPS.setFont, [loadedName, fontSize]);
+ next(resolve, reject);
+ }, reject);
+ case OPS.endInlineImage:
+ var cacheKey = args[0].cacheKey;
+ if (cacheKey && imageCache.key === cacheKey) {
+ operatorList.addOp(imageCache.fn, imageCache.args);
+ args = null;
+ continue;
+ }
+ self.buildPaintImageXObject(resources, args[0], true,
+ operatorList, cacheKey, imageCache);
+ args = null;
+ continue;
+ case OPS.showText:
+ args[0] = self.handleText(args[0], stateManager.state);
+ break;
+ case OPS.showSpacedText:
+ var arr = args[0];
+ var combinedGlyphs = [];
+ var arrLength = arr.length;
+ for (i = 0; i < arrLength; ++i) {
+ var arrItem = arr[i];
+ if (isString(arrItem)) {
+ Array.prototype.push.apply(combinedGlyphs,
+ self.handleText(arrItem, stateManager.state));
+ } else if (isNum(arrItem)) {
+ combinedGlyphs.push(arrItem);
+ }
+ }
+ args[0] = combinedGlyphs;
+ fn = OPS.showText;
+ break;
+ case OPS.nextLineShowText:
+ operatorList.addOp(OPS.nextLine);
+ args[0] = self.handleText(args[0], stateManager.state);
+ fn = OPS.showText;
+ break;
+ case OPS.nextLineSetSpacingShowText:
+ operatorList.addOp(OPS.nextLine);
+ operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
+ operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
+ args[0] = self.handleText(args[0], stateManager.state);
+ fn = OPS.showText;
+ break;
+ case OPS.setTextRenderingMode:
+ stateManager.state.textRenderingMode = args[0];
+ break;
+
+ case OPS.setFillColorSpace:
+ stateManager.state.fillColorSpace =
+ ColorSpace.parse(args[0], xref, resources);
+ continue;
+ case OPS.setStrokeColorSpace:
+ stateManager.state.strokeColorSpace =
+ ColorSpace.parse(args[0], xref, resources);
+ continue;
+ case OPS.setFillColor:
+ cs = stateManager.state.fillColorSpace;
+ args = cs.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeColor:
+ cs = stateManager.state.strokeColorSpace;
+ args = cs.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillGray:
+ stateManager.state.fillColorSpace = ColorSpace.singletons.gray;
+ args = ColorSpace.singletons.gray.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeGray:
+ stateManager.state.strokeColorSpace = ColorSpace.singletons.gray;
+ args = ColorSpace.singletons.gray.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillCMYKColor:
+ stateManager.state.fillColorSpace = ColorSpace.singletons.cmyk;
+ args = ColorSpace.singletons.cmyk.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeCMYKColor:
+ stateManager.state.strokeColorSpace = ColorSpace.singletons.cmyk;
+ args = ColorSpace.singletons.cmyk.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+ case OPS.setFillRGBColor:
+ stateManager.state.fillColorSpace = ColorSpace.singletons.rgb;
+ args = ColorSpace.singletons.rgb.getRgb(args, 0);
+ break;
+ case OPS.setStrokeRGBColor:
+ stateManager.state.strokeColorSpace = ColorSpace.singletons.rgb;
+ args = ColorSpace.singletons.rgb.getRgb(args, 0);
+ break;
+ case OPS.setFillColorN:
+ cs = stateManager.state.fillColorSpace;
+ if (cs.name === 'Pattern') {
+ return self.handleColorN(operatorList, OPS.setFillColorN,
+ args, cs, patterns, resources, xref).then(function() {
+ next(resolve, reject);
+ }, reject);
+ }
+ args = cs.getRgb(args, 0);
+ fn = OPS.setFillRGBColor;
+ break;
+ case OPS.setStrokeColorN:
+ cs = stateManager.state.strokeColorSpace;
+ if (cs.name === 'Pattern') {
+ return self.handleColorN(operatorList, OPS.setStrokeColorN,
+ args, cs, patterns, resources, xref).then(function() {
+ next(resolve, reject);
+ }, reject);
+ }
+ args = cs.getRgb(args, 0);
+ fn = OPS.setStrokeRGBColor;
+ break;
+
+ case OPS.shadingFill:
+ var shadingRes = resources.get('Shading');
+ if (!shadingRes) {
+ error('No shading resource found');
+ }
+
+ var shading = shadingRes.get(args[0].name);
+ if (!shading) {
+ error('No shading object found');
+ }
+
+ var shadingFill = Pattern.parseShading(shading, null, xref,
+ resources);
+ var patternIR = shadingFill.getIR();
+ args = [patternIR];
+ fn = OPS.shadingFill;
+ break;
+ case OPS.setGState:
+ var dictName = args[0];
+ var extGState = resources.get('ExtGState');
+
+ if (!isDict(extGState) || !extGState.has(dictName.name)) {
+ break;
+ }
+
+ var gState = extGState.get(dictName.name);
+ return self.setGState(resources, gState, operatorList, xref,
+ stateManager).then(function() {
+ next(resolve, reject);
+ }, reject);
+ case OPS.moveTo:
+ case OPS.lineTo:
+ case OPS.curveTo:
+ case OPS.curveTo2:
+ case OPS.curveTo3:
+ case OPS.closePath:
+ self.buildPath(operatorList, fn, args);
+ continue;
+ case OPS.rectangle:
+ self.buildPath(operatorList, fn, args);
+ continue;
+ }
+ operatorList.addOp(fn, args);
+ }
+ if (stop) {
+ deferred.then(function () {
+ next(resolve, reject);
+ });
+ return;
+ }
+ // Some PDFs don't close all restores inside object/form.
+ // Closing those for them.
+ for (i = 0, ii = preprocessor.savedStatesDepth; i < ii; i++) {
+ operatorList.addOp(OPS.restore, []);
+ }
+ resolve();
+ });
+ },
+
+ getTextContent: function PartialEvaluator_getTextContent(stream, resources,
+ stateManager) {
+
+ stateManager = (stateManager || new StateManager(new TextState()));
+
+ var textContent = {
+ items: [],
+ styles: Object.create(null)
+ };
+ var bidiTexts = textContent.items;
+ var SPACE_FACTOR = 0.35;
+ var MULTI_SPACE_FACTOR = 1.5;
+
+ var self = this;
+ var xref = this.xref;
+
+ resources = (xref.fetchIfRef(resources) || Dict.empty);
+
+ // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
+ var xobjs = null;
+ var xobjsCache = {};
+
+ var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
+
+ var textState;
+
+ function newTextChunk() {
+ var font = textState.font;
+ if (!(font.loadedName in textContent.styles)) {
+ textContent.styles[font.loadedName] = {
+ fontFamily: font.fallbackName,
+ ascent: font.ascent,
+ descent: font.descent,
+ vertical: font.vertical
+ };
+ }
+ return {
+ // |str| is initially an array which we push individual chars to, and
+ // then runBidi() overwrites it with the final string.
+ str: [],
+ dir: null,
+ width: 0,
+ height: 0,
+ transform: null,
+ fontName: font.loadedName
+ };
+ }
+
+ function runBidi(textChunk) {
+ var str = textChunk.str.join('');
+ var bidiResult = PDFJS.bidi(str, -1, textState.font.vertical);
+ textChunk.str = bidiResult.str;
+ textChunk.dir = bidiResult.dir;
+ return textChunk;
+ }
+
+ function handleSetFont(fontName, fontRef) {
+ return self.loadFont(fontName, fontRef, xref, resources).
+ then(function (translated) {
+ textState.font = translated.font;
+ textState.fontMatrix = translated.font.fontMatrix ||
+ FONT_IDENTITY_MATRIX;
+ });
+ }
+
+ function buildTextGeometry(chars, textChunk) {
+ var font = textState.font;
+ textChunk = textChunk || newTextChunk();
+ if (!textChunk.transform) {
+ // 9.4.4 Text Space Details
+ var tsm = [textState.fontSize * textState.textHScale, 0,
+ 0, textState.fontSize,
+ 0, textState.textRise];
+ var trm = textChunk.transform = Util.transform(textState.ctm,
+ Util.transform(textState.textMatrix, tsm));
+ if (!font.vertical) {
+ textChunk.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);
+ } else {
+ textChunk.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);
+ }
+ }
+ var width = 0;
+ var height = 0;
+ var glyphs = font.charsToGlyphs(chars);
+ var defaultVMetrics = font.defaultVMetrics;
+ for (var i = 0; i < glyphs.length; i++) {
+ var glyph = glyphs[i];
+ if (!glyph) { // Previous glyph was a space.
+ width += textState.wordSpacing * textState.textHScale;
+ continue;
+ }
+ var vMetricX = null;
+ var vMetricY = null;
+ var glyphWidth = null;
+ if (font.vertical) {
+ if (glyph.vmetric) {
+ glyphWidth = glyph.vmetric[0];
+ vMetricX = glyph.vmetric[1];
+ vMetricY = glyph.vmetric[2];
+ } else {
+ glyphWidth = glyph.width;
+ vMetricX = glyph.width * 0.5;
+ vMetricY = defaultVMetrics[2];
+ }
+ } else {
+ glyphWidth = glyph.width;
+ }
+
+ var glyphUnicode = glyph.unicode;
+ if (NormalizedUnicodes[glyphUnicode] !== undefined) {
+ glyphUnicode = NormalizedUnicodes[glyphUnicode];
+ }
+ glyphUnicode = reverseIfRtl(glyphUnicode);
+
+ // The following will calculate the x and y of the individual glyphs.
+ // if (font.vertical) {
+ // tsm[4] -= vMetricX * Math.abs(textState.fontSize) *
+ // textState.fontMatrix[0];
+ // tsm[5] -= vMetricY * textState.fontSize *
+ // textState.fontMatrix[0];
+ // }
+ // var trm = Util.transform(textState.textMatrix, tsm);
+ // var pt = Util.applyTransform([trm[4], trm[5]], textState.ctm);
+ // var x = pt[0];
+ // var y = pt[1];
+
+ var tx = 0;
+ var ty = 0;
+ if (!font.vertical) {
+ var w0 = glyphWidth * textState.fontMatrix[0];
+ tx = (w0 * textState.fontSize + textState.charSpacing) *
+ textState.textHScale;
+ width += tx;
+ } else {
+ var w1 = glyphWidth * textState.fontMatrix[0];
+ ty = w1 * textState.fontSize + textState.charSpacing;
+ height += ty;
+ }
+ textState.translateTextMatrix(tx, ty);
+
+ textChunk.str.push(glyphUnicode);
+ }
+
+ var a = textState.textLineMatrix[0];
+ var b = textState.textLineMatrix[1];
+ var scaleLineX = Math.sqrt(a * a + b * b);
+ a = textState.ctm[0];
+ b = textState.ctm[1];
+ var scaleCtmX = Math.sqrt(a * a + b * b);
+ if (!font.vertical) {
+ textChunk.width += width * scaleCtmX * scaleLineX;
+ } else {
+ textChunk.height += Math.abs(height * scaleCtmX * scaleLineX);
+ }
+ return textChunk;
+ }
+
+ var timeSlotManager = new TimeSlotManager();
+
+ return new Promise(function next(resolve, reject) {
+ timeSlotManager.reset();
+ var stop, operation = {}, args = [];
+ while (!(stop = timeSlotManager.check())) {
+ // The arguments parsed by read() are not used beyond this loop, so
+ // we can reuse the same array on every iteration, thus avoiding
+ // unnecessary allocations.
+ args.length = 0;
+ operation.args = args;
+ if (!(preprocessor.read(operation))) {
+ break;
+ }
+ textState = stateManager.state;
+ var fn = operation.fn;
+ args = operation.args;
+
+ switch (fn | 0) {
+ case OPS.setFont:
+ textState.fontSize = args[1];
+ return handleSetFont(args[0].name).then(function() {
+ next(resolve, reject);
+ }, reject);
+ case OPS.setTextRise:
+ textState.textRise = args[0];
+ break;
+ case OPS.setHScale:
+ textState.textHScale = args[0] / 100;
+ break;
+ case OPS.setLeading:
+ textState.leading = args[0];
+ break;
+ case OPS.moveText:
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
+ break;
+ case OPS.setLeadingMoveText:
+ textState.leading = -args[1];
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
+ break;
+ case OPS.nextLine:
+ textState.carriageReturn();
+ break;
+ case OPS.setTextMatrix:
+ textState.setTextMatrix(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
+ textState.setTextLineMatrix(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
+ break;
+ case OPS.setCharSpacing:
+ textState.charSpacing = args[0];
+ break;
+ case OPS.setWordSpacing:
+ textState.wordSpacing = args[0];
+ break;
+ case OPS.beginText:
+ textState.textMatrix = IDENTITY_MATRIX.slice();
+ textState.textLineMatrix = IDENTITY_MATRIX.slice();
+ break;
+ case OPS.showSpacedText:
+ var items = args[0];
+ var textChunk = newTextChunk();
+ var offset;
+ for (var j = 0, jj = items.length; j < jj; j++) {
+ if (typeof items[j] === 'string') {
+ buildTextGeometry(items[j], textChunk);
+ } else {
+ var val = items[j] / 1000;
+ if (!textState.font.vertical) {
+ offset = -val * textState.fontSize * textState.textHScale *
+ textState.textMatrix[0];
+ textState.translateTextMatrix(offset, 0);
+ textChunk.width += offset;
+ } else {
+ offset = -val * textState.fontSize *
+ textState.textMatrix[3];
+ textState.translateTextMatrix(0, offset);
+ textChunk.height += offset;
+ }
+ if (items[j] < 0 && textState.font.spaceWidth > 0) {
+ var fakeSpaces = -items[j] / textState.font.spaceWidth;
+ if (fakeSpaces > MULTI_SPACE_FACTOR) {
+ fakeSpaces = Math.round(fakeSpaces);
+ while (fakeSpaces--) {
+ textChunk.str.push(' ');
+ }
+ } else if (fakeSpaces > SPACE_FACTOR) {
+ textChunk.str.push(' ');
+ }
+ }
+ }
+ }
+ bidiTexts.push(runBidi(textChunk));
+ break;
+ case OPS.showText:
+ bidiTexts.push(runBidi(buildTextGeometry(args[0])));
+ break;
+ case OPS.nextLineShowText:
+ textState.carriageReturn();
+ bidiTexts.push(runBidi(buildTextGeometry(args[0])));
+ break;
+ case OPS.nextLineSetSpacingShowText:
+ textState.wordSpacing = args[0];
+ textState.charSpacing = args[1];
+ textState.carriageReturn();
+ bidiTexts.push(runBidi(buildTextGeometry(args[2])));
+ break;
+ case OPS.paintXObject:
+ if (args[0].code) {
+ break;
+ }
+
+ if (!xobjs) {
+ xobjs = (resources.get('XObject') || Dict.empty);
+ }
+
+ var name = args[0].name;
+ if (xobjsCache.key === name) {
+ if (xobjsCache.texts) {
+ Util.appendToArray(bidiTexts, xobjsCache.texts.items);
+ Util.extendObj(textContent.styles, xobjsCache.texts.styles);
+ }
+ break;
+ }
+
+ var xobj = xobjs.get(name);
+ if (!xobj) {
+ break;
+ }
+ assert(isStream(xobj), 'XObject should be a stream');
+
+ var type = xobj.dict.get('Subtype');
+ assert(isName(type),
+ 'XObject should have a Name subtype');
+
+ if ('Form' !== type.name) {
+ xobjsCache.key = name;
+ xobjsCache.texts = null;
+ break;
+ }
+
+ stateManager.save();
+ var matrix = xobj.dict.get('Matrix');
+ if (isArray(matrix) && matrix.length === 6) {
+ stateManager.transform(matrix);
+ }
+
+ return self.getTextContent(xobj,
+ xobj.dict.get('Resources') || resources, stateManager).
+ then(function (formTextContent) {
+ Util.appendToArray(bidiTexts, formTextContent.items);
+ Util.extendObj(textContent.styles, formTextContent.styles);
+ stateManager.restore();
+
+ xobjsCache.key = name;
+ xobjsCache.texts = formTextContent;
+
+ next(resolve, reject);
+ }, reject);
+ case OPS.setGState:
+ var dictName = args[0];
+ var extGState = resources.get('ExtGState');
+
+ if (!isDict(extGState) || !extGState.has(dictName.name)) {
+ break;
+ }
+
+ var gsStateMap = extGState.get(dictName.name);
+ var gsStateFont = null;
+ for (var key in gsStateMap) {
+ if (key === 'Font') {
+ assert(!gsStateFont);
+ gsStateFont = gsStateMap[key];
+ }
+ }
+ if (gsStateFont) {
+ textState.fontSize = gsStateFont[1];
+ return handleSetFont(gsStateFont[0]).then(function() {
+ next(resolve, reject);
+ }, reject);
+ }
+ break;
+ } // switch
+ } // while
+ if (stop) {
+ deferred.then(function () {
+ next(resolve, reject);
+ });
+ return;
+ }
+ resolve(textContent);
+ });
+ },
+
+ extractDataStructures: function
+ partialEvaluatorExtractDataStructures(dict, baseDict,
+ xref, properties) {
+ // 9.10.2
+ var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));
+ if (toUnicode) {
+ properties.toUnicode = this.readToUnicode(toUnicode);
+ }
+ if (properties.composite) {
+ // CIDSystemInfo helps to match CID to glyphs
+ var cidSystemInfo = dict.get('CIDSystemInfo');
+ if (isDict(cidSystemInfo)) {
+ properties.cidSystemInfo = {
+ registry: cidSystemInfo.get('Registry'),
+ ordering: cidSystemInfo.get('Ordering'),
+ supplement: cidSystemInfo.get('Supplement')
+ };
+ }
+
+ var cidToGidMap = dict.get('CIDToGIDMap');
+ if (isStream(cidToGidMap)) {
+ properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
+ }
+ }
+
+ // Based on 9.6.6 of the spec the encoding can come from multiple places
+ // and depends on the font type. The base encoding and differences are
+ // read here, but the encoding that is actually used is chosen during
+ // glyph mapping in the font.
+ // TODO: Loading the built in encoding in the font would allow the
+ // differences to be merged in here not require us to hold on to it.
+ var differences = [];
+ var baseEncodingName = null;
+ var encoding;
+ if (dict.has('Encoding')) {
+ encoding = dict.get('Encoding');
+ if (isDict(encoding)) {
+ baseEncodingName = encoding.get('BaseEncoding');
+ baseEncodingName = (isName(baseEncodingName) ?
+ baseEncodingName.name : null);
+ // Load the differences between the base and original
+ if (encoding.has('Differences')) {
+ var diffEncoding = encoding.get('Differences');
+ var index = 0;
+ for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
+ var data = diffEncoding[j];
+ if (isNum(data)) {
+ index = data;
+ } else {
+ differences[index++] = data.name;
+ }
+ }
+ }
+ } else if (isName(encoding)) {
+ baseEncodingName = encoding.name;
+ } else {
+ error('Encoding is not a Name nor a Dict');
+ }
+ // According to table 114 if the encoding is a named encoding it must be
+ // one of these predefined encodings.
+ if ((baseEncodingName !== 'MacRomanEncoding' &&
+ baseEncodingName !== 'MacExpertEncoding' &&
+ baseEncodingName !== 'WinAnsiEncoding')) {
+ baseEncodingName = null;
+ }
+ }
+
+ if (baseEncodingName) {
+ properties.defaultEncoding = Encodings[baseEncodingName].slice();
+ } else {
+ encoding = (properties.type === 'TrueType' ?
+ Encodings.WinAnsiEncoding : Encodings.StandardEncoding);
+ // The Symbolic attribute can be misused for regular fonts
+ // Heuristic: we have to check if the font is a standard one also
+ if (!!(properties.flags & FontFlags.Symbolic)) {
+ encoding = Encodings.MacRomanEncoding;
+ if (!properties.file) {
+ if (/Symbol/i.test(properties.name)) {
+ encoding = Encodings.SymbolSetEncoding;
+ } else if (/Dingbats/i.test(properties.name)) {
+ encoding = Encodings.ZapfDingbatsEncoding;
+ }
+ }
+ }
+ properties.defaultEncoding = encoding;
+ }
+
+ properties.differences = differences;
+ properties.baseEncodingName = baseEncodingName;
+ properties.dict = dict;
+ },
+
+ readToUnicode: function PartialEvaluator_readToUnicode(toUnicode) {
+ var cmap, cmapObj = toUnicode;
+ if (isName(cmapObj)) {
+ cmap = CMapFactory.create(cmapObj,
+ { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null).getMap();
+ return new ToUnicodeMap(cmap);
+ } else if (isStream(cmapObj)) {
+ cmap = CMapFactory.create(cmapObj,
+ { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null).getMap();
+ // Convert UTF-16BE
+ // NOTE: cmap can be a sparse array, so use forEach instead of for(;;)
+ // to iterate over all keys.
+ cmap.forEach(function(token, i) {
+ var str = [];
+ for (var k = 0; k < token.length; k += 2) {
+ var w1 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
+ if ((w1 & 0xF800) !== 0xD800) { // w1 < 0xD800 || w1 > 0xDFFF
+ str.push(w1);
+ continue;
+ }
+ k += 2;
+ var w2 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
+ str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000);
+ }
+ cmap[i] = String.fromCharCode.apply(String, str);
+ });
+ return new ToUnicodeMap(cmap);
+ }
+ return null;
+ },
+
+ readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
+ // Extract the encoding from the CIDToGIDMap
+ var glyphsData = cidToGidStream.getBytes();
+
+ // Set encoding 0 to later verify the font has an encoding
+ var result = [];
+ for (var j = 0, jj = glyphsData.length; j < jj; j++) {
+ var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
+ if (glyphID === 0) {
+ continue;
+ }
+ var code = j >> 1;
+ result[code] = glyphID;
+ }
+ return result;
+ },
+
+ extractWidths: function PartialEvaluator_extractWidths(dict, xref,
+ descriptor,
+ properties) {
+ var glyphsWidths = [];
+ var defaultWidth = 0;
+ var glyphsVMetrics = [];
+ var defaultVMetrics;
+ var i, ii, j, jj, start, code, widths;
+ if (properties.composite) {
+ defaultWidth = dict.get('DW') || 1000;
+
+ widths = dict.get('W');
+ if (widths) {
+ for (i = 0, ii = widths.length; i < ii; i++) {
+ start = widths[i++];
+ code = xref.fetchIfRef(widths[i]);
+ if (isArray(code)) {
+ for (j = 0, jj = code.length; j < jj; j++) {
+ glyphsWidths[start++] = code[j];
+ }
+ } else {
+ var width = widths[++i];
+ for (j = start; j <= code; j++) {
+ glyphsWidths[j] = width;
+ }
+ }
+ }
+ }
+
+ if (properties.vertical) {
+ var vmetrics = (dict.get('DW2') || [880, -1000]);
+ defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
+ vmetrics = dict.get('W2');
+ if (vmetrics) {
+ for (i = 0, ii = vmetrics.length; i < ii; i++) {
+ start = vmetrics[i++];
+ code = xref.fetchIfRef(vmetrics[i]);
+ if (isArray(code)) {
+ for (j = 0, jj = code.length; j < jj; j++) {
+ glyphsVMetrics[start++] = [code[j++], code[j++], code[j]];
+ }
+ } else {
+ var vmetric = [vmetrics[++i], vmetrics[++i], vmetrics[++i]];
+ for (j = start; j <= code; j++) {
+ glyphsVMetrics[j] = vmetric;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ var firstChar = properties.firstChar;
+ widths = dict.get('Widths');
+ if (widths) {
+ j = firstChar;
+ for (i = 0, ii = widths.length; i < ii; i++) {
+ glyphsWidths[j++] = widths[i];
+ }
+ defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);
+ } else {
+ // Trying get the BaseFont metrics (see comment above).
+ var baseFontName = dict.get('BaseFont');
+ if (isName(baseFontName)) {
+ var metrics = this.getBaseFontMetrics(baseFontName.name);
+
+ glyphsWidths = this.buildCharCodeToWidth(metrics.widths,
+ properties);
+ defaultWidth = metrics.defaultWidth;
+ }
+ }
+ }
+
+ // Heuristic: detection of monospace font by checking all non-zero widths
+ var isMonospace = true;
+ var firstWidth = defaultWidth;
+ for (var glyph in glyphsWidths) {
+ var glyphWidth = glyphsWidths[glyph];
+ if (!glyphWidth) {
+ continue;
+ }
+ if (!firstWidth) {
+ firstWidth = glyphWidth;
+ continue;
+ }
+ if (firstWidth !== glyphWidth) {
+ isMonospace = false;
+ break;
+ }
+ }
+ if (isMonospace) {
+ properties.flags |= FontFlags.FixedPitch;
+ }
+
+ properties.defaultWidth = defaultWidth;
+ properties.widths = glyphsWidths;
+ properties.defaultVMetrics = defaultVMetrics;
+ properties.vmetrics = glyphsVMetrics;
+ },
+
+ isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) {
+ // Simulating descriptor flags attribute
+ var fontNameWoStyle = baseFontName.split('-')[0];
+ return (fontNameWoStyle in serifFonts) ||
+ (fontNameWoStyle.search(/serif/gi) !== -1);
+ },
+
+ getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
+ var defaultWidth = 0;
+ var widths = [];
+ var monospace = false;
+ var lookupName = (stdFontMap[name] || name);
+
+ if (!(lookupName in Metrics)) {
+ // Use default fonts for looking up font metrics if the passed
+ // font is not a base font
+ if (this.isSerifFont(name)) {
+ lookupName = 'Times-Roman';
+ } else {
+ lookupName = 'Helvetica';
+ }
+ }
+ var glyphWidths = Metrics[lookupName];
+
+ if (isNum(glyphWidths)) {
+ defaultWidth = glyphWidths;
+ monospace = true;
+ } else {
+ widths = glyphWidths;
+ }
+
+ return {
+ defaultWidth: defaultWidth,
+ monospace: monospace,
+ widths: widths
+ };
+ },
+
+ buildCharCodeToWidth:
+ function PartialEvaluator_bulildCharCodeToWidth(widthsByGlyphName,
+ properties) {
+ var widths = Object.create(null);
+ var differences = properties.differences;
+ var encoding = properties.defaultEncoding;
+ for (var charCode = 0; charCode < 256; charCode++) {
+ if (charCode in differences &&
+ widthsByGlyphName[differences[charCode]]) {
+ widths[charCode] = widthsByGlyphName[differences[charCode]];
+ continue;
+ }
+ if (charCode in encoding && widthsByGlyphName[encoding[charCode]]) {
+ widths[charCode] = widthsByGlyphName[encoding[charCode]];
+ continue;
+ }
+ }
+ return widths;
+ },
+
+ preEvaluateFont: function PartialEvaluator_preEvaluateFont(dict, xref) {
+ var baseDict = dict;
+ var type = dict.get('Subtype');
+ assert(isName(type), 'invalid font Subtype');
+
+ var composite = false;
+ var uint8array;
+ if (type.name === 'Type0') {
+ // If font is a composite
+ // - get the descendant font
+ // - set the type according to the descendant font
+ // - get the FontDescriptor from the descendant font
+ var df = dict.get('DescendantFonts');
+ if (!df) {
+ error('Descendant fonts are not specified');
+ }
+ dict = (isArray(df) ? xref.fetchIfRef(df[0]) : df);
+
+ type = dict.get('Subtype');
+ assert(isName(type), 'invalid font Subtype');
+ composite = true;
+ }
+
+ var descriptor = dict.get('FontDescriptor');
+ if (descriptor) {
+ var hash = new MurmurHash3_64();
+ var encoding = baseDict.getRaw('Encoding');
+ if (isName(encoding)) {
+ hash.update(encoding.name);
+ } else if (isRef(encoding)) {
+ hash.update(encoding.num + '_' + encoding.gen);
+ }
+
+ var toUnicode = dict.get('ToUnicode') || baseDict.get('ToUnicode');
+ if (isStream(toUnicode)) {
+ var stream = toUnicode.str || toUnicode;
+ uint8array = stream.buffer ?
+ new Uint8Array(stream.buffer.buffer, 0, stream.bufferLength) :
+ new Uint8Array(stream.bytes.buffer,
+ stream.start, stream.end - stream.start);
+ hash.update(uint8array);
+
+ } else if (isName(toUnicode)) {
+ hash.update(toUnicode.name);
+ }
+
+ var widths = dict.get('Widths') || baseDict.get('Widths');
+ if (widths) {
+ uint8array = new Uint8Array(new Uint32Array(widths).buffer);
+ hash.update(uint8array);
+ }
+ }
+
+ return {
+ descriptor: descriptor,
+ dict: dict,
+ baseDict: baseDict,
+ composite: composite,
+ type: type.name,
+ hash: hash ? hash.hexdigest() : ''
+ };
+ },
+
+ translateFont: function PartialEvaluator_translateFont(preEvaluatedFont,
+ xref) {
+ var baseDict = preEvaluatedFont.baseDict;
+ var dict = preEvaluatedFont.dict;
+ var composite = preEvaluatedFont.composite;
+ var descriptor = preEvaluatedFont.descriptor;
+ var type = preEvaluatedFont.type;
+ var maxCharIndex = (composite ? 0xFFFF : 0xFF);
+ var properties;
+
+ if (!descriptor) {
+ if (type === 'Type3') {
+ // FontDescriptor is only required for Type3 fonts when the document
+ // is a tagged pdf. Create a barbebones one to get by.
+ descriptor = new Dict(null);
+ descriptor.set('FontName', Name.get(type));
+ } else {
+ // Before PDF 1.5 if the font was one of the base 14 fonts, having a
+ // FontDescriptor was not required.
+ // This case is here for compatibility.
+ var baseFontName = dict.get('BaseFont');
+ if (!isName(baseFontName)) {
+ error('Base font is not specified');
+ }
+
+ // Using base font name as a font name.
+ baseFontName = baseFontName.name.replace(/[,_]/g, '-');
+ var metrics = this.getBaseFontMetrics(baseFontName);
+
+ // Simulating descriptor flags attribute
+ var fontNameWoStyle = baseFontName.split('-')[0];
+ var flags =
+ (this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |
+ (metrics.monospace ? FontFlags.FixedPitch : 0) |
+ (symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
+ FontFlags.Nonsymbolic);
+
+ properties = {
+ type: type,
+ name: baseFontName,
+ widths: metrics.widths,
+ defaultWidth: metrics.defaultWidth,
+ flags: flags,
+ firstChar: 0,
+ lastChar: maxCharIndex
+ };
+ this.extractDataStructures(dict, dict, xref, properties);
+ properties.widths = this.buildCharCodeToWidth(metrics.widths,
+ properties);
+ return new Font(baseFontName, null, properties);
+ }
+ }
+
+ // According to the spec if 'FontDescriptor' is declared, 'FirstChar',
+ // 'LastChar' and 'Widths' should exist too, but some PDF encoders seem
+ // to ignore this rule when a variant of a standart font is used.
+ // TODO Fill the width array depending on which of the base font this is
+ // a variant.
+ var firstChar = (dict.get('FirstChar') || 0);
+ var lastChar = (dict.get('LastChar') || maxCharIndex);
+
+ var fontName = descriptor.get('FontName');
+ var baseFont = dict.get('BaseFont');
+ // Some bad PDFs have a string as the font name.
+ if (isString(fontName)) {
+ fontName = Name.get(fontName);
+ }
+ if (isString(baseFont)) {
+ baseFont = Name.get(baseFont);
+ }
+
+ if (type !== 'Type3') {
+ var fontNameStr = fontName && fontName.name;
+ var baseFontStr = baseFont && baseFont.name;
+ if (fontNameStr !== baseFontStr) {
+ info('The FontDescriptor\'s FontName is "' + fontNameStr +
+ '" but should be the same as the Font\'s BaseFont "' +
+ baseFontStr + '"');
+ // Workaround for cases where e.g. fontNameStr = 'Arial' and
+ // baseFontStr = 'Arial,Bold' (needed when no font file is embedded).
+ if (fontNameStr && baseFontStr &&
+ baseFontStr.indexOf(fontNameStr) === 0) {
+ fontName = baseFont;
+ }
+ }
+ }
+ fontName = (fontName || baseFont);
+
+ assert(isName(fontName), 'invalid font name');
+
+ var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
+ if (fontFile) {
+ if (fontFile.dict) {
+ var subtype = fontFile.dict.get('Subtype');
+ if (subtype) {
+ subtype = subtype.name;
+ }
+ var length1 = fontFile.dict.get('Length1');
+ var length2 = fontFile.dict.get('Length2');
+ }
+ }
+
+ properties = {
+ type: type,
+ name: fontName.name,
+ subtype: subtype,
+ file: fontFile,
+ length1: length1,
+ length2: length2,
+ loadedName: baseDict.loadedName,
+ composite: composite,
+ wideChars: composite,
+ fixedPitch: false,
+ fontMatrix: (dict.get('FontMatrix') || FONT_IDENTITY_MATRIX),
+ firstChar: firstChar || 0,
+ lastChar: (lastChar || maxCharIndex),
+ bbox: descriptor.get('FontBBox'),
+ ascent: descriptor.get('Ascent'),
+ descent: descriptor.get('Descent'),
+ xHeight: descriptor.get('XHeight'),
+ capHeight: descriptor.get('CapHeight'),
+ flags: descriptor.get('Flags'),
+ italicAngle: descriptor.get('ItalicAngle'),
+ coded: false
+ };
+
+ if (composite) {
+ var cidEncoding = baseDict.get('Encoding');
+ if (isName(cidEncoding)) {
+ properties.cidEncoding = cidEncoding.name;
+ }
+ properties.cMap = CMapFactory.create(cidEncoding,
+ { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
+ properties.vertical = properties.cMap.vertical;
+ }
+ this.extractDataStructures(dict, baseDict, xref, properties);
+ this.extractWidths(dict, xref, descriptor, properties);
+
+ if (type === 'Type3') {
+ properties.isType3Font = true;
+ }
+
+ return new Font(fontName.name, fontFile, properties);
+ }
+ };
+
+ return PartialEvaluator;
+})();
+
+var TranslatedFont = (function TranslatedFontClosure() {
+ function TranslatedFont(loadedName, font, dict) {
+ this.loadedName = loadedName;
+ this.font = font;
+ this.dict = dict;
+ this.type3Loaded = null;
+ this.sent = false;
+ }
+ TranslatedFont.prototype = {
+ send: function (handler) {
+ if (this.sent) {
+ return;
+ }
+ var fontData = this.font.exportData();
+ handler.send('commonobj', [
+ this.loadedName,
+ 'Font',
+ fontData
+ ]);
+ this.sent = true;
+ },
+ loadType3Data: function (evaluator, resources, parentOperatorList) {
+ assert(this.font.isType3Font);
+
+ if (this.type3Loaded) {
+ return this.type3Loaded;
+ }
+
+ var translatedFont = this.font;
+ var loadCharProcsPromise = Promise.resolve();
+ var charProcs = this.dict.get('CharProcs').getAll();
+ var fontResources = this.dict.get('Resources') || resources;
+ var charProcKeys = Object.keys(charProcs);
+ var charProcOperatorList = {};
+ for (var i = 0, n = charProcKeys.length; i < n; ++i) {
+ loadCharProcsPromise = loadCharProcsPromise.then(function (key) {
+ var glyphStream = charProcs[key];
+ var operatorList = new OperatorList();
+ return evaluator.getOperatorList(glyphStream, fontResources,
+ operatorList).then(function () {
+ charProcOperatorList[key] = operatorList.getIR();
+
+ // Add the dependencies to the parent operator list so they are
+ // resolved before sub operator list is executed synchronously.
+ parentOperatorList.addDependencies(operatorList.dependencies);
+ }, function (reason) {
+ warn('Type3 font resource \"' + key + '\" is not available');
+ var operatorList = new OperatorList();
+ charProcOperatorList[key] = operatorList.getIR();
+ });
+ }.bind(this, charProcKeys[i]));
+ }
+ this.type3Loaded = loadCharProcsPromise.then(function () {
+ translatedFont.charProcOperatorList = charProcOperatorList;
+ });
+ return this.type3Loaded;
+ }
+ };
+ return TranslatedFont;
+})();
+
+var OperatorList = (function OperatorListClosure() {
+ var CHUNK_SIZE = 1000;
+ var CHUNK_SIZE_ABOUT = CHUNK_SIZE - 5; // close to chunk size
+
+ function getTransfers(queue) {
+ var transfers = [];
+ var fnArray = queue.fnArray, argsArray = queue.argsArray;
+ for (var i = 0, ii = queue.length; i < ii; i++) {
+ switch (fnArray[i]) {
+ case OPS.paintInlineImageXObject:
+ case OPS.paintInlineImageXObjectGroup:
+ case OPS.paintImageMaskXObject:
+ var arg = argsArray[i][0]; // first param in imgData
+ if (!arg.cached) {
+ transfers.push(arg.data.buffer);
+ }
+ break;
+ }
+ }
+ return transfers;
+ }
+
+ function OperatorList(intent, messageHandler, pageIndex) {
+ this.messageHandler = messageHandler;
+ this.fnArray = [];
+ this.argsArray = [];
+ this.dependencies = {};
+ this.pageIndex = pageIndex;
+ this.intent = intent;
+ }
+
+ OperatorList.prototype = {
+ get length() {
+ return this.argsArray.length;
+ },
+
+ addOp: function(fn, args) {
+ this.fnArray.push(fn);
+ this.argsArray.push(args);
+ if (this.messageHandler) {
+ if (this.fnArray.length >= CHUNK_SIZE) {
+ this.flush();
+ } else if (this.fnArray.length >= CHUNK_SIZE_ABOUT &&
+ (fn === OPS.restore || fn === OPS.endText)) {
+ // heuristic to flush on boundary of restore or endText
+ this.flush();
+ }
+ }
+ },
+
+ addDependency: function(dependency) {
+ if (dependency in this.dependencies) {
+ return;
+ }
+ this.dependencies[dependency] = true;
+ this.addOp(OPS.dependency, [dependency]);
+ },
+
+ addDependencies: function(dependencies) {
+ for (var key in dependencies) {
+ this.addDependency(key);
+ }
+ },
+
+ addOpList: function(opList) {
+ Util.extendObj(this.dependencies, opList.dependencies);
+ for (var i = 0, ii = opList.length; i < ii; i++) {
+ this.addOp(opList.fnArray[i], opList.argsArray[i]);
+ }
+ },
+
+ getIR: function() {
+ return {
+ fnArray: this.fnArray,
+ argsArray: this.argsArray,
+ length: this.length
+ };
+ },
+
+ flush: function(lastChunk) {
+ if (this.intent !== 'oplist') {
+ new QueueOptimizer().optimize(this);
+ }
+ var transfers = getTransfers(this);
+ this.messageHandler.send('RenderPageChunk', {
+ operatorList: {
+ fnArray: this.fnArray,
+ argsArray: this.argsArray,
+ lastChunk: lastChunk,
+ length: this.length
+ },
+ pageIndex: this.pageIndex,
+ intent: this.intent
+ }, transfers);
+ this.dependencies = {};
+ this.fnArray.length = 0;
+ this.argsArray.length = 0;
+ }
+ };
+
+ return OperatorList;
+})();
+
+var StateManager = (function StateManagerClosure() {
+ function StateManager(initialState) {
+ this.state = initialState;
+ this.stateStack = [];
+ }
+ StateManager.prototype = {
+ save: function () {
+ var old = this.state;
+ this.stateStack.push(this.state);
+ this.state = old.clone();
+ },
+ restore: function () {
+ var prev = this.stateStack.pop();
+ if (prev) {
+ this.state = prev;
+ }
+ },
+ transform: function (args) {
+ this.state.ctm = Util.transform(this.state.ctm, args);
+ }
+ };
+ return StateManager;
+})();
+
+var TextState = (function TextStateClosure() {
+ function TextState() {
+ this.ctm = new Float32Array(IDENTITY_MATRIX);
+ this.fontSize = 0;
+ this.font = null;
+ this.fontMatrix = FONT_IDENTITY_MATRIX;
+ this.textMatrix = IDENTITY_MATRIX.slice();
+ this.textLineMatrix = IDENTITY_MATRIX.slice();
+ this.charSpacing = 0;
+ this.wordSpacing = 0;
+ this.leading = 0;
+ this.textHScale = 1;
+ this.textRise = 0;
+ }
+
+ TextState.prototype = {
+ setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
+ var m = this.textMatrix;
+ m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
+ },
+ setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
+ var m = this.textLineMatrix;
+ m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
+ },
+ translateTextMatrix: function TextState_translateTextMatrix(x, y) {
+ var m = this.textMatrix;
+ m[4] = m[0] * x + m[2] * y + m[4];
+ m[5] = m[1] * x + m[3] * y + m[5];
+ },
+ translateTextLineMatrix: function TextState_translateTextMatrix(x, y) {
+ var m = this.textLineMatrix;
+ m[4] = m[0] * x + m[2] * y + m[4];
+ m[5] = m[1] * x + m[3] * y + m[5];
+ },
+ calcRenderMatrix: function TextState_calcRendeMatrix(ctm) {
+ // 9.4.4 Text Space Details
+ var tsm = [this.fontSize * this.textHScale, 0,
+ 0, this.fontSize,
+ 0, this.textRise];
+ return Util.transform(ctm, Util.transform(this.textMatrix, tsm));
+ },
+ carriageReturn: function TextState_carriageReturn() {
+ this.translateTextLineMatrix(0, -this.leading);
+ this.textMatrix = this.textLineMatrix.slice();
+ },
+ clone: function TextState_clone() {
+ var clone = Object.create(this);
+ clone.textMatrix = this.textMatrix.slice();
+ clone.textLineMatrix = this.textLineMatrix.slice();
+ clone.fontMatrix = this.fontMatrix.slice();
+ return clone;
+ }
+ };
+ return TextState;
+})();
+
+var EvalState = (function EvalStateClosure() {
+ function EvalState() {
+ this.ctm = new Float32Array(IDENTITY_MATRIX);
+ this.font = null;
+ this.textRenderingMode = TextRenderingMode.FILL;
+ this.fillColorSpace = ColorSpace.singletons.gray;
+ this.strokeColorSpace = ColorSpace.singletons.gray;
+ }
+ EvalState.prototype = {
+ clone: function CanvasExtraState_clone() {
+ return Object.create(this);
+ },
+ };
+ return EvalState;
+})();
+
+var EvaluatorPreprocessor = (function EvaluatorPreprocessorClosure() {
// Specifies properties for each command
//
// If variableArgs === true: [0, `numArgs`] expected
@@ -14613,7 +12548,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
TJ: { id: OPS.showSpacedText, numArgs: 1, variableArgs: false },
'\'': { id: OPS.nextLineShowText, numArgs: 1, variableArgs: false },
'"': { id: OPS.nextLineSetSpacingShowText, numArgs: 3,
- variableArgs: false },
+ variableArgs: false },
// Type3 fonts
d0: { id: OPS.setCharWidth, numArgs: 2, variableArgs: false },
@@ -14647,7 +12582,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
DP: { id: OPS.markPointProps, numArgs: 2, variableArgs: false },
BMC: { id: OPS.beginMarkedContent, numArgs: 1, variableArgs: false },
BDC: { id: OPS.beginMarkedContentProps, numArgs: 2,
- variableArgs: false },
+ variableArgs: false },
EMC: { id: OPS.endMarkedContent, numArgs: 0, variableArgs: false },
// Compatibility
@@ -14667,414 +12602,46 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
'null': null
};
- var TILING_PATTERN = 1, SHADING_PATTERN = 2;
+ function EvaluatorPreprocessor(stream, xref, stateManager) {
+ // TODO(mduan): pass array of knownCommands rather than OP_MAP
+ // dictionary
+ this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
+ this.stateManager = stateManager;
+ this.nonProcessedArgs = [];
+ }
- PartialEvaluator.prototype = {
- hasBlendModes: function PartialEvaluator_hasBlendModes(resources) {
- if (!isDict(resources)) {
- return false;
- }
-
- var nodes = [resources];
- while (nodes.length) {
- var node = nodes.shift();
- // First check the current resources for blend modes.
- var graphicStates = node.get('ExtGState');
- if (isDict(graphicStates)) {
- graphicStates = graphicStates.getAll();
- for (var key in graphicStates) {
- var graphicState = graphicStates[key];
- var bm = graphicState['BM'];
- if (isName(bm) && bm.name !== 'Normal') {
- return true;
- }
- }
- }
- // Descend into the XObjects to look for more resources and blend modes.
- var xObjects = node.get('XObject');
- if (!isDict(xObjects)) {
- continue;
- }
- xObjects = xObjects.getAll();
- for (var key in xObjects) {
- var xObject = xObjects[key];
- if (!isStream(xObject)) {
- continue;
- }
- var xResources = xObject.dict.get('Resources');
- if (isDict(xResources)) {
- nodes.push(xResources);
- }
- }
- }
- return false;
+ EvaluatorPreprocessor.prototype = {
+ get savedStatesDepth() {
+ return this.stateManager.stateStack.length;
},
- buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
- xobj, smask,
- operatorList) {
- var self = this;
-
- var matrix = xobj.dict.get('Matrix');
- var bbox = xobj.dict.get('BBox');
- var group = xobj.dict.get('Group');
- if (group) {
- var groupOptions = {
- matrix: matrix,
- bbox: bbox,
- smask: !!smask,
- isolated: false,
- knockout: false
- };
-
- var groupSubtype = group.get('S');
- if (isName(groupSubtype) && groupSubtype.name === 'Transparency') {
- groupOptions.isolated = group.get('I') || false;
- groupOptions.knockout = group.get('K') || false;
- // There is also a group colorspace, but since we put everything in
- // RGB I'm not sure we need it.
- }
- operatorList.addOp(OPS.beginGroup, [groupOptions]);
- }
-
- operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
-
- this.getOperatorList(xobj, xobj.dict.get('Resources') || resources,
- operatorList);
- operatorList.addOp(OPS.paintFormXObjectEnd, []);
-
- if (group) {
- operatorList.addOp(OPS.endGroup, [groupOptions]);
- }
- },
-
- buildPaintImageXObject: function PartialEvaluator_buildPaintImageXObject(
- resources, image, inline, operatorList) {
- var self = this;
- var dict = image.dict;
- var w = dict.get('Width', 'W');
- var h = dict.get('Height', 'H');
-
- if (PDFJS.maxImageSize !== -1 && w * h > PDFJS.maxImageSize) {
- warn('Image exceeded maximum allowed size and was removed.');
- return;
- }
-
- var imageMask = dict.get('ImageMask', 'IM') || false;
- if (imageMask) {
- // This depends on a tmpCanvas beeing filled with the
- // current fillStyle, such that processing the pixel
- // data can't be done here. Instead of creating a
- // complete PDFImage, only read the information needed
- // for later.
-
- var width = dict.get('Width', 'W');
- var height = dict.get('Height', 'H');
- var bitStrideLength = (width + 7) >> 3;
- var imgArray = image.getBytes(bitStrideLength * height);
- var decode = dict.get('Decode', 'D');
- var inverseDecode = !!decode && decode[0] > 0;
-
- operatorList.addOp(OPS.paintImageMaskXObject,
- [PDFImage.createMask(imgArray, width, height,
- inverseDecode)]
- );
- return;
- }
-
- var softMask = dict.get('SMask', 'SM') || false;
- var mask = dict.get('Mask') || false;
-
- var SMALL_IMAGE_DIMENSIONS = 200;
- // Inlining small images into the queue as RGB data
- if (inline && !softMask && !mask &&
- !(image instanceof JpegStream) &&
- (w + h) < SMALL_IMAGE_DIMENSIONS) {
- var imageObj = new PDFImage(this.xref, resources, image,
- inline, null, null);
- var imgData = imageObj.getImageData();
- operatorList.addOp(OPS.paintInlineImageXObject, [imgData]);
- return;
- }
-
- // If there is no imageMask, create the PDFImage and a lot
- // of image processing can be done here.
- var uniquePrefix = this.uniquePrefix || '';
- var objId = 'img_' + uniquePrefix + (++this.idCounters.obj);
- operatorList.addDependency(objId);
- var args = [objId, w, h];
-
- if (!softMask && !mask && image instanceof JpegStream &&
- image.isNativelySupported(this.xref, resources)) {
- // These JPEGs don't need any more processing so we can just send it.
- operatorList.addOp(OPS.paintJpegXObject, args);
- this.handler.send(
- 'obj', [objId, this.pageIndex, 'JpegStream', image.getIR()]);
- return;
- }
-
-
- PDFImage.buildImage(function(imageObj) {
- var imgData = imageObj.getImageData();
- self.handler.send('obj', [objId, self.pageIndex, 'Image', imgData],
- null, [imgData.data.buffer]);
- }, self.handler, self.xref, resources, image, inline);
-
- operatorList.addOp(OPS.paintImageXObject, args);
- },
-
- handleTilingType: function PartialEvaluator_handleTilingType(
- fn, args, resources, pattern, patternDict,
- operatorList) {
- // Create an IR of the pattern code.
- var tilingOpList = this.getOperatorList(pattern,
- patternDict.get('Resources') || resources);
- // Add the dependencies to the parent operator list so they are resolved
- // before sub operator list is executed synchronously.
- operatorList.addDependencies(tilingOpList.dependencies);
- operatorList.addOp(fn, TilingPattern.getIR({
- fnArray: tilingOpList.fnArray,
- argsArray: tilingOpList.argsArray
- }, patternDict, args));
- },
-
- handleSetFont: function PartialEvaluator_handleSetFont(
- resources, fontArgs, fontRef, operatorList) {
-
- // TODO(mack): Not needed?
- var fontName;
- if (fontArgs) {
- fontArgs = fontArgs.slice();
- fontName = fontArgs[0].name;
- }
- var self = this;
- var font = this.loadFont(fontName, fontRef, this.xref, resources,
- operatorList);
- this.state.font = font;
- var loadedName = font.loadedName;
- if (!font.sent) {
- var fontData = font.translated.exportData();
-
- self.handler.send('commonobj', [
- loadedName,
- 'Font',
- fontData
- ]);
- font.sent = true;
- }
-
- return loadedName;
- },
-
- handleText: function PartialEvaluator_handleText(chars) {
- var font = this.state.font.translated;
- var glyphs = font.charsToGlyphs(chars);
- var isAddToPathSet = !!(this.state.textRenderingMode &
- TextRenderingMode.ADD_TO_PATH_FLAG);
- if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) {
- for (var i = 0; i < glyphs.length; i++) {
- if (glyphs[i] === null) {
- continue;
- }
- var fontChar = glyphs[i].fontChar;
- if (!font.renderer.hasBuiltPath(fontChar)) {
- var path = font.renderer.getPathJs(fontChar);
- this.handler.send('commonobj', [
- font.loadedName + '_path_' + fontChar,
- 'FontPath',
- path
- ]);
- }
- }
- }
-
- return glyphs;
- },
-
- setGState: function PartialEvaluator_setGState(resources, gState,
- operatorList) {
-
- var self = this;
- // TODO(mack): This should be rewritten so that this function returns
- // what should be added to the queue during each iteration
- function setGStateForKey(gStateObj, key, value) {
- switch (key) {
- case 'Type':
- break;
- case 'LW':
- case 'LC':
- case 'LJ':
- case 'ML':
- case 'D':
- case 'RI':
- case 'FL':
- case 'CA':
- case 'ca':
- gStateObj.push([key, value]);
- break;
- case 'Font':
- var loadedName = self.handleSetFont(resources, null, value[0],
- operatorList);
- operatorList.addDependency(loadedName);
- gStateObj.push([key, [loadedName, value[1]]]);
- break;
- case 'BM':
- gStateObj.push([key, value]);
- break;
- case 'SMask':
- // We support the default so don't trigger a warning bar.
- if (!isName(value) || value.name != 'None')
- UnsupportedManager.notify(UNSUPPORTED_FEATURES.smask);
- break;
- // Only generate info log messages for the following since
- // they are unlikey to have a big impact on the rendering.
- case 'OP':
- case 'op':
- case 'OPM':
- case 'BG':
- case 'BG2':
- case 'UCR':
- case 'UCR2':
- case 'TR':
- case 'TR2':
- case 'HT':
- case 'SM':
- case 'SA':
- case 'AIS':
- case 'TK':
- // TODO implement these operators.
- info('graphic state operator ' + key);
- break;
- default:
- info('Unknown graphic state operator ' + key);
- break;
- }
- }
-
- // This array holds the converted/processed state data.
- var gStateObj = [];
- var gStateMap = gState.map;
- for (var key in gStateMap) {
- var value = gStateMap[key];
- setGStateForKey(gStateObj, key, value);
- }
-
- operatorList.addOp(OPS.setGState, [gStateObj]);
- },
-
- loadFont: function PartialEvaluator_loadFont(fontName, font, xref,
- resources,
- parentOperatorList) {
-
- function errorFont() {
- return {
- translated: new ErrorFont('Font ' + fontName + ' is not available'),
- loadedName: 'g_font_error'
- };
- }
-
- var fontRef;
- if (font) { // Loading by ref.
- assert(isRef(font));
- fontRef = font;
- } else { // Loading by name.
- var fontRes = resources.get('Font');
- if (fontRes) {
- fontRef = fontRes.getRaw(fontName);
- } else {
- warn('fontRes not available');
- return errorFont();
- }
- }
- if (this.fontCache.has(fontRef)) {
- return this.fontCache.get(fontRef);
- }
-
- font = xref.fetchIfRef(fontRef);
- if (!isDict(font)) {
- return errorFont();
- }
- // Workaround for bad PDF generators that doesn't reference fonts
- // properly, i.e. by not using an object identifier.
- // Check if the fontRef is a Dict (as opposed to a standard object),
- // in which case we don't cache the font and instead reference it by
- // fontName in font.loadedName below.
- var fontRefIsDict = isDict(fontRef);
- if (!fontRefIsDict) {
- this.fontCache.put(fontRef, font);
- }
-
- // keep track of each font we translated so the caller can
- // load them asynchronously before calling display on a page
- font.loadedName = 'g_font_' + (fontRefIsDict ?
- fontName.replace(/\W/g, '') : (fontRef.num + '_' + fontRef.gen));
-
- if (!font.translated) {
- var translated;
- try {
- translated = this.translateFont(font, xref);
- } catch (e) {
- UnsupportedManager.notify(UNSUPPORTED_FEATURES.font);
- translated = new ErrorFont(e instanceof Error ? e.message : e);
- }
- font.translated = translated;
- }
-
- if (font.translated.loadCharProcs) {
- var charProcs = font.get('CharProcs').getAll();
- var fontResources = font.get('Resources') || resources;
- var charProcKeys = Object.keys(charProcs);
- var charProcOperatorList = {};
- for (var i = 0, n = charProcKeys.length; i < n; ++i) {
- var key = charProcKeys[i];
- var glyphStream = charProcs[key];
- var operatorList = this.getOperatorList(glyphStream, fontResources);
- charProcOperatorList[key] = operatorList.getIR();
- if (!parentOperatorList) {
- continue;
- }
- // Add the dependencies to the parent operator list so they are
- // resolved before sub operator list is executed synchronously.
- parentOperatorList.addDependencies(charProcOperatorList.dependencies);
- }
- font.translated.charProcOperatorList = charProcOperatorList;
- font.loaded = true;
- } else {
- font.loaded = true;
- }
- return font;
- },
-
- getOperatorList: function PartialEvaluator_getOperatorList(stream,
- resources,
- operatorList) {
-
- var self = this;
- var xref = this.xref;
- var handler = this.handler;
-
- operatorList = operatorList || new OperatorList();
-
- resources = resources || new Dict();
- var xobjs = resources.get('XObject') || new Dict();
- var patterns = resources.get('Pattern') || new Dict();
- // TODO(mduan): pass array of knownCommands rather than OP_MAP
- // dictionary
- var parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
-
- var promise = new LegacyPromise();
- var args = [];
+ // |operation| is an object with two fields:
+ //
+ // - |fn| is an out param.
+ //
+ // - |args| is an inout param. On entry, it should have one of two values.
+ //
+ // - An empty array. This indicates that the caller is providing the
+ // array in which the args will be stored in. The caller should use
+ // this value if it can reuse a single array for each call to read().
+ //
+ // - |null|. This indicates that the caller needs this function to create
+ // the array in which any args are stored in. If there are zero args,
+ // this function will leave |operation.args| as |null| (thus avoiding
+ // allocations that would occur if we used an empty array to represent
+ // zero arguments). Otherwise, it will replace |null| with a new array
+ // containing the arguments. The caller should use this value if it
+ // cannot reuse an array for each call to read().
+ //
+ // These two modes are present because this function is very hot and so
+ // avoiding allocations where possible is worthwhile.
+ //
+ read: function EvaluatorPreprocessor_read(operation) {
+ var args = operation.args;
while (true) {
-
- var obj = parser.getObj();
-
- if (isEOF(obj)) {
- break;
- }
-
+ var obj = this.parser.getObj();
if (isCmd(obj)) {
var cmd = obj.cmd;
-
// Check that the command is valid
var opSpec = OP_MAP[cmd];
if (!opSpec) {
@@ -15083,1122 +12650,1426 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var fn = opSpec.id;
+ var numArgs = opSpec.numArgs;
+ var argsLength = args !== null ? args.length : 0;
- // Validate the number of arguments for the command
- if (opSpec.variableArgs) {
- if (args.length > opSpec.numArgs) {
- info('Command ' + fn + ': expected [0,' + opSpec.numArgs +
- '] args, but received ' + args.length + ' args');
+ if (!opSpec.variableArgs) {
+ // Postscript commands can be nested, e.g. /F2 /GS2 gs 5.711 Tf
+ if (argsLength !== numArgs) {
+ var nonProcessedArgs = this.nonProcessedArgs;
+ while (argsLength > numArgs) {
+ nonProcessedArgs.push(args.shift());
+ argsLength--;
+ }
+ while (argsLength < numArgs && nonProcessedArgs.length !== 0) {
+ if (!args) {
+ args = [];
+ }
+ args.unshift(nonProcessedArgs.pop());
+ argsLength++;
+ }
}
- } else {
- if (args.length < opSpec.numArgs) {
+
+ if (argsLength < numArgs) {
// If we receive too few args, it's not possible to possible
// to execute the command, so skip the command
info('Command ' + fn + ': because expected ' +
- opSpec.numArgs + ' args, but received ' + args.length +
+ numArgs + ' args, but received ' + argsLength +
' args; skipping');
- args = [];
+ args = null;
continue;
- } else if (args.length > opSpec.numArgs) {
- info('Command ' + fn + ': expected ' + opSpec.numArgs +
- ' args, but received ' + args.length + ' args');
}
+ } else if (argsLength > numArgs) {
+ info('Command ' + fn + ': expected [0,' + numArgs +
+ '] args, but received ' + argsLength + ' args');
}
// TODO figure out how to type-check vararg functions
+ this.preprocessCommand(fn, args);
- switch (fn) {
- case OPS.setStrokeColorN:
- case OPS.setFillColorN:
- if (args[args.length - 1].code) {
- break;
- }
- // compile tiling patterns
- var patternName = args[args.length - 1];
- // SCN/scn applies patterns along with normal colors
- var pattern;
- if (isName(patternName) &&
- (pattern = patterns.get(patternName.name))) {
-
- var dict = isStream(pattern) ? pattern.dict : pattern;
- var typeNum = dict.get('PatternType');
-
- if (typeNum == TILING_PATTERN) {
- self.handleTilingType(fn, args, resources, pattern, dict,
- operatorList);
- args = [];
- continue;
- } else if (typeNum == SHADING_PATTERN) {
- var shading = dict.get('Shading');
- var matrix = dict.get('Matrix');
- var pattern = Pattern.parseShading(shading, matrix, xref,
- resources);
- args = pattern.getIR();
- } else {
- error('Unkown PatternType ' + typeNum);
- }
- }
- break;
- case OPS.paintXObject:
- if (args[0].code) {
- break;
- }
- // eagerly compile XForm objects
- var name = args[0].name;
- var xobj = xobjs.get(name);
- if (xobj) {
- assertWellFormed(
- isStream(xobj), 'XObject should be a stream');
-
- var type = xobj.dict.get('Subtype');
- assertWellFormed(
- isName(type),
- 'XObject should have a Name subtype'
- );
-
- if ('Form' == type.name) {
- self.buildFormXObject(resources, xobj, null, operatorList);
- args = [];
- continue;
- } else if ('Image' == type.name) {
- self.buildPaintImageXObject(resources, xobj, false,
- operatorList);
- args = [];
- continue;
- } else {
- error('Unhandled XObject subtype ' + type.name);
- }
- }
- break;
- case OPS.setFont:
- // eagerly collect all fonts
- var loadedName = self.handleSetFont(resources, args, null,
- operatorList);
- operatorList.addDependency(loadedName);
- args[0] = loadedName;
- break;
- case OPS.endInlineImage:
- self.buildPaintImageXObject(resources, args[0], true,
- operatorList);
- args = [];
- continue;
- case OPS.save:
- var old = this.state;
- this.stateStack.push(this.state);
- this.state = old.clone();
- break;
- case OPS.restore:
- var prev = this.stateStack.pop();
- if (prev) {
- this.state = prev;
- }
- break;
- case OPS.showText:
- args[0] = this.handleText(args[0]);
- break;
- case OPS.showSpacedText:
- var arr = args[0];
- var arrLength = arr.length;
- for (var i = 0; i < arrLength; ++i) {
- if (isString(arr[i])) {
- arr[i] = this.handleText(arr[i]);
- }
- }
- break;
- case OPS.nextLineShowText:
- args[0] = this.handleText(args[0]);
- break;
- case OPS.nextLineSetSpacingShowText:
- args[2] = this.handleText(args[2]);
- break;
- case OPS.setTextRenderingMode:
- this.state.textRenderingMode = args[0];
- break;
- // Parse the ColorSpace data to a raw format.
- case OPS.setFillColorSpace:
- case OPS.setStrokeColorSpace:
- args = [ColorSpace.parseToIR(args[0], xref, resources)];
- break;
- case OPS.shadingFill:
- var shadingRes = resources.get('Shading');
- if (!shadingRes)
- error('No shading resource found');
-
- var shading = shadingRes.get(args[0].name);
- if (!shading)
- error('No shading object found');
-
- var shadingFill = Pattern.parseShading(
- shading, null, xref, resources);
- var patternIR = shadingFill.getIR();
- args = [patternIR];
- fn = OPS.shadingFill;
- break;
- case OPS.setGState:
- var dictName = args[0];
- var extGState = resources.get('ExtGState');
-
- if (!isDict(extGState) || !extGState.has(dictName.name))
- break;
-
- var gState = extGState.get(dictName.name);
- self.setGState(resources, gState, operatorList);
- args = [];
- continue;
- } // switch
-
- operatorList.addOp(fn, args);
- args = [];
- parser.saveState();
- } else if (obj !== null && obj !== undefined) {
- args.push(obj instanceof Dict ? obj.getAll() : obj);
- assertWellFormed(args.length <= 33, 'Too many arguments');
- }
- }
-
- return operatorList;
- },
-
- getTextContent: function PartialEvaluator_getTextContent(
- stream, resources, state) {
-
- var bidiTexts;
- var SPACE_FACTOR = 0.35;
- var MULTI_SPACE_FACTOR = 1.5;
- var textState;
-
- if (!state) {
- textState = new TextState();
- bidiTexts = [];
- state = {
- textState: textState,
- bidiTexts: bidiTexts
- };
- } else {
- bidiTexts = state.bidiTexts;
- textState = state.textState;
- }
-
- var self = this;
- var xref = this.xref;
-
- function handleSetFont(fontName, fontRef) {
- return self.loadFont(fontName, fontRef, xref, resources, null);
- }
-
- resources = xref.fetchIfRef(resources) || new Dict();
- // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
- var xobjs = null;
-
- var parser = new Parser(new Lexer(stream), false);
- var res = resources;
- var args = [], obj;
-
- var chunk = '';
- var font = null;
- var charSpace = 0, wordSpace = 0;
- while (!isEOF(obj = parser.getObj())) {
- if (isCmd(obj)) {
- var cmd = obj.cmd;
- switch (cmd) {
- // TODO: Add support for SAVE/RESTORE and XFORM here.
- case 'Tf':
- font = handleSetFont(args[0].name).translated;
- textState.fontSize = args[1];
- break;
- case 'Ts':
- textState.textRise = args[0];
- break;
- case 'Tz':
- textState.textHScale = args[0] / 100;
- break;
- case 'TL':
- textState.leading = args[0];
- break;
- case 'Td':
- textState.translateTextMatrix(args[0], args[1]);
- break;
- case 'TD':
- textState.leading = -args[1];
- textState.translateTextMatrix(args[0], args[1]);
- break;
- case 'T*':
- textState.translateTextMatrix(0, -textState.leading);
- break;
- case 'Tm':
- textState.setTextMatrix(args[0], args[1],
- args[2], args[3], args[4], args[5]);
- break;
- case 'Tc':
- charSpace = args[0];
- break;
- case 'Tw':
- wordSpace = args[0];
- break;
- case 'q':
- textState.push();
- break;
- case 'Q':
- textState.pop();
- break;
- case 'BT':
- textState.initialiseTextObj();
- break;
- case 'cm':
- textState.transformCTM(args[0], args[1], args[2],
- args[3], args[4], args[5]);
- break;
- case 'TJ':
- var items = args[0];
- for (var j = 0, jj = items.length; j < jj; j++) {
- if (typeof items[j] === 'string') {
- chunk += fontCharsToUnicode(items[j], font);
- } else if (items[j] < 0 && font.spaceWidth > 0) {
- var fakeSpaces = -items[j] / font.spaceWidth;
- if (fakeSpaces > MULTI_SPACE_FACTOR) {
- fakeSpaces = Math.round(fakeSpaces);
- while (fakeSpaces--) {
- chunk += ' ';
- }
- } else if (fakeSpaces > SPACE_FACTOR) {
- chunk += ' ';
- }
- }
- }
- break;
- case 'Tj':
- chunk += fontCharsToUnicode(args[0], font);
- break;
- case '\'':
- // For search, adding a extra white space for line breaks would be
- // better here, but that causes too much spaces in the
- // text-selection divs.
- chunk += fontCharsToUnicode(args[0], font);
- break;
- case '"':
- // Note comment in "'"
- chunk += fontCharsToUnicode(args[2], font);
- break;
- case 'Do':
- // Set the chunk such that the following if won't add something
- // to the state.
- chunk = '';
-
- if (args[0].code) {
- break;
- }
-
- if (!xobjs) {
- xobjs = resources.get('XObject') || new Dict();
- }
-
- var name = args[0].name;
- var xobj = xobjs.get(name);
- if (!xobj)
- break;
- assertWellFormed(isStream(xobj), 'XObject should be a stream');
-
- var type = xobj.dict.get('Subtype');
- assertWellFormed(
- isName(type),
- 'XObject should have a Name subtype'
- );
-
- if ('Form' !== type.name)
- break;
-
- state = this.getTextContent(
- xobj,
- xobj.dict.get('Resources') || resources,
- state
- );
- break;
- case 'gs':
- var dictName = args[0];
- var extGState = resources.get('ExtGState');
-
- if (!isDict(extGState) || !extGState.has(dictName.name))
- break;
-
- var gsState = extGState.get(dictName.name);
-
- for (var i = 0; i < gsState.length; i++) {
- if (gsState[i] === 'Font') {
- font = handleSetFont(args[0].name).translated;
- }
- }
- break;
- } // switch
-
- if (chunk !== '') {
- var bidiText = PDFJS.bidi(chunk, -1, font.vertical);
- var renderParams = textState.calcRenderParams();
- bidiText.x = renderParams.renderMatrix[4] - (textState.fontSize *
- renderParams.vScale * Math.sin(renderParams.angle));
- bidiText.y = renderParams.renderMatrix[5] + (textState.fontSize *
- renderParams.vScale * Math.cos(renderParams.angle));
- if (bidiText.dir == 'ttb') {
- bidiText.x += renderParams.vScale / 2;
- bidiText.y -= renderParams.vScale;
- }
- bidiTexts.push(bidiText);
-
- chunk = '';
- }
-
- args = [];
- } else if (obj !== null && obj !== undefined) {
- assertWellFormed(args.length <= 33, 'Too many arguments');
- args.push(obj);
- }
- } // while
-
- return state;
- },
-
- extractDataStructures: function
- partialEvaluatorExtractDataStructures(dict, baseDict,
- xref, properties) {
- // 9.10.2
- var toUnicode = dict.get('ToUnicode') ||
- baseDict.get('ToUnicode');
- if (toUnicode)
- properties.toUnicode = this.readToUnicode(toUnicode, xref, properties);
-
- if (properties.composite) {
- // CIDSystemInfo helps to match CID to glyphs
- var cidSystemInfo = dict.get('CIDSystemInfo');
- if (isDict(cidSystemInfo)) {
- properties.cidSystemInfo = {
- registry: cidSystemInfo.get('Registry'),
- ordering: cidSystemInfo.get('Ordering'),
- supplement: cidSystemInfo.get('Supplement')
- };
- }
-
- var cidToGidMap = dict.get('CIDToGIDMap');
- if (isStream(cidToGidMap))
- properties.cidToGidMap = this.readCidToGidMap(cidToGidMap);
- }
-
- // Based on 9.6.6 of the spec the encoding can come from multiple places
- // but should be prioritized in the following order:
- // 1. Encoding dictionary
- // 2. Encoding within font file (Type1 or Type1C)
- // 3. Default (depends on font type)
- // Differences applied to the above.
- // Note: we don't fill in the encoding from the font file(2) here but use
- // the flag overridableEncoding to signal that the font can override the
- // encoding if it has one built in.
- var overridableEncoding = true;
- var hasEncoding = false;
- var flags = properties.flags;
- var differences = [];
- var baseEncoding = properties.type === 'TrueType' ?
- Encodings.WinAnsiEncoding :
- Encodings.StandardEncoding;
- // The Symbolic attribute can be misused for regular fonts
- // Heuristic: we have to check if the font is a standard one or
- // toUnicode is provided
- if (!!(flags & FontFlags.Symbolic)) {
- baseEncoding = !properties.file && !properties.toUnicode ?
- Encodings.SymbolSetEncoding : Encodings.MacRomanEncoding;
- }
- if (dict.has('Encoding')) {
- var encoding = dict.get('Encoding');
- if (isDict(encoding)) {
- var baseName = encoding.get('BaseEncoding');
- if (baseName) {
- overridableEncoding = false;
- hasEncoding = true;
- baseEncoding = Encodings[baseName.name];
- }
-
- // Load the differences between the base and original
- if (encoding.has('Differences')) {
- hasEncoding = true;
- var diffEncoding = encoding.get('Differences');
- var index = 0;
- for (var j = 0, jj = diffEncoding.length; j < jj; j++) {
- var data = diffEncoding[j];
- if (isNum(data))
- index = data;
- else
- differences[index++] = data.name;
- }
- }
- } else if (isName(encoding)) {
- overridableEncoding = false;
- hasEncoding = true;
- baseEncoding = Encodings[encoding.name];
+ operation.fn = fn;
+ operation.args = args;
+ return true;
} else {
- error('Encoding is not a Name nor a Dict');
+ if (isEOF(obj)) {
+ return false; // no more commands
+ }
+ // argument
+ if (obj !== null) {
+ if (!args) {
+ args = [];
+ }
+ args.push((obj instanceof Dict ? obj.getAll() : obj));
+ assert(args.length <= 33, 'Too many arguments');
+ }
}
}
-
- properties.differences = differences;
- properties.baseEncoding = baseEncoding;
- properties.hasEncoding = hasEncoding;
- properties.overridableEncoding = overridableEncoding;
},
- readToUnicode: function PartialEvaluator_readToUnicode(toUnicode, xref,
- properties) {
- var cmapObj = toUnicode;
- var charToUnicode = [];
- if (isName(cmapObj)) {
- var isIdentityMap = cmapObj.name.substr(0, 9) == 'Identity-';
- if (!isIdentityMap)
- error('ToUnicode file cmap translation not implemented');
- } else if (isStream(cmapObj)) {
- var cmap = CMapFactory.create(cmapObj).map;
- // Convert UTF-16BE
- for (var i in cmap) {
- var token = cmap[i];
- var str = [];
- for (var k = 0; k < token.length; k += 2) {
- var w1 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
- if ((w1 & 0xF800) !== 0xD800) { // w1 < 0xD800 || w1 > 0xDFFF
- str.push(w1);
- continue;
- }
- k += 2;
- var w2 = (token.charCodeAt(k) << 8) | token.charCodeAt(k + 1);
- str.push(((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000);
- }
- cmap[i] = String.fromCharCode.apply(String, str);
- }
- return cmap;
- }
- return charToUnicode;
- },
- readCidToGidMap: function PartialEvaluator_readCidToGidMap(cidToGidStream) {
- // Extract the encoding from the CIDToGIDMap
- var glyphsData = cidToGidStream.getBytes();
-
- // Set encoding 0 to later verify the font has an encoding
- var result = [];
- for (var j = 0, jj = glyphsData.length; j < jj; j++) {
- var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
- if (glyphID === 0)
- continue;
-
- var code = j >> 1;
- result[code] = glyphID;
- }
- return result;
- },
-
- extractWidths: function PartialEvaluator_extractWidths(dict,
- xref,
- descriptor,
- properties) {
- var glyphsWidths = [];
- var defaultWidth = 0;
- var glyphsVMetrics = [];
- var defaultVMetrics;
- if (properties.composite) {
- defaultWidth = dict.get('DW') || 1000;
-
- var widths = dict.get('W');
- if (widths) {
- for (var i = 0, ii = widths.length; i < ii; i++) {
- var start = widths[i++];
- var code = xref.fetchIfRef(widths[i]);
- if (isArray(code)) {
- for (var j = 0, jj = code.length; j < jj; j++)
- glyphsWidths[start++] = code[j];
- } else {
- var width = widths[++i];
- for (var j = start; j <= code; j++)
- glyphsWidths[j] = width;
- }
- }
- }
-
- if (properties.vertical) {
- var vmetrics = dict.get('DW2') || [880, -1000];
- defaultVMetrics = [vmetrics[1], defaultWidth * 0.5, vmetrics[0]];
- vmetrics = dict.get('W2');
- if (vmetrics) {
- for (var i = 0, ii = vmetrics.length; i < ii; i++) {
- var start = vmetrics[i++];
- var code = xref.fetchIfRef(vmetrics[i]);
- if (isArray(code)) {
- for (var j = 0, jj = code.length; j < jj; j++)
- glyphsVMetrics[start++] = [code[j++], code[j++], code[j]];
- } else {
- var vmetric = [vmetrics[++i], vmetrics[++i], vmetrics[++i]];
- for (var j = start; j <= code; j++)
- glyphsVMetrics[j] = vmetric;
- }
- }
- }
- }
- } else {
- var firstChar = properties.firstChar;
- var widths = dict.get('Widths');
- if (widths) {
- var j = firstChar;
- for (var i = 0, ii = widths.length; i < ii; i++)
- glyphsWidths[j++] = widths[i];
- defaultWidth = parseFloat(descriptor.get('MissingWidth')) || 0;
- } else {
- // Trying get the BaseFont metrics (see comment above).
- var baseFontName = dict.get('BaseFont');
- if (isName(baseFontName)) {
- var metrics = this.getBaseFontMetrics(baseFontName.name);
-
- glyphsWidths = metrics.widths;
- defaultWidth = metrics.defaultWidth;
- }
- }
- }
-
- // Heuristic: detection of monospace font by checking all non-zero widths
- var isMonospace = true, firstWidth = defaultWidth;
- for (var glyph in glyphsWidths) {
- var glyphWidth = glyphsWidths[glyph];
- if (!glyphWidth)
- continue;
- if (!firstWidth) {
- firstWidth = glyphWidth;
- continue;
- }
- if (firstWidth != glyphWidth) {
- isMonospace = false;
+ preprocessCommand:
+ function EvaluatorPreprocessor_preprocessCommand(fn, args) {
+ switch (fn | 0) {
+ case OPS.save:
+ this.stateManager.save();
+ break;
+ case OPS.restore:
+ this.stateManager.restore();
+ break;
+ case OPS.transform:
+ this.stateManager.transform(args);
break;
- }
- }
- if (isMonospace)
- properties.flags |= FontFlags.FixedPitch;
-
- properties.defaultWidth = defaultWidth;
- properties.widths = glyphsWidths;
- properties.defaultVMetrics = defaultVMetrics;
- properties.vmetrics = glyphsVMetrics;
- },
-
- isSerifFont: function PartialEvaluator_isSerifFont(baseFontName) {
-
- // Simulating descriptor flags attribute
- var fontNameWoStyle = baseFontName.split('-')[0];
- return (fontNameWoStyle in serifFonts) ||
- (fontNameWoStyle.search(/serif/gi) !== -1);
- },
-
- getBaseFontMetrics: function PartialEvaluator_getBaseFontMetrics(name) {
- var defaultWidth = 0, widths = [], monospace = false;
-
- var lookupName = stdFontMap[name] || name;
-
- if (!(lookupName in Metrics)) {
- // Use default fonts for looking up font metrics if the passed
- // font is not a base font
- if (this.isSerifFont(name)) {
- lookupName = 'Times-Roman';
- } else {
- lookupName = 'Helvetica';
- }
- }
- var glyphWidths = Metrics[lookupName];
-
- if (isNum(glyphWidths)) {
- defaultWidth = glyphWidths;
- monospace = true;
- } else {
- widths = glyphWidths;
- }
-
- return {
- defaultWidth: defaultWidth,
- monospace: monospace,
- widths: widths
- };
- },
-
- translateFont: function PartialEvaluator_translateFont(dict,
- xref) {
- var baseDict = dict;
- var type = dict.get('Subtype');
- assertWellFormed(isName(type), 'invalid font Subtype');
-
- var composite = false;
- if (type.name == 'Type0') {
- // If font is a composite
- // - get the descendant font
- // - set the type according to the descendant font
- // - get the FontDescriptor from the descendant font
- var df = dict.get('DescendantFonts');
- if (!df)
- error('Descendant fonts are not specified');
-
- dict = isArray(df) ? xref.fetchIfRef(df[0]) : df;
-
- type = dict.get('Subtype');
- assertWellFormed(isName(type), 'invalid font Subtype');
- composite = true;
- }
- var maxCharIndex = composite ? 0xFFFF : 0xFF;
-
- var descriptor = dict.get('FontDescriptor');
- if (!descriptor) {
- if (type.name == 'Type3') {
- // FontDescriptor is only required for Type3 fonts when the document
- // is a tagged pdf. Create a barbebones one to get by.
- descriptor = new Dict();
- descriptor.set('FontName', new Name(type.name));
- } else {
- // Before PDF 1.5 if the font was one of the base 14 fonts, having a
- // FontDescriptor was not required.
- // This case is here for compatibility.
- var baseFontName = dict.get('BaseFont');
- if (!isName(baseFontName))
- error('Base font is not specified');
-
- // Using base font name as a font name.
- baseFontName = baseFontName.name.replace(/[,_]/g, '-');
- var metrics = this.getBaseFontMetrics(baseFontName);
-
- // Simulating descriptor flags attribute
- var fontNameWoStyle = baseFontName.split('-')[0];
- var flags = (
- this.isSerifFont(fontNameWoStyle) ? FontFlags.Serif : 0) |
- (metrics.monospace ? FontFlags.FixedPitch : 0) |
- (symbolsFonts[fontNameWoStyle] ? FontFlags.Symbolic :
- FontFlags.Nonsymbolic);
-
- var properties = {
- type: type.name,
- widths: metrics.widths,
- defaultWidth: metrics.defaultWidth,
- flags: flags,
- firstChar: 0,
- lastChar: maxCharIndex
- };
- this.extractDataStructures(dict, dict, xref, properties);
-
- return new Font(baseFontName, null, properties);
- }
- }
-
- // According to the spec if 'FontDescriptor' is declared, 'FirstChar',
- // 'LastChar' and 'Widths' should exist too, but some PDF encoders seem
- // to ignore this rule when a variant of a standart font is used.
- // TODO Fill the width array depending on which of the base font this is
- // a variant.
- var firstChar = dict.get('FirstChar') || 0;
- var lastChar = dict.get('LastChar') || maxCharIndex;
-
- var fontName = descriptor.get('FontName');
- var baseFont = dict.get('BaseFont');
- // Some bad pdf's have a string as the font name.
- if (isString(fontName)) {
- fontName = new Name(fontName);
- }
- if (isString(baseFont)) {
- baseFont = new Name(baseFont);
- }
-
- if (type.name !== 'Type3') {
- var fontNameStr = fontName && fontName.name;
- var baseFontStr = baseFont && baseFont.name;
- if (fontNameStr !== baseFontStr) {
- info('The FontDescriptor\'s FontName is "' + fontNameStr +
- '" but should be the same as the Font\'s BaseFont "' +
- baseFontStr + '"');
- }
- }
- fontName = fontName || baseFont;
-
- assertWellFormed(isName(fontName), 'invalid font name');
-
- var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
- if (fontFile) {
- if (fontFile.dict) {
- var subtype = fontFile.dict.get('Subtype');
- if (subtype)
- subtype = subtype.name;
-
- var length1 = fontFile.dict.get('Length1');
-
- var length2 = fontFile.dict.get('Length2');
- }
- }
-
- var properties = {
- type: type.name,
- subtype: subtype,
- file: fontFile,
- length1: length1,
- length2: length2,
- loadedName: baseDict.loadedName,
- composite: composite,
- wideChars: composite,
- fixedPitch: false,
- fontMatrix: dict.get('FontMatrix') || FONT_IDENTITY_MATRIX,
- firstChar: firstChar || 0,
- lastChar: lastChar || maxCharIndex,
- bbox: descriptor.get('FontBBox'),
- ascent: descriptor.get('Ascent'),
- descent: descriptor.get('Descent'),
- xHeight: descriptor.get('XHeight'),
- capHeight: descriptor.get('CapHeight'),
- flags: descriptor.get('Flags'),
- italicAngle: descriptor.get('ItalicAngle'),
- coded: false
- };
-
- if (composite) {
- var cidEncoding = baseDict.get('Encoding');
- if (isName(cidEncoding)) {
- properties.cidEncoding = cidEncoding.name;
- properties.vertical = /-V$/.test(cidEncoding.name);
- }
- properties.cmap = CMapFactory.create(cidEncoding);
- }
- this.extractWidths(dict, xref, descriptor, properties);
- this.extractDataStructures(dict, baseDict, xref, properties);
-
- if (type.name === 'Type3') {
- properties.coded = true;
- }
-
- return new Font(fontName.name, fontFile, properties);
- }
- };
-
- PartialEvaluator.optimizeQueue =
- function PartialEvaluator_optimizeQueue(queue) {
-
- function squash(array, index, howMany, element) {
- if (isArray(array)) {
- array.splice(index, howMany, element);
- } else {
- // Replace the element.
- array[index] = element;
- // Shift everything after the element up.
- var sub = array.subarray(index + howMany);
- array.set(sub, index + 1);
- }
- }
-
- var fnArray = queue.fnArray, argsArray = queue.argsArray;
- // grouping paintInlineImageXObject's into paintInlineImageXObjectGroup
- // searching for (save, transform, paintInlineImageXObject, restore)+
- var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10;
- var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200;
- var MAX_WIDTH = 1000;
- var IMAGE_PADDING = 1;
- for (var i = 0, ii = argsArray.length; i < ii; i++) {
- if (fnArray[i] === OPS.paintInlineImageXObject &&
- fnArray[i - 2] === OPS.save && fnArray[i - 1] === OPS.transform &&
- fnArray[i + 1] === OPS.restore) {
- var j = i - 2;
- for (i += 2; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
- }
- var count = Math.min((i - j) >> 2,
- MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);
- if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {
- continue;
- }
- // assuming that heights of those image is too small (~1 pixel)
- // packing as much as possible by lines
- var maxX = 0;
- var map = [], maxLineHeight = 0;
- var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;
- for (var q = 0; q < count; q++) {
- var transform = argsArray[j + (q << 2) + 1];
- var img = argsArray[j + (q << 2) + 2][0];
- if (currentX + img.width > MAX_WIDTH) {
- // starting new line
- maxX = Math.max(maxX, currentX);
- currentY += maxLineHeight + 2 * IMAGE_PADDING;
- currentX = 0;
- maxLineHeight = 0;
- }
- map.push({
- transform: transform,
- x: currentX, y: currentY,
- w: img.width, h: img.height
- });
- currentX += img.width + 2 * IMAGE_PADDING;
- maxLineHeight = Math.max(maxLineHeight, img.height);
- }
- var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING;
- var imgHeight = currentY + maxLineHeight + IMAGE_PADDING;
- var imgData = new Uint8Array(imgWidth * imgHeight * 4);
- var imgRowSize = imgWidth << 2;
- for (var q = 0; q < count; q++) {
- var data = argsArray[j + (q << 2) + 2][0].data;
- // copy image by lines and extends pixels into padding
- var rowSize = map[q].w << 2;
- var dataOffset = 0;
- var offset = (map[q].x + map[q].y * imgWidth) << 2;
- imgData.set(
- data.subarray(0, rowSize), offset - imgRowSize);
- for (var k = 0, kk = map[q].h; k < kk; k++) {
- imgData.set(
- data.subarray(dataOffset, dataOffset + rowSize), offset);
- dataOffset += rowSize;
- offset += imgRowSize;
- }
- imgData.set(
- data.subarray(dataOffset - rowSize, dataOffset), offset);
- while (offset >= 0) {
- data[offset - 4] = data[offset];
- data[offset - 3] = data[offset + 1];
- data[offset - 2] = data[offset + 2];
- data[offset - 1] = data[offset + 3];
- data[offset + rowSize] = data[offset + rowSize - 4];
- data[offset + rowSize + 1] = data[offset + rowSize - 3];
- data[offset + rowSize + 2] = data[offset + rowSize - 2];
- data[offset + rowSize + 3] = data[offset + rowSize - 1];
- offset -= imgRowSize;
- }
- }
- // replacing queue items
- squash(fnArray, j, count * 4, OPS.paintInlineImageXObjectGroup);
- argsArray.splice(j, count * 4,
- [{width: imgWidth, height: imgHeight, data: imgData}, map]);
- i = j;
- ii = argsArray.length;
- }
- }
- // grouping paintImageMaskXObject's into paintImageMaskXObjectGroup
- // searching for (save, transform, paintImageMaskXObject, restore)+
- var MIN_IMAGES_IN_MASKS_BLOCK = 10;
- var MAX_IMAGES_IN_MASKS_BLOCK = 100;
- for (var i = 0, ii = argsArray.length; i < ii; i++) {
- if (fnArray[i] === OPS.paintImageMaskXObject &&
- fnArray[i - 2] === OPS.save && fnArray[i - 1] === OPS.transform &&
- fnArray[i + 1] === OPS.restore) {
- var j = i - 2;
- for (i += 2; i < ii && fnArray[i - 4] === fnArray[i]; i++) {
- }
- var count = Math.min((i - j) >> 2,
- MAX_IMAGES_IN_MASKS_BLOCK);
- if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
- continue;
- }
- var images = [];
- for (var q = 0; q < count; q++) {
- var transform = argsArray[j + (q << 2) + 1];
- var maskParams = argsArray[j + (q << 2) + 2][0];
- images.push({data: maskParams.data, width: maskParams.width,
- height: maskParams.height, transform: transform});
- }
- // replacing queue items
- squash(fnArray, j, count * 4, OPS.paintImageMaskXObjectGroup);
- argsArray.splice(j, count * 4, [images]);
- i = j;
- ii = argsArray.length;
}
}
};
-
- return PartialEvaluator;
+ return EvaluatorPreprocessor;
})();
-var OperatorList = (function OperatorListClosure() {
- var CHUNK_SIZE = 100;
+var QueueOptimizer = (function QueueOptimizerClosure() {
+ function addState(parentState, pattern, fn) {
+ var state = parentState;
+ for (var i = 0, ii = pattern.length - 1; i < ii; i++) {
+ var item = pattern[i];
+ state = (state[item] || (state[item] = []));
+ }
+ state[pattern[pattern.length - 1]] = fn;
+ }
- function getTransfers(queue) {
- var transfers = [];
+ function handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
+ argsArray) {
+ // Handles special case of mainly LaTeX documents which use image masks to
+ // draw lines with the current fill style.
+ // 'count' groups of (save, transform, paintImageMaskXObject, restore)+
+ // have been found at iFirstSave.
+ var iFirstPIMXO = iFirstSave + 2;
+ for (var i = 0; i < count; i++) {
+ var arg = argsArray[iFirstPIMXO + 4 * i];
+ var imageMask = arg.length === 1 && arg[0];
+ if (imageMask && imageMask.width === 1 && imageMask.height === 1 &&
+ (!imageMask.data.length ||
+ (imageMask.data.length === 1 && imageMask.data[0] === 0))) {
+ fnArray[iFirstPIMXO + 4 * i] = OPS.paintSolidColorImageMask;
+ continue;
+ }
+ break;
+ }
+ return count - i;
+ }
+
+ var InitialState = [];
+
+ // This replaces (save, transform, paintInlineImageXObject, restore)+
+ // sequences with one |paintInlineImageXObjectGroup| operation.
+ addState(InitialState,
+ [OPS.save, OPS.transform, OPS.paintInlineImageXObject, OPS.restore],
+ function foundInlineImageGroup(context) {
+ var MIN_IMAGES_IN_INLINE_IMAGES_BLOCK = 10;
+ var MAX_IMAGES_IN_INLINE_IMAGES_BLOCK = 200;
+ var MAX_WIDTH = 1000;
+ var IMAGE_PADDING = 1;
+
+ var fnArray = context.fnArray, argsArray = context.argsArray;
+ var curr = context.iCurr;
+ var iFirstSave = curr - 3;
+ var iFirstTransform = curr - 2;
+ var iFirstPIIXO = curr - 1;
+
+ // Look for the quartets.
+ var i = iFirstSave + 4;
+ var ii = fnArray.length;
+ while (i + 3 < ii) {
+ if (fnArray[i] !== OPS.save ||
+ fnArray[i + 1] !== OPS.transform ||
+ fnArray[i + 2] !== OPS.paintInlineImageXObject ||
+ fnArray[i + 3] !== OPS.restore) {
+ break; // ops don't match
+ }
+ i += 4;
+ }
+
+ // At this point, i is the index of the first op past the last valid
+ // quartet.
+ var count = Math.min((i - iFirstSave) / 4,
+ MAX_IMAGES_IN_INLINE_IMAGES_BLOCK);
+ if (count < MIN_IMAGES_IN_INLINE_IMAGES_BLOCK) {
+ return i;
+ }
+
+ // assuming that heights of those image is too small (~1 pixel)
+ // packing as much as possible by lines
+ var maxX = 0;
+ var map = [], maxLineHeight = 0;
+ var currentX = IMAGE_PADDING, currentY = IMAGE_PADDING;
+ var q;
+ for (q = 0; q < count; q++) {
+ var transform = argsArray[iFirstTransform + (q << 2)];
+ var img = argsArray[iFirstPIIXO + (q << 2)][0];
+ if (currentX + img.width > MAX_WIDTH) {
+ // starting new line
+ maxX = Math.max(maxX, currentX);
+ currentY += maxLineHeight + 2 * IMAGE_PADDING;
+ currentX = 0;
+ maxLineHeight = 0;
+ }
+ map.push({
+ transform: transform,
+ x: currentX, y: currentY,
+ w: img.width, h: img.height
+ });
+ currentX += img.width + 2 * IMAGE_PADDING;
+ maxLineHeight = Math.max(maxLineHeight, img.height);
+ }
+ var imgWidth = Math.max(maxX, currentX) + IMAGE_PADDING;
+ var imgHeight = currentY + maxLineHeight + IMAGE_PADDING;
+ var imgData = new Uint8Array(imgWidth * imgHeight * 4);
+ var imgRowSize = imgWidth << 2;
+ for (q = 0; q < count; q++) {
+ var data = argsArray[iFirstPIIXO + (q << 2)][0].data;
+ // Copy image by lines and extends pixels into padding.
+ var rowSize = map[q].w << 2;
+ var dataOffset = 0;
+ var offset = (map[q].x + map[q].y * imgWidth) << 2;
+ imgData.set(data.subarray(0, rowSize), offset - imgRowSize);
+ for (var k = 0, kk = map[q].h; k < kk; k++) {
+ imgData.set(data.subarray(dataOffset, dataOffset + rowSize), offset);
+ dataOffset += rowSize;
+ offset += imgRowSize;
+ }
+ imgData.set(data.subarray(dataOffset - rowSize, dataOffset), offset);
+ while (offset >= 0) {
+ data[offset - 4] = data[offset];
+ data[offset - 3] = data[offset + 1];
+ data[offset - 2] = data[offset + 2];
+ data[offset - 1] = data[offset + 3];
+ data[offset + rowSize] = data[offset + rowSize - 4];
+ data[offset + rowSize + 1] = data[offset + rowSize - 3];
+ data[offset + rowSize + 2] = data[offset + rowSize - 2];
+ data[offset + rowSize + 3] = data[offset + rowSize - 1];
+ offset -= imgRowSize;
+ }
+ }
+
+ // Replace queue items.
+ fnArray.splice(iFirstSave, count * 4, OPS.paintInlineImageXObjectGroup);
+ argsArray.splice(iFirstSave, count * 4,
+ [{ width: imgWidth, height: imgHeight, kind: ImageKind.RGBA_32BPP,
+ data: imgData }, map]);
+
+ return iFirstSave + 1;
+ });
+
+ // This replaces (save, transform, paintImageMaskXObject, restore)+
+ // sequences with one |paintImageMaskXObjectGroup| or one
+ // |paintImageMaskXObjectRepeat| operation.
+ addState(InitialState,
+ [OPS.save, OPS.transform, OPS.paintImageMaskXObject, OPS.restore],
+ function foundImageMaskGroup(context) {
+ var MIN_IMAGES_IN_MASKS_BLOCK = 10;
+ var MAX_IMAGES_IN_MASKS_BLOCK = 100;
+ var MAX_SAME_IMAGES_IN_MASKS_BLOCK = 1000;
+
+ var fnArray = context.fnArray, argsArray = context.argsArray;
+ var curr = context.iCurr;
+ var iFirstSave = curr - 3;
+ var iFirstTransform = curr - 2;
+ var iFirstPIMXO = curr - 1;
+
+ // Look for the quartets.
+ var i = iFirstSave + 4;
+ var ii = fnArray.length;
+ while (i + 3 < ii) {
+ if (fnArray[i] !== OPS.save ||
+ fnArray[i + 1] !== OPS.transform ||
+ fnArray[i + 2] !== OPS.paintImageMaskXObject ||
+ fnArray[i + 3] !== OPS.restore) {
+ break; // ops don't match
+ }
+ i += 4;
+ }
+
+ // At this point, i is the index of the first op past the last valid
+ // quartet.
+ var count = (i - iFirstSave) / 4;
+ count = handlePaintSolidColorImageMask(iFirstSave, count, fnArray,
+ argsArray);
+ if (count < MIN_IMAGES_IN_MASKS_BLOCK) {
+ return i;
+ }
+
+ var q;
+ var isSameImage = false;
+ var iTransform, transformArgs;
+ var firstPIMXOArg0 = argsArray[iFirstPIMXO][0];
+ if (argsArray[iFirstTransform][1] === 0 &&
+ argsArray[iFirstTransform][2] === 0) {
+ isSameImage = true;
+ var firstTransformArg0 = argsArray[iFirstTransform][0];
+ var firstTransformArg3 = argsArray[iFirstTransform][3];
+ iTransform = iFirstTransform + 4;
+ var iPIMXO = iFirstPIMXO + 4;
+ for (q = 1; q < count; q++, iTransform += 4, iPIMXO += 4) {
+ transformArgs = argsArray[iTransform];
+ if (argsArray[iPIMXO][0] !== firstPIMXOArg0 ||
+ transformArgs[0] !== firstTransformArg0 ||
+ transformArgs[1] !== 0 ||
+ transformArgs[2] !== 0 ||
+ transformArgs[3] !== firstTransformArg3) {
+ if (q < MIN_IMAGES_IN_MASKS_BLOCK) {
+ isSameImage = false;
+ } else {
+ count = q;
+ }
+ break; // different image or transform
+ }
+ }
+ }
+
+ if (isSameImage) {
+ count = Math.min(count, MAX_SAME_IMAGES_IN_MASKS_BLOCK);
+ var positions = new Float32Array(count * 2);
+ iTransform = iFirstTransform;
+ for (q = 0; q < count; q++, iTransform += 4) {
+ transformArgs = argsArray[iTransform];
+ positions[(q << 1)] = transformArgs[4];
+ positions[(q << 1) + 1] = transformArgs[5];
+ }
+
+ // Replace queue items.
+ fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectRepeat);
+ argsArray.splice(iFirstSave, count * 4,
+ [firstPIMXOArg0, firstTransformArg0, firstTransformArg3, positions]);
+ } else {
+ count = Math.min(count, MAX_IMAGES_IN_MASKS_BLOCK);
+ var images = [];
+ for (q = 0; q < count; q++) {
+ transformArgs = argsArray[iFirstTransform + (q << 2)];
+ var maskParams = argsArray[iFirstPIMXO + (q << 2)][0];
+ images.push({ data: maskParams.data, width: maskParams.width,
+ height: maskParams.height,
+ transform: transformArgs });
+ }
+
+ // Replace queue items.
+ fnArray.splice(iFirstSave, count * 4, OPS.paintImageMaskXObjectGroup);
+ argsArray.splice(iFirstSave, count * 4, [images]);
+ }
+
+ return iFirstSave + 1;
+ });
+
+ // This replaces (save, transform, paintImageXObject, restore)+ sequences
+ // with one paintImageXObjectRepeat operation, if the |transform| and
+ // |paintImageXObjectRepeat| ops are appropriate.
+ addState(InitialState,
+ [OPS.save, OPS.transform, OPS.paintImageXObject, OPS.restore],
+ function (context) {
+ var MIN_IMAGES_IN_BLOCK = 3;
+ var MAX_IMAGES_IN_BLOCK = 1000;
+
+ var fnArray = context.fnArray, argsArray = context.argsArray;
+ var curr = context.iCurr;
+ var iFirstSave = curr - 3;
+ var iFirstTransform = curr - 2;
+ var iFirstPIXO = curr - 1;
+ var iFirstRestore = curr;
+
+ if (argsArray[iFirstTransform][1] !== 0 ||
+ argsArray[iFirstTransform][2] !== 0) {
+ return iFirstRestore + 1; // transform has the wrong form
+ }
+
+ // Look for the quartets.
+ var firstPIXOArg0 = argsArray[iFirstPIXO][0];
+ var firstTransformArg0 = argsArray[iFirstTransform][0];
+ var firstTransformArg3 = argsArray[iFirstTransform][3];
+ var i = iFirstSave + 4;
+ var ii = fnArray.length;
+ while (i + 3 < ii) {
+ if (fnArray[i] !== OPS.save ||
+ fnArray[i + 1] !== OPS.transform ||
+ fnArray[i + 2] !== OPS.paintImageXObject ||
+ fnArray[i + 3] !== OPS.restore) {
+ break; // ops don't match
+ }
+ if (argsArray[i + 1][0] !== firstTransformArg0 ||
+ argsArray[i + 1][1] !== 0 ||
+ argsArray[i + 1][2] !== 0 ||
+ argsArray[i + 1][3] !== firstTransformArg3) {
+ break; // transforms don't match
+ }
+ if (argsArray[i + 2][0] !== firstPIXOArg0) {
+ break; // images don't match
+ }
+ i += 4;
+ }
+
+ // At this point, i is the index of the first op past the last valid
+ // quartet.
+ var count = Math.min((i - iFirstSave) / 4, MAX_IMAGES_IN_BLOCK);
+ if (count < MIN_IMAGES_IN_BLOCK) {
+ return i;
+ }
+
+ // Extract the (x,y) positions from all of the matching transforms.
+ var positions = new Float32Array(count * 2);
+ var iTransform = iFirstTransform;
+ for (var q = 0; q < count; q++, iTransform += 4) {
+ var transformArgs = argsArray[iTransform];
+ positions[(q << 1)] = transformArgs[4];
+ positions[(q << 1) + 1] = transformArgs[5];
+ }
+
+ // Replace queue items.
+ var args = [firstPIXOArg0, firstTransformArg0, firstTransformArg3,
+ positions];
+ fnArray.splice(iFirstSave, count * 4, OPS.paintImageXObjectRepeat);
+ argsArray.splice(iFirstSave, count * 4, args);
+
+ return iFirstSave + 1;
+ });
+
+ // This replaces (beginText, setFont, setTextMatrix, showText, endText)+
+ // sequences with (beginText, setFont, (setTextMatrix, showText)+, endText)+
+ // sequences, if the font for each one is the same.
+ addState(InitialState,
+ [OPS.beginText, OPS.setFont, OPS.setTextMatrix, OPS.showText, OPS.endText],
+ function (context) {
+ var MIN_CHARS_IN_BLOCK = 3;
+ var MAX_CHARS_IN_BLOCK = 1000;
+
+ var fnArray = context.fnArray, argsArray = context.argsArray;
+ var curr = context.iCurr;
+ var iFirstBeginText = curr - 4;
+ var iFirstSetFont = curr - 3;
+ var iFirstSetTextMatrix = curr - 2;
+ var iFirstShowText = curr - 1;
+ var iFirstEndText = curr;
+
+ // Look for the quintets.
+ var firstSetFontArg0 = argsArray[iFirstSetFont][0];
+ var firstSetFontArg1 = argsArray[iFirstSetFont][1];
+ var i = iFirstBeginText + 5;
+ var ii = fnArray.length;
+ while (i + 4 < ii) {
+ if (fnArray[i] !== OPS.beginText ||
+ fnArray[i + 1] !== OPS.setFont ||
+ fnArray[i + 2] !== OPS.setTextMatrix ||
+ fnArray[i + 3] !== OPS.showText ||
+ fnArray[i + 4] !== OPS.endText) {
+ break; // ops don't match
+ }
+ if (argsArray[i + 1][0] !== firstSetFontArg0 ||
+ argsArray[i + 1][1] !== firstSetFontArg1) {
+ break; // fonts don't match
+ }
+ i += 5;
+ }
+
+ // At this point, i is the index of the first op past the last valid
+ // quintet.
+ var count = Math.min(((i - iFirstBeginText) / 5), MAX_CHARS_IN_BLOCK);
+ if (count < MIN_CHARS_IN_BLOCK) {
+ return i;
+ }
+
+ // If the preceding quintet is (, setFont, setTextMatrix,
+ // showText, endText), include that as well. (E.g. might be
+ // |dependency|.)
+ var iFirst = iFirstBeginText;
+ if (iFirstBeginText >= 4 &&
+ fnArray[iFirstBeginText - 4] === fnArray[iFirstSetFont] &&
+ fnArray[iFirstBeginText - 3] === fnArray[iFirstSetTextMatrix] &&
+ fnArray[iFirstBeginText - 2] === fnArray[iFirstShowText] &&
+ fnArray[iFirstBeginText - 1] === fnArray[iFirstEndText] &&
+ argsArray[iFirstBeginText - 4][0] === firstSetFontArg0 &&
+ argsArray[iFirstBeginText - 4][1] === firstSetFontArg1) {
+ count++;
+ iFirst -= 5;
+ }
+
+ // Remove (endText, beginText, setFont) trios.
+ var iEndText = iFirst + 4;
+ for (var q = 1; q < count; q++) {
+ fnArray.splice(iEndText, 3);
+ argsArray.splice(iEndText, 3);
+ iEndText += 2;
+ }
+
+ return iEndText + 1;
+ });
+
+ function QueueOptimizer() {}
+
+ QueueOptimizer.prototype = {
+ optimize: function QueueOptimizer_optimize(queue) {
var fnArray = queue.fnArray, argsArray = queue.argsArray;
- for (var i = 0, ii = queue.length; i < ii; i++) {
- switch (fnArray[i]) {
- case OPS.paintInlineImageXObject:
- case OPS.paintInlineImageXObjectGroup:
- case OPS.paintImageMaskXObject:
- var arg = argsArray[i][0]; // first param in imgData
- transfers.push(arg.data.buffer);
+ var context = {
+ iCurr: 0,
+ fnArray: fnArray,
+ argsArray: argsArray
+ };
+ var state;
+ var i = 0, ii = fnArray.length;
+ while (i < ii) {
+ state = (state || InitialState)[fnArray[i]];
+ if (typeof state === 'function') { // we found some handler
+ context.iCurr = i;
+ // state() returns the index of the first non-matching op (if we
+ // didn't match) or the first op past the modified ops (if we did
+ // match and replace).
+ i = state(context);
+ state = undefined; // reset the state machine
+ ii = context.fnArray.length;
+ } else {
+ i++;
+ }
+ }
+ }
+ };
+ return QueueOptimizer;
+})();
+
+
+var BUILT_IN_CMAPS = [
+// << Start unicode maps.
+'Adobe-GB1-UCS2',
+'Adobe-CNS1-UCS2',
+'Adobe-Japan1-UCS2',
+'Adobe-Korea1-UCS2',
+// >> End unicode maps.
+'78-EUC-H',
+'78-EUC-V',
+'78-H',
+'78-RKSJ-H',
+'78-RKSJ-V',
+'78-V',
+'78ms-RKSJ-H',
+'78ms-RKSJ-V',
+'83pv-RKSJ-H',
+'90ms-RKSJ-H',
+'90ms-RKSJ-V',
+'90msp-RKSJ-H',
+'90msp-RKSJ-V',
+'90pv-RKSJ-H',
+'90pv-RKSJ-V',
+'Add-H',
+'Add-RKSJ-H',
+'Add-RKSJ-V',
+'Add-V',
+'Adobe-CNS1-0',
+'Adobe-CNS1-1',
+'Adobe-CNS1-2',
+'Adobe-CNS1-3',
+'Adobe-CNS1-4',
+'Adobe-CNS1-5',
+'Adobe-CNS1-6',
+'Adobe-GB1-0',
+'Adobe-GB1-1',
+'Adobe-GB1-2',
+'Adobe-GB1-3',
+'Adobe-GB1-4',
+'Adobe-GB1-5',
+'Adobe-Japan1-0',
+'Adobe-Japan1-1',
+'Adobe-Japan1-2',
+'Adobe-Japan1-3',
+'Adobe-Japan1-4',
+'Adobe-Japan1-5',
+'Adobe-Japan1-6',
+'Adobe-Korea1-0',
+'Adobe-Korea1-1',
+'Adobe-Korea1-2',
+'B5-H',
+'B5-V',
+'B5pc-H',
+'B5pc-V',
+'CNS-EUC-H',
+'CNS-EUC-V',
+'CNS1-H',
+'CNS1-V',
+'CNS2-H',
+'CNS2-V',
+'ETHK-B5-H',
+'ETHK-B5-V',
+'ETen-B5-H',
+'ETen-B5-V',
+'ETenms-B5-H',
+'ETenms-B5-V',
+'EUC-H',
+'EUC-V',
+'Ext-H',
+'Ext-RKSJ-H',
+'Ext-RKSJ-V',
+'Ext-V',
+'GB-EUC-H',
+'GB-EUC-V',
+'GB-H',
+'GB-V',
+'GBK-EUC-H',
+'GBK-EUC-V',
+'GBK2K-H',
+'GBK2K-V',
+'GBKp-EUC-H',
+'GBKp-EUC-V',
+'GBT-EUC-H',
+'GBT-EUC-V',
+'GBT-H',
+'GBT-V',
+'GBTpc-EUC-H',
+'GBTpc-EUC-V',
+'GBpc-EUC-H',
+'GBpc-EUC-V',
+'H',
+'HKdla-B5-H',
+'HKdla-B5-V',
+'HKdlb-B5-H',
+'HKdlb-B5-V',
+'HKgccs-B5-H',
+'HKgccs-B5-V',
+'HKm314-B5-H',
+'HKm314-B5-V',
+'HKm471-B5-H',
+'HKm471-B5-V',
+'HKscs-B5-H',
+'HKscs-B5-V',
+'Hankaku',
+'Hiragana',
+'KSC-EUC-H',
+'KSC-EUC-V',
+'KSC-H',
+'KSC-Johab-H',
+'KSC-Johab-V',
+'KSC-V',
+'KSCms-UHC-H',
+'KSCms-UHC-HW-H',
+'KSCms-UHC-HW-V',
+'KSCms-UHC-V',
+'KSCpc-EUC-H',
+'KSCpc-EUC-V',
+'Katakana',
+'NWP-H',
+'NWP-V',
+'RKSJ-H',
+'RKSJ-V',
+'Roman',
+'UniCNS-UCS2-H',
+'UniCNS-UCS2-V',
+'UniCNS-UTF16-H',
+'UniCNS-UTF16-V',
+'UniCNS-UTF32-H',
+'UniCNS-UTF32-V',
+'UniCNS-UTF8-H',
+'UniCNS-UTF8-V',
+'UniGB-UCS2-H',
+'UniGB-UCS2-V',
+'UniGB-UTF16-H',
+'UniGB-UTF16-V',
+'UniGB-UTF32-H',
+'UniGB-UTF32-V',
+'UniGB-UTF8-H',
+'UniGB-UTF8-V',
+'UniJIS-UCS2-H',
+'UniJIS-UCS2-HW-H',
+'UniJIS-UCS2-HW-V',
+'UniJIS-UCS2-V',
+'UniJIS-UTF16-H',
+'UniJIS-UTF16-V',
+'UniJIS-UTF32-H',
+'UniJIS-UTF32-V',
+'UniJIS-UTF8-H',
+'UniJIS-UTF8-V',
+'UniJIS2004-UTF16-H',
+'UniJIS2004-UTF16-V',
+'UniJIS2004-UTF32-H',
+'UniJIS2004-UTF32-V',
+'UniJIS2004-UTF8-H',
+'UniJIS2004-UTF8-V',
+'UniJISPro-UCS2-HW-V',
+'UniJISPro-UCS2-V',
+'UniJISPro-UTF8-V',
+'UniJISX0213-UTF32-H',
+'UniJISX0213-UTF32-V',
+'UniJISX02132004-UTF32-H',
+'UniJISX02132004-UTF32-V',
+'UniKS-UCS2-H',
+'UniKS-UCS2-V',
+'UniKS-UTF16-H',
+'UniKS-UTF16-V',
+'UniKS-UTF32-H',
+'UniKS-UTF32-V',
+'UniKS-UTF8-H',
+'UniKS-UTF8-V',
+'V',
+'WP-Symbol'];
+
+// CMap, not to be confused with TrueType's cmap.
+var CMap = (function CMapClosure() {
+ function CMap(builtInCMap) {
+ // Codespace ranges are stored as follows:
+ // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
+ // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
+ this.codespaceRanges = [[], [], [], []];
+ this.numCodespaceRanges = 0;
+ // Map entries have one of two forms.
+ // - cid chars are 16-bit unsigned integers, stored as integers.
+ // - bf chars are variable-length byte sequences, stored as strings, with
+ // one byte per character.
+ this._map = [];
+ this.vertical = false;
+ this.useCMap = null;
+ this.builtInCMap = builtInCMap;
+ }
+ CMap.prototype = {
+ addCodespaceRange: function(n, low, high) {
+ this.codespaceRanges[n - 1].push(low, high);
+ this.numCodespaceRanges++;
+ },
+
+ mapCidRange: function(low, high, dstLow) {
+ while (low <= high) {
+ this._map[low++] = dstLow++;
+ }
+ },
+
+ mapBfRange: function(low, high, dstLow) {
+ var lastByte = dstLow.length - 1;
+ while (low <= high) {
+ this._map[low++] = dstLow;
+ // Only the last byte has to be incremented.
+ dstLow = dstLow.substr(0, lastByte) +
+ String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
+ }
+ },
+
+ mapBfRangeToArray: function(low, high, array) {
+ var i = 0, ii = array.length;
+ while (low <= high && i < ii) {
+ this._map[low] = array[i++];
+ ++low;
+ }
+ },
+
+ // This is used for both bf and cid chars.
+ mapOne: function(src, dst) {
+ this._map[src] = dst;
+ },
+
+ lookup: function(code) {
+ return this._map[code];
+ },
+
+ contains: function(code) {
+ return this._map[code] !== undefined;
+ },
+
+ forEach: function(callback) {
+ // Most maps have fewer than 65536 entries, and for those we use normal
+ // array iteration. But really sparse tables are possible -- e.g. with
+ // indices in the *billions*. For such tables we use for..in, which isn't
+ // ideal because it stringifies the indices for all present elements, but
+ // it does avoid iterating over every undefined entry.
+ var map = this._map;
+ var length = map.length;
+ var i;
+ if (length <= 0x10000) {
+ for (i = 0; i < length; i++) {
+ if (map[i] !== undefined) {
+ callback(i, map[i]);
+ }
+ }
+ } else {
+ for (i in this._map) {
+ callback(i, map[i]);
+ }
+ }
+ },
+
+ charCodeOf: function(value) {
+ return this._map.indexOf(value);
+ },
+
+ getMap: function() {
+ return this._map;
+ },
+
+ readCharCode: function(str, offset, out) {
+ var c = 0;
+ var codespaceRanges = this.codespaceRanges;
+ var codespaceRangesLen = this.codespaceRanges.length;
+ // 9.7.6.2 CMap Mapping
+ // The code length is at most 4.
+ for (var n = 0; n < codespaceRangesLen; n++) {
+ c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
+ // Check each codespace range to see if it falls within.
+ var codespaceRange = codespaceRanges[n];
+ for (var k = 0, kk = codespaceRange.length; k < kk;) {
+ var low = codespaceRange[k++];
+ var high = codespaceRange[k++];
+ if (c >= low && c <= high) {
+ out.charcode = c;
+ out.length = n + 1;
+ return;
+ }
+ }
+ }
+ out.charcode = 0;
+ out.length = 1;
+ }
+ };
+ return CMap;
+})();
+
+// A special case of CMap, where the _map array implicitly has a length of
+// 65535 and each element is equal to its index.
+var IdentityCMap = (function IdentityCMapClosure() {
+ function IdentityCMap(vertical, n) {
+ CMap.call(this);
+ this.vertical = vertical;
+ this.addCodespaceRange(n, 0, 0xffff);
+ }
+ Util.inherit(IdentityCMap, CMap, {});
+
+ IdentityCMap.prototype = {
+ addCodespaceRange: CMap.prototype.addCodespaceRange,
+
+ mapCidRange: function(low, high, dstLow) {
+ error('should not call mapCidRange');
+ },
+
+ mapBfRange: function(low, high, dstLow) {
+ error('should not call mapBfRange');
+ },
+
+ mapBfRangeToArray: function(low, high, array) {
+ error('should not call mapBfRangeToArray');
+ },
+
+ mapOne: function(src, dst) {
+ error('should not call mapCidOne');
+ },
+
+ lookup: function(code) {
+ return (isInt(code) && code <= 0xffff) ? code : undefined;
+ },
+
+ contains: function(code) {
+ return isInt(code) && code <= 0xffff;
+ },
+
+ forEach: function(callback) {
+ for (var i = 0; i <= 0xffff; i++) {
+ callback(i, i);
+ }
+ },
+
+ charCodeOf: function(value) {
+ return (isInt(value) && value <= 0xffff) ? value : -1;
+ },
+
+ getMap: function() {
+ // Sometimes identity maps must be instantiated, but it's rare.
+ var map = new Array(0x10000);
+ for (var i = 0; i <= 0xffff; i++) {
+ map[i] = i;
+ }
+ return map;
+ },
+
+ readCharCode: CMap.prototype.readCharCode
+ };
+
+ return IdentityCMap;
+})();
+
+var BinaryCMapReader = (function BinaryCMapReaderClosure() {
+ function fetchBinaryData(url) {
+ var nonBinaryRequest = PDFJS.disableWorker;
+ var request = new XMLHttpRequest();
+ request.open('GET', url, false);
+ if (!nonBinaryRequest) {
+ try {
+ request.responseType = 'arraybuffer';
+ nonBinaryRequest = request.responseType !== 'arraybuffer';
+ } catch (e) {
+ nonBinaryRequest = true;
+ }
+ }
+ if (nonBinaryRequest && request.overrideMimeType) {
+ request.overrideMimeType('text/plain; charset=x-user-defined');
+ }
+ request.send(null);
+ if (nonBinaryRequest ? !request.responseText : !request.response) {
+ error('Unable to get binary cMap at: ' + url);
+ }
+ if (nonBinaryRequest) {
+ var data = Array.prototype.map.call(request.responseText, function (ch) {
+ return ch.charCodeAt(0) & 255;
+ });
+ return new Uint8Array(data);
+ }
+ return new Uint8Array(request.response);
+ }
+
+ function hexToInt(a, size) {
+ var n = 0;
+ for (var i = 0; i <= size; i++) {
+ n = (n << 8) | a[i];
+ }
+ return n >>> 0;
+ }
+
+ function hexToStr(a, size) {
+ // This code is hot. Special-case some common values to avoid creating an
+ // object with subarray().
+ if (size === 1) {
+ return String.fromCharCode(a[0], a[1]);
+ }
+ if (size === 3) {
+ return String.fromCharCode(a[0], a[1], a[2], a[3]);
+ }
+ return String.fromCharCode.apply(null, a.subarray(0, size + 1));
+ }
+
+ function addHex(a, b, size) {
+ var c = 0;
+ for (var i = size; i >= 0; i--) {
+ c += a[i] + b[i];
+ a[i] = c & 255;
+ c >>= 8;
+ }
+ }
+
+ function incHex(a, size) {
+ var c = 1;
+ for (var i = size; i >= 0 && c > 0; i--) {
+ c += a[i];
+ a[i] = c & 255;
+ c >>= 8;
+ }
+ }
+
+ var MAX_NUM_SIZE = 16;
+ var MAX_ENCODED_NUM_SIZE = 19; // ceil(MAX_NUM_SIZE * 7 / 8)
+
+ function BinaryCMapStream(data) {
+ this.buffer = data;
+ this.pos = 0;
+ this.end = data.length;
+ this.tmpBuf = new Uint8Array(MAX_ENCODED_NUM_SIZE);
+ }
+
+ BinaryCMapStream.prototype = {
+ readByte: function () {
+ if (this.pos >= this.end) {
+ return -1;
+ }
+ return this.buffer[this.pos++];
+ },
+ readNumber: function () {
+ var n = 0;
+ var last;
+ do {
+ var b = this.readByte();
+ if (b < 0) {
+ error('unexpected EOF in bcmap');
+ }
+ last = !(b & 0x80);
+ n = (n << 7) | (b & 0x7F);
+ } while (!last);
+ return n;
+ },
+ readSigned: function () {
+ var n = this.readNumber();
+ return (n & 1) ? ~(n >>> 1) : n >>> 1;
+ },
+ readHex: function (num, size) {
+ num.set(this.buffer.subarray(this.pos,
+ this.pos + size + 1));
+ this.pos += size + 1;
+ },
+ readHexNumber: function (num, size) {
+ var last;
+ var stack = this.tmpBuf, sp = 0;
+ do {
+ var b = this.readByte();
+ if (b < 0) {
+ error('unexpected EOF in bcmap');
+ }
+ last = !(b & 0x80);
+ stack[sp++] = b & 0x7F;
+ } while (!last);
+ var i = size, buffer = 0, bufferSize = 0;
+ while (i >= 0) {
+ while (bufferSize < 8 && stack.length > 0) {
+ buffer = (stack[--sp] << bufferSize) | buffer;
+ bufferSize += 7;
+ }
+ num[i] = buffer & 255;
+ i--;
+ buffer >>= 8;
+ bufferSize -= 8;
+ }
+ },
+ readHexSigned: function (num, size) {
+ this.readHexNumber(num, size);
+ var sign = num[size] & 1 ? 255 : 0;
+ var c = 0;
+ for (var i = 0; i <= size; i++) {
+ c = ((c & 1) << 8) | num[i];
+ num[i] = (c >> 1) ^ sign;
+ }
+ },
+ readString: function () {
+ var len = this.readNumber();
+ var s = '';
+ for (var i = 0; i < len; i++) {
+ s += String.fromCharCode(this.readNumber());
+ }
+ return s;
+ }
+ };
+
+ function processBinaryCMap(url, cMap, extend) {
+ var data = fetchBinaryData(url);
+ var stream = new BinaryCMapStream(data);
+
+ var header = stream.readByte();
+ cMap.vertical = !!(header & 1);
+
+ var useCMap = null;
+ var start = new Uint8Array(MAX_NUM_SIZE);
+ var end = new Uint8Array(MAX_NUM_SIZE);
+ var char = new Uint8Array(MAX_NUM_SIZE);
+ var charCode = new Uint8Array(MAX_NUM_SIZE);
+ var tmp = new Uint8Array(MAX_NUM_SIZE);
+ var code;
+
+ var b;
+ while ((b = stream.readByte()) >= 0) {
+ var type = b >> 5;
+ if (type === 7) { // metadata, e.g. comment or usecmap
+ switch (b & 0x1F) {
+ case 0:
+ stream.readString(); // skipping comment
+ break;
+ case 1:
+ useCMap = stream.readString();
+ break;
+ }
+ continue;
+ }
+ var sequence = !!(b & 0x10);
+ var dataSize = b & 15;
+
+ assert(dataSize + 1 <= MAX_NUM_SIZE);
+
+ var ucs2DataSize = 1;
+ var subitemsCount = stream.readNumber();
+ var i;
+ switch (type) {
+ case 0: // codespacerange
+ stream.readHex(start, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
+ hexToInt(end, dataSize));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, dataSize);
+ stream.readHexNumber(start, dataSize);
+ addHex(start, end, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ cMap.addCodespaceRange(dataSize + 1, hexToInt(start, dataSize),
+ hexToInt(end, dataSize));
+ }
+ break;
+ case 1: // notdefrange
+ stream.readHex(start, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ // undefined range, skipping
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, dataSize);
+ stream.readHexNumber(start, dataSize);
+ addHex(start, end, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ // nop
+ }
+ break;
+ case 2: // cidchar
+ stream.readHex(char, dataSize);
+ code = stream.readNumber();
+ cMap.mapOne(hexToInt(char, dataSize), code);
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(char, dataSize);
+ if (!sequence) {
+ stream.readHexNumber(tmp, dataSize);
+ addHex(char, tmp, dataSize);
+ }
+ code = stream.readSigned() + (code + 1);
+ cMap.mapOne(hexToInt(char, dataSize), code);
+ }
+ break;
+ case 3: // cidrange
+ stream.readHex(start, dataSize);
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
+ code);
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, dataSize);
+ if (!sequence) {
+ stream.readHexNumber(start, dataSize);
+ addHex(start, end, dataSize);
+ } else {
+ start.set(end);
+ }
+ stream.readHexNumber(end, dataSize);
+ addHex(end, start, dataSize);
+ code = stream.readNumber();
+ cMap.mapCidRange(hexToInt(start, dataSize), hexToInt(end, dataSize),
+ code);
+ }
+ break;
+ case 4: // bfchar
+ stream.readHex(char, ucs2DataSize);
+ stream.readHex(charCode, dataSize);
+ cMap.mapOne(hexToInt(char, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(char, ucs2DataSize);
+ if (!sequence) {
+ stream.readHexNumber(tmp, ucs2DataSize);
+ addHex(char, tmp, ucs2DataSize);
+ }
+ incHex(charCode, dataSize);
+ stream.readHexSigned(tmp, dataSize);
+ addHex(charCode, tmp, dataSize);
+ cMap.mapOne(hexToInt(char, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ }
+ break;
+ case 5: // bfrange
+ stream.readHex(start, ucs2DataSize);
+ stream.readHexNumber(end, ucs2DataSize);
+ addHex(end, start, ucs2DataSize);
+ stream.readHex(charCode, dataSize);
+ cMap.mapBfRange(hexToInt(start, ucs2DataSize),
+ hexToInt(end, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ for (i = 1; i < subitemsCount; i++) {
+ incHex(end, ucs2DataSize);
+ if (!sequence) {
+ stream.readHexNumber(start, ucs2DataSize);
+ addHex(start, end, ucs2DataSize);
+ } else {
+ start.set(end);
+ }
+ stream.readHexNumber(end, ucs2DataSize);
+ addHex(end, start, ucs2DataSize);
+ stream.readHex(charCode, dataSize);
+ cMap.mapBfRange(hexToInt(start, ucs2DataSize),
+ hexToInt(end, ucs2DataSize),
+ hexToStr(charCode, dataSize));
+ }
+ break;
+ default:
+ error('Unknown type: ' + type);
+ break;
+ }
+ }
+
+ if (useCMap) {
+ extend(useCMap);
+ }
+ return cMap;
+ }
+
+ function BinaryCMapReader() {}
+
+ BinaryCMapReader.prototype = {
+ read: processBinaryCMap
+ };
+
+ return BinaryCMapReader;
+})();
+
+var CMapFactory = (function CMapFactoryClosure() {
+ function strToInt(str) {
+ var a = 0;
+ for (var i = 0; i < str.length; i++) {
+ a = (a << 8) | str.charCodeAt(i);
+ }
+ return a >>> 0;
+ }
+
+ function expectString(obj) {
+ if (!isString(obj)) {
+ error('Malformed CMap: expected string.');
+ }
+ }
+
+ function expectInt(obj) {
+ if (!isInt(obj)) {
+ error('Malformed CMap: expected int.');
+ }
+ }
+
+ function parseBfChar(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endbfchar')) {
+ return;
+ }
+ expectString(obj);
+ var src = strToInt(obj);
+ obj = lexer.getObj();
+ // TODO are /dstName used?
+ expectString(obj);
+ var dst = obj;
+ cMap.mapOne(src, dst);
+ }
+ }
+
+ function parseBfRange(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endbfrange')) {
+ return;
+ }
+ expectString(obj);
+ var low = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ var high = strToInt(obj);
+ obj = lexer.getObj();
+ if (isInt(obj) || isString(obj)) {
+ var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
+ cMap.mapBfRange(low, high, dstLow);
+ } else if (isCmd(obj, '[')) {
+ obj = lexer.getObj();
+ var array = [];
+ while (!isCmd(obj, ']') && !isEOF(obj)) {
+ array.push(obj);
+ obj = lexer.getObj();
+ }
+ cMap.mapBfRangeToArray(low, high, array);
+ } else {
+ break;
+ }
+ }
+ error('Invalid bf range.');
+ }
+
+ function parseCidChar(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endcidchar')) {
+ return;
+ }
+ expectString(obj);
+ var src = strToInt(obj);
+ obj = lexer.getObj();
+ expectInt(obj);
+ var dst = obj;
+ cMap.mapOne(src, dst);
+ }
+ }
+
+ function parseCidRange(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endcidrange')) {
+ return;
+ }
+ expectString(obj);
+ var low = strToInt(obj);
+ obj = lexer.getObj();
+ expectString(obj);
+ var high = strToInt(obj);
+ obj = lexer.getObj();
+ expectInt(obj);
+ var dstLow = obj;
+ cMap.mapCidRange(low, high, dstLow);
+ }
+ }
+
+ function parseCodespaceRange(cMap, lexer) {
+ while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ }
+ if (isCmd(obj, 'endcodespacerange')) {
+ return;
+ }
+ if (!isString(obj)) {
+ break;
+ }
+ var low = strToInt(obj);
+ obj = lexer.getObj();
+ if (!isString(obj)) {
+ break;
+ }
+ var high = strToInt(obj);
+ cMap.addCodespaceRange(obj.length, low, high);
+ }
+ error('Invalid codespace range.');
+ }
+
+ function parseWMode(cMap, lexer) {
+ var obj = lexer.getObj();
+ if (isInt(obj)) {
+ cMap.vertical = !!obj;
+ }
+ }
+
+ function parseCMap(cMap, lexer, builtInCMapParams, useCMap) {
+ var previous;
+ var embededUseCMap;
+ objLoop: while (true) {
+ var obj = lexer.getObj();
+ if (isEOF(obj)) {
+ break;
+ } else if (isName(obj)) {
+ if (obj.name === 'WMode') {
+ parseWMode(cMap, lexer);
+ }
+ previous = obj;
+ } else if (isCmd(obj)) {
+ switch (obj.cmd) {
+ case 'endcmap':
+ break objLoop;
+ case 'usecmap':
+ if (isName(previous)) {
+ embededUseCMap = previous.name;
+ }
+ break;
+ case 'begincodespacerange':
+ parseCodespaceRange(cMap, lexer);
+ break;
+ case 'beginbfchar':
+ parseBfChar(cMap, lexer);
+ break;
+ case 'begincidchar':
+ parseCidChar(cMap, lexer);
+ break;
+ case 'beginbfrange':
+ parseBfRange(cMap, lexer);
+ break;
+ case 'begincidrange':
+ parseCidRange(cMap, lexer);
break;
}
}
- return transfers;
}
-
- function OperatorList(messageHandler, pageIndex) {
- this.messageHandler = messageHandler;
- // When there isn't a message handler the fn array needs to be able to grow
- // since we can't flush the operators.
- if (messageHandler) {
- this.fnArray = new Uint8Array(CHUNK_SIZE);
- } else {
- this.fnArray = [];
+ if (!useCMap && embededUseCMap) {
+ // Load the usecmap definition from the file only if there wasn't one
+ // specified.
+ useCMap = embededUseCMap;
+ }
+ if (useCMap) {
+ extendCMap(cMap, builtInCMapParams, useCMap);
}
- this.argsArray = [];
- this.dependencies = {},
- this.pageIndex = pageIndex;
- this.fnIndex = 0;
}
- OperatorList.prototype = {
+ function extendCMap(cMap, builtInCMapParams, useCMap) {
+ cMap.useCMap = createBuiltInCMap(useCMap, builtInCMapParams);
+ // If there aren't any code space ranges defined clone all the parent ones
+ // into this cMap.
+ if (cMap.numCodespaceRanges === 0) {
+ var useCodespaceRanges = cMap.useCMap.codespaceRanges;
+ for (var i = 0; i < useCodespaceRanges.length; i++) {
+ cMap.codespaceRanges[i] = useCodespaceRanges[i].slice();
+ }
+ cMap.numCodespaceRanges = cMap.useCMap.numCodespaceRanges;
+ }
+ // Merge the map into the current one, making sure not to override
+ // any previously defined entries.
+ cMap.useCMap.forEach(function(key, value) {
+ if (!cMap.contains(key)) {
+ cMap.mapOne(key, cMap.useCMap.lookup(key));
+ }
+ });
+ }
- get length() {
- return this.argsArray.length;
- },
+ function parseBinaryCMap(name, builtInCMapParams) {
+ var url = builtInCMapParams.url + name + '.bcmap';
+ var cMap = new CMap(true);
+ new BinaryCMapReader().read(url, cMap, function (useCMap) {
+ extendCMap(cMap, builtInCMapParams, useCMap);
+ });
+ return cMap;
+ }
- addOp: function(fn, args) {
- if (this.messageHandler) {
- this.fnArray[this.fnIndex++] = fn;
- this.argsArray.push(args);
- if (this.fnIndex >= CHUNK_SIZE) {
- this.flush();
+ function createBuiltInCMap(name, builtInCMapParams) {
+ if (name === 'Identity-H') {
+ return new IdentityCMap(false, 2);
+ } else if (name === 'Identity-V') {
+ return new IdentityCMap(true, 2);
+ }
+ if (BUILT_IN_CMAPS.indexOf(name) === -1) {
+ error('Unknown cMap name: ' + name);
+ }
+ assert(builtInCMapParams, 'built-in cMap parameters are not provided');
+
+ if (builtInCMapParams.packed) {
+ return parseBinaryCMap(name, builtInCMapParams);
+ }
+
+ var request = new XMLHttpRequest();
+ var url = builtInCMapParams.url + name;
+ request.open('GET', url, false);
+ request.send(null);
+ if (!request.responseText) {
+ error('Unable to get cMap at: ' + url);
+ }
+ var cMap = new CMap(true);
+ var lexer = new Lexer(new StringStream(request.responseText));
+ parseCMap(cMap, lexer, builtInCMapParams, null);
+ return cMap;
+ }
+
+ return {
+ create: function (encoding, builtInCMapParams, useCMap) {
+ if (isName(encoding)) {
+ return createBuiltInCMap(encoding.name, builtInCMapParams);
+ } else if (isStream(encoding)) {
+ var cMap = new CMap();
+ var lexer = new Lexer(encoding);
+ try {
+ parseCMap(cMap, lexer, builtInCMapParams, useCMap);
+ } catch (e) {
+ warn('Invalid CMap data. ' + e);
}
- } else {
- this.fnArray.push(fn);
- this.argsArray.push(args);
+ return cMap;
}
- },
-
- addDependency: function(dependency) {
- if (dependency in this.dependencies) {
- return;
- }
- this.dependencies[dependency] = true;
- this.addOp(OPS.dependency, [dependency]);
- },
-
- addDependencies: function(dependencies) {
- for (var key in dependencies) {
- this.addDependency(key);
- }
- },
-
- addOpList: function(opList) {
- Util.extendObj(this.dependencies, opList.dependencies);
- for (var i = 0, ii = opList.length; i < ii; i++) {
- this.addOp(opList.fnArray[i], opList.argsArray[i]);
- }
- },
-
- getIR: function() {
- return {
- fnArray: this.fnArray,
- argsArray: this.argsArray,
- length: this.length
- };
- },
-
- flush: function(lastChunk) {
- PartialEvaluator.optimizeQueue(this);
- var transfers = getTransfers(this);
- this.messageHandler.send('RenderPageChunk', {
- operatorList: {
- fnArray: this.fnArray,
- argsArray: this.argsArray,
- lastChunk: lastChunk,
- length: this.length
- },
- pageIndex: this.pageIndex
- }, null, transfers);
- this.dependencies = [];
- this.fnIndex = 0;
- this.argsArray = [];
+ error('Encoding required.');
}
};
-
- return OperatorList;
})();
-var TextState = (function TextStateClosure() {
- function TextState() {
- this.fontSize = 0;
- this.ctm = [1, 0, 0, 1, 0, 0];
- this.textMatrix = [1, 0, 0, 1, 0, 0];
- this.stateStack = [];
- //textState variables
- this.leading = 0;
- this.textHScale = 1;
- this.textRise = 0;
- }
- TextState.prototype = {
- push: function TextState_push() {
- this.stateStack.push(this.ctm.slice());
- },
- pop: function TextState_pop() {
- var prev = this.stateStack.pop();
- if (prev) {
- this.ctm = prev;
- }
- },
- initialiseTextObj: function TextState_initialiseTextObj() {
- var m = this.textMatrix;
- m[0] = 1, m[1] = 0, m[2] = 0, m[3] = 1, m[4] = 0, m[5] = 0;
- },
- setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
- var m = this.textMatrix;
- m[0] = a, m[1] = b, m[2] = c, m[3] = d, m[4] = e, m[5] = f;
- },
- transformCTM: function TextState_transformCTM(a, b, c, d, e, f) {
- var m = this.ctm;
- var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4], m5 = m[5];
- m[0] = m0 * a + m2 * b;
- m[1] = m1 * a + m3 * b;
- m[2] = m0 * c + m2 * d;
- m[3] = m1 * c + m3 * d;
- m[4] = m0 * e + m2 * f + m4;
- m[5] = m1 * e + m3 * f + m5;
- },
- translateTextMatrix: function TextState_translateTextMatrix(x, y) {
- var m = this.textMatrix;
- m[4] = m[0] * x + m[2] * y + m[4];
- m[5] = m[1] * x + m[3] * y + m[5];
- },
- calcRenderParams: function TextState_calcRenderingParams() {
- var tm = this.textMatrix;
- var cm = this.ctm;
- var a = this.fontSize;
- var b = a * this.textHScale;
- var c = this.textRise;
- var vScale = Math.sqrt((tm[2] * tm[2]) + (tm[3] * tm[3]));
- var angle = Math.atan2(tm[1], tm[0]);
- var m0 = tm[0] * cm[0] + tm[1] * cm[2];
- var m1 = tm[0] * cm[1] + tm[1] * cm[3];
- var m2 = tm[2] * cm[0] + tm[3] * cm[2];
- var m3 = tm[2] * cm[1] + tm[3] * cm[3];
- var m4 = tm[4] * cm[0] + tm[5] * cm[2] + cm[4];
- var m5 = tm[4] * cm[1] + tm[5] * cm[3] + cm[5];
- var renderMatrix = [
- b * m0,
- b * m1,
- a * m2,
- a * m3,
- c * m2 + m4,
- c * m3 + m5
- ];
- return {
- renderMatrix: renderMatrix,
- vScale: vScale,
- angle: angle
- };
- },
- };
- return TextState;
-})();
-
-var EvalState = (function EvalStateClosure() {
- function EvalState() {
- this.font = null;
- this.textRenderingMode = TextRenderingMode.FILL;
- }
- EvalState.prototype = {
- clone: function CanvasExtraState_clone() {
- return Object.create(this);
- },
- };
- return EvalState;
-})();
-
-
// Unicode Private Use Area
-var CMAP_GLYPH_OFFSET = 0xE000;
-var GLYPH_AREA_SIZE = 0x1900;
-var SYMBOLIC_FONT_GLYPH_OFFSET = 0xF000;
+var PRIVATE_USE_OFFSET_START = 0xE000;
+var PRIVATE_USE_OFFSET_END = 0xF8FF;
+var SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = false;
// PDF Glyph Space Units are one Thousandth of a TextSpace Unit
// except for Type 3 fonts
@@ -16330,7 +14201,7 @@ var Encodings = {
'summation', 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine',
'Omega', 'ae', 'oslash', 'questiondown', 'exclamdown', 'logicalnot',
'radical', 'florin', 'approxequal', 'Delta', 'guillemotleft',
- 'guillemotright', 'ellipsis', '', 'Agrave', 'Atilde', 'Otilde', 'OE',
+ 'guillemotright', 'ellipsis', 'space', 'Agrave', 'Atilde', 'Otilde', 'OE',
'oe', 'endash', 'emdash', 'quotedblleft', 'quotedblright', 'quoteleft',
'quoteright', 'divide', 'lozenge', 'ydieresis', 'Ydieresis', 'fraction',
'currency', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'daggerdbl',
@@ -16382,7 +14253,7 @@ var Encodings = {
'guilsinglleft', 'OE', 'bullet', 'Zcaron', 'bullet', 'bullet', 'quoteleft',
'quoteright', 'quotedblleft', 'quotedblright', 'bullet', 'endash',
'emdash', 'tilde', 'trademark', 'scaron', 'guilsinglright', 'oe', 'bullet',
- 'zcaron', 'Ydieresis', '', 'exclamdown', 'cent', 'sterling',
+ 'zcaron', 'Ydieresis', 'space', 'exclamdown', 'cent', 'sterling',
'currency', 'yen', 'brokenbar', 'section', 'dieresis', 'copyright',
'ordfeminine', 'guillemotleft', 'logicalnot', 'hyphen', 'registered',
'macron', 'degree', 'plusminus', 'twosuperior', 'threesuperior', 'acute',
@@ -16435,7 +14306,7 @@ var Encodings = {
'parenrighttp', 'parenrightex', 'parenrightbt', 'bracketrighttp',
'bracketrightex', 'bracketrightbt', 'bracerighttp', 'bracerightmid',
'bracerightbt'],
- zapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
+ ZapfDingbatsEncoding: ['', '', '', '', '', '', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
'space', 'a1', 'a2', 'a202', 'a3', 'a4', 'a5', 'a119', 'a118', 'a117',
'a11', 'a12', 'a13', 'a14', 'a15', 'a16', 'a105', 'a17', 'a18', 'a19',
@@ -16446,19 +14317,19 @@ var Encodings = {
'a57', 'a58', 'a59', 'a60', 'a61', 'a62', 'a63', 'a64', 'a65', 'a66',
'a67', 'a68', 'a69', 'a70', 'a71', 'a72', 'a73', 'a74', 'a203', 'a75',
'a204', 'a76', 'a77', 'a78', 'a79', 'a81', 'a82', 'a83', 'a84', 'a97',
- 'a98', 'a99', 'a100', '', '', '', '', '', '', '', '', '', '', '', '', '',
- '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
- '', '', 'a101', 'a102', 'a103', 'a104', 'a106', 'a107', 'a108', 'a112',
- 'a111', 'a110', 'a109', 'a120', 'a121', 'a122', 'a123', 'a124', 'a125',
- 'a126', 'a127', 'a128', 'a129', 'a130', 'a131', 'a132', 'a133', 'a134',
- 'a135', 'a136', 'a137', 'a138', 'a139', 'a140', 'a141', 'a142', 'a143',
- 'a144', 'a145', 'a146', 'a147', 'a148', 'a149', 'a150', 'a151', 'a152',
- 'a153', 'a154', 'a155', 'a156', 'a157', 'a158', 'a159', 'a160', 'a161',
- 'a163', 'a164', 'a196', 'a165', 'a192', 'a166', 'a167', 'a168', 'a169',
- 'a170', 'a171', 'a172', 'a173', 'a162', 'a174', 'a175', 'a176', 'a177',
- 'a178', 'a179', 'a193', 'a180', 'a199', 'a181', 'a200', 'a182', '', 'a201',
- 'a183', 'a184', 'a197', 'a185', 'a194', 'a198', 'a186', 'a195', 'a187',
- 'a188', 'a189', 'a190', 'a191']
+ 'a98', 'a99', 'a100', '', 'a89', 'a90', 'a93', 'a94', 'a91', 'a92', 'a205',
+ 'a85', 'a206', 'a86', 'a87', 'a88', 'a95', 'a96', '', '', '', '', '', '',
+ '', '', '', '', '', '', '', '', '', '', '', '', '', 'a101', 'a102', 'a103',
+ 'a104', 'a106', 'a107', 'a108', 'a112', 'a111', 'a110', 'a109', 'a120',
+ 'a121', 'a122', 'a123', 'a124', 'a125', 'a126', 'a127', 'a128', 'a129',
+ 'a130', 'a131', 'a132', 'a133', 'a134', 'a135', 'a136', 'a137', 'a138',
+ 'a139', 'a140', 'a141', 'a142', 'a143', 'a144', 'a145', 'a146', 'a147',
+ 'a148', 'a149', 'a150', 'a151', 'a152', 'a153', 'a154', 'a155', 'a156',
+ 'a157', 'a158', 'a159', 'a160', 'a161', 'a163', 'a164', 'a196', 'a165',
+ 'a192', 'a166', 'a167', 'a168', 'a169', 'a170', 'a171', 'a172', 'a173',
+ 'a162', 'a174', 'a175', 'a176', 'a177', 'a178', 'a179', 'a193', 'a180',
+ 'a199', 'a181', 'a200', 'a182', '', 'a201', 'a183', 'a184', 'a197', 'a185',
+ 'a194', 'a198', 'a186', 'a195', 'a187', 'a188', 'a189', 'a190', 'a191']
};
/**
@@ -16544,7 +14415,7 @@ var nonStdFontMap = {
'MS-PMincho': 'MS PMincho',
'MS-PMincho-Bold': 'MS PMincho-Bold',
'MS-PMincho-BoldItalic': 'MS PMincho-BoldItalic',
- 'MS-PMincho-Italic': 'MS PMincho-Italic',
+ 'MS-PMincho-Italic': 'MS PMincho-Italic'
};
var serifFonts = {
@@ -16598,43 +14469,12 @@ var symbolsFonts = {
'Dingbats': true, 'Symbol': true, 'ZapfDingbats': true
};
-var CMapConverterList = {
- 'H': jis7ToUnicode,
- 'V': jis7ToUnicode,
- 'EUC-H': eucjpToUnicode,
- 'EUC-V': eucjpToUnicode,
- '83pv-RKSJ-H': sjis83pvToUnicode,
- '90pv-RKSJ-H': sjis90pvToUnicode,
- '90ms-RKSJ-H': sjisToUnicode,
- '90ms-RKSJ-V': sjisToUnicode,
- '90msp-RKSJ-H': sjisToUnicode,
- '90msp-RKSJ-V': sjisToUnicode,
- 'GBK-EUC-H': gbkToUnicode,
- 'GBKp-EUC-H': gbkToUnicode,
- 'B5pc-H': big5ToUnicode,
- 'ETenms-B5-H': big5ToUnicode,
- 'ETenms-B5-V': big5ToUnicode,
-};
-
-// CMaps using Hankaku (Halfwidth) Latin glyphs instead of proportional one.
-// We need to distinguish them to get correct widths from CIDFont dicts.
-var HalfwidthCMaps = {
- 'H': true,
- 'V': true,
- 'EUC-H': true,
- 'EUC-V': true,
- '90ms-RKSJ-H': true,
- '90ms-RKSJ-V': true,
- 'UniJIS-UCS2-HW-H': true,
- 'UniJIS-UCS2-HW-V': true
-};
-
// Glyph map for well-known standard fonts. Sometimes Ghostscript uses CID fonts
// but does not embed the CID to GID mapping. The mapping is incomplete for all
// glyphs, but common for some set of the standard fonts.
var GlyphMapForStandardFonts = {
'2': 10, '3': 32, '4': 33, '5': 34, '6': 35, '7': 36, '8': 37, '9': 38,
- '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 173,
+ '10': 39, '11': 40, '12': 41, '13': 42, '14': 43, '15': 44, '16': 45,
'17': 46, '18': 47, '19': 48, '20': 49, '21': 50, '22': 51, '23': 52,
'24': 53, '25': 54, '26': 55, '27': 56, '28': 57, '29': 58, '30': 894,
'31': 60, '32': 61, '33': 62, '34': 63, '35': 64, '36': 65, '37': 66,
@@ -16658,7 +14498,12 @@ var GlyphMapForStandardFonts = {
'149': 8805, '150': 165, '151': 181, '152': 8706, '153': 8721, '154': 8719,
'156': 8747, '157': 170, '158': 186, '159': 8486, '160': 230, '161': 248,
'162': 191, '163': 161, '164': 172, '165': 8730, '166': 402, '167': 8776,
- '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '305': 963,
+ '168': 8710, '169': 171, '170': 187, '171': 8230, '210': 218, '223': 711,
+ '224': 321, '225': 322, '227': 353, '229': 382, '234': 253, '252': 263,
+ '253': 268, '254': 269, '258': 258, '260': 260, '261': 261, '265': 280,
+ '266': 281, '268': 283, '269': 313, '275': 323, '276': 324, '278': 328,
+ '284': 345, '285': 346, '286': 347, '292': 367, '295': 377, '296': 378,
+ '298': 380, '305': 963,
'306': 964, '307': 966, '308': 8215, '309': 8252, '310': 8319, '311': 8359,
'312': 8592, '313': 8593, '337': 9552, '493': 1039, '494': 1040, '705': 1524,
'706': 8362, '710': 64288, '711': 64298, '759': 1617, '761': 1776,
@@ -16699,82 +14544,42 @@ var GlyphMapForStandardFonts = {
'3316': 578, '3379': 42785, '3393': 1159, '3416': 8377
};
-var decodeBytes;
-if (typeof TextDecoder !== 'undefined') {
- // The encodings supported by TextDecoder can be found at:
- // http://encoding.spec.whatwg.org/#concept-encoding-get
- decodeBytes = function(bytes, encoding, fatal) {
- return new TextDecoder(encoding, {fatal: !!fatal}).decode(bytes);
- };
-} else if (typeof FileReaderSync !== 'undefined') {
- decodeBytes = function(bytes, encoding) {
- return new FileReaderSync().readAsText(new Blob([bytes]), encoding);
- };
-} else {
- // Clear the list so that decodeBytes will never be called.
- CMapConverterList = {};
-}
-
-function jis7ToUnicode(str) {
- var bytes = stringToBytes(str);
- var length = bytes.length;
- for (var i = 0; i < length; ++i) {
- bytes[i] |= 0x80;
- }
- return decodeBytes(bytes, 'euc-jp');
-}
-
-function eucjpToUnicode(str) {
- return decodeBytes(stringToBytes(str), 'euc-jp');
-}
-
-function sjisToUnicode(str) {
- return decodeBytes(stringToBytes(str), 'shift_jis');
-}
-
-function sjis83pvToUnicode(str) {
- var bytes = stringToBytes(str);
- try {
- // TODO: 83pv has incompatible mappings in ed40..ee9c range.
- return decodeBytes(bytes, 'shift_jis', true);
- } catch (e) {
- warn('Unsupported 83pv character found');
- // Just retry without checking errors for now.
- return decodeBytes(bytes, 'shift_jis');
- }
-}
-
-function sjis90pvToUnicode(str) {
- var bytes = stringToBytes(str);
- try {
- // TODO: 90pv has incompatible mappings in 8740..879c and eb41..ee9c.
- return decodeBytes(bytes, 'shift_jis', true);
- } catch (e) {
- warn('Unsupported 90pv character found');
- // Just retry without checking errors for now.
- return decodeBytes(bytes, 'shift_jis');
- }
-}
-
-function gbkToUnicode(str) {
- return decodeBytes(stringToBytes(str), 'gbk');
-}
-
-function big5ToUnicode(str) {
- return decodeBytes(stringToBytes(str), 'big5');
-}
-
-// Some characters, e.g. copyrightserif, mapped to the private use area and
+// Some characters, e.g. copyrightserif, are mapped to the private use area and
// might not be displayed using standard fonts. Mapping/hacking well-known chars
// to the similar equivalents in the normal characters range.
-function mapPrivateUseChars(code) {
- switch (code) {
- case 0xF8E9: // copyrightsans
- case 0xF6D9: // copyrightserif
- return 0x00A9; // copyright
- default:
- return code;
+var SpecialPUASymbols = {
+ '63721': 0x00A9, // copyrightsans (0xF8E9) => copyright
+ '63193': 0x00A9, // copyrightserif (0xF6D9) => copyright
+ '63720': 0x00AE, // registersans (0xF8E8) => registered
+ '63194': 0x00AE, // registerserif (0xF6DA) => registered
+ '63722': 0x2122, // trademarksans (0xF8EA) => trademark
+ '63195': 0x2122, // trademarkserif (0xF6DB) => trademark
+ '63729': 0x23A7, // bracelefttp (0xF8F1)
+ '63730': 0x23A8, // braceleftmid (0xF8F2)
+ '63731': 0x23A9, // braceleftbt (0xF8F3)
+ '63740': 0x23AB, // bracerighttp (0xF8FC)
+ '63741': 0x23AC, // bracerightmid (0xF8FD)
+ '63742': 0x23AD, // bracerightmid (0xF8FE)
+ '63726': 0x23A1, // bracketlefttp (0xF8EE)
+ '63727': 0x23A2, // bracketleftex (0xF8EF)
+ '63728': 0x23A3, // bracketleftbt (0xF8F0)
+ '63737': 0x23A4, // bracketrighttp (0xF8F9)
+ '63738': 0x23A5, // bracketrightex (0xF8FA)
+ '63739': 0x23A6, // bracketrightbt (0xF8FB)
+ '63723': 0x239B, // parenlefttp (0xF8EB)
+ '63724': 0x239C, // parenleftex (0xF8EC)
+ '63725': 0x239D, // parenleftbt (0xF8ED)
+ '63734': 0x239E, // parenrighttp (0xF8F6)
+ '63735': 0x239F, // parenrightex (0xF8F7)
+ '63736': 0x23A0, // parenrightbt (0xF8F8)
+};
+function mapSpecialUnicodeValues(code) {
+ if (code >= 0xFFF0 && code <= 0xFFFF) { // Specials unicode block.
+ return 0;
+ } else if (code >= 0xF600 && code <= 0xF8FF) {
+ return (SpecialPUASymbols[code] || code);
}
+ return code;
}
var UnicodeRanges = [
@@ -16944,28 +14749,25 @@ var MacStandardGlyphOrdering = [
function getUnicodeRangeFor(value) {
for (var i = 0, ii = UnicodeRanges.length; i < ii; i++) {
var range = UnicodeRanges[i];
- if (value >= range.begin && value < range.end)
+ if (value >= range.begin && value < range.end) {
return i;
+ }
}
return -1;
}
function isRTLRangeFor(value) {
var range = UnicodeRanges[13];
- if (value >= range.begin && value < range.end)
+ if (value >= range.begin && value < range.end) {
return true;
+ }
range = UnicodeRanges[11];
- if (value >= range.begin && value < range.end)
+ if (value >= range.begin && value < range.end) {
return true;
+ }
return false;
}
-function isSpecialUnicode(unicode) {
- return (unicode <= 0x1F || (unicode >= 127 && unicode < GLYPH_AREA_SIZE)) ||
- (unicode >= CMAP_GLYPH_OFFSET &&
- unicode < CMAP_GLYPH_OFFSET + GLYPH_AREA_SIZE);
-}
-
// The normalization table is obtained by filtering the Unicode characters
// database with entries.
var NormalizedUnicodes = {
@@ -18351,29 +16153,14 @@ var NormalizedUnicodes = {
function reverseIfRtl(chars) {
var charsLength = chars.length;
//reverse an arabic ligature
- if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0)))
+ if (charsLength <= 1 || !isRTLRangeFor(chars.charCodeAt(0))) {
return chars;
-
- var s = '';
- for (var ii = charsLength - 1; ii >= 0; ii--)
- s += chars[ii];
- return s;
-}
-
-function fontCharsToUnicode(charCodes, font) {
- var glyphs = font.charsToGlyphs(charCodes);
- var result = '';
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var glyph = glyphs[i];
- if (!glyph)
- continue;
-
- var glyphUnicode = glyph.unicode;
- if (glyphUnicode in NormalizedUnicodes)
- glyphUnicode = NormalizedUnicodes[glyphUnicode];
- result += reverseIfRtl(glyphUnicode);
}
- return result;
+ var s = '';
+ for (var ii = charsLength - 1; ii >= 0; ii--) {
+ s += chars[ii];
+ }
+ return s;
}
function adjustWidths(properties) {
@@ -18389,6 +16176,254 @@ function adjustWidths(properties) {
properties.defaultWidth *= scale;
}
+function getFontType(type, subtype) {
+ switch (type) {
+ case 'Type1':
+ return subtype === 'Type1C' ? FontType.TYPE1C : FontType.TYPE1;
+ case 'CIDFontType0':
+ return subtype === 'CIDFontType0C' ? FontType.CIDFONTTYPE0C :
+ FontType.CIDFONTTYPE0;
+ case 'OpenType':
+ return FontType.OPENTYPE;
+ case 'TrueType':
+ return FontType.TRUETYPE;
+ case 'CIDFontType2':
+ return FontType.CIDFONTTYPE2;
+ case 'MMType1':
+ return FontType.MMTYPE1;
+ case 'Type0':
+ return FontType.TYPE0;
+ default:
+ return FontType.UNKNOWN;
+ }
+}
+
+var Glyph = (function GlyphClosure() {
+ function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId) {
+ this.fontChar = fontChar;
+ this.unicode = unicode;
+ this.accent = accent;
+ this.width = width;
+ this.vmetric = vmetric;
+ this.operatorListId = operatorListId;
+ }
+
+ Glyph.prototype.matchesForCache =
+ function(fontChar, unicode, accent, width, vmetric, operatorListId) {
+ return this.fontChar === fontChar &&
+ this.unicode === unicode &&
+ this.accent === accent &&
+ this.width === width &&
+ this.vmetric === vmetric &&
+ this.operatorListId === operatorListId;
+ };
+
+ return Glyph;
+})();
+
+var ToUnicodeMap = (function ToUnicodeMapClosure() {
+ function ToUnicodeMap(cmap) {
+ // The elements of this._map can be integers or strings, depending on how
+ // |cmap| was created.
+ this._map = cmap;
+ }
+
+ ToUnicodeMap.prototype = {
+ get length() {
+ return this._map.length;
+ },
+
+ forEach: function(callback) {
+ for (var charCode in this._map) {
+ callback(charCode, this._map[charCode].charCodeAt(0));
+ }
+ },
+
+ get: function(i) {
+ return this._map[i];
+ },
+
+ charCodeOf: function(v) {
+ return this._map.indexOf(v);
+ }
+ };
+
+ return ToUnicodeMap;
+})();
+
+var IdentityToUnicodeMap = (function IdentityToUnicodeMapClosure() {
+ function IdentityToUnicodeMap(firstChar, lastChar) {
+ this.firstChar = firstChar;
+ this.lastChar = lastChar;
+ }
+
+ IdentityToUnicodeMap.prototype = {
+ get length() {
+ error('should not access .length');
+ },
+
+ forEach: function (callback) {
+ for (var i = this.firstChar, ii = this.lastChar; i <= ii; i++) {
+ callback(i, i);
+ }
+ },
+
+ get: function (i) {
+ if (this.firstChar <= i && i <= this.lastChar) {
+ return String.fromCharCode(i);
+ }
+ return undefined;
+ },
+
+ charCodeOf: function (v) {
+ error('should not call .charCodeOf');
+ }
+ };
+
+ return IdentityToUnicodeMap;
+})();
+
+var OpenTypeFileBuilder = (function OpenTypeFileBuilderClosure() {
+ function writeInt16(dest, offset, num) {
+ dest[offset] = (num >> 8) & 0xFF;
+ dest[offset + 1] = num & 0xFF;
+ }
+
+ function writeInt32(dest, offset, num) {
+ dest[offset] = (num >> 24) & 0xFF;
+ dest[offset + 1] = (num >> 16) & 0xFF;
+ dest[offset + 2] = (num >> 8) & 0xFF;
+ dest[offset + 3] = num & 0xFF;
+ }
+
+ function writeData(dest, offset, data) {
+ var i, ii;
+ if (data instanceof Uint8Array) {
+ dest.set(data, offset);
+ } else if (typeof data === 'string') {
+ for (i = 0, ii = data.length; i < ii; i++) {
+ dest[offset++] = data.charCodeAt(i) & 0xFF;
+ }
+ } else {
+ // treating everything else as array
+ for (i = 0, ii = data.length; i < ii; i++) {
+ dest[offset++] = data[i] & 0xFF;
+ }
+ }
+ }
+
+ function OpenTypeFileBuilder(sfnt) {
+ this.sfnt = sfnt;
+ this.tables = Object.create(null);
+ }
+
+ OpenTypeFileBuilder.getSearchParams =
+ function OpenTypeFileBuilder_getSearchParams(entriesCount, entrySize) {
+ var maxPower2 = 1, log2 = 0;
+ while ((maxPower2 ^ entriesCount) > maxPower2) {
+ maxPower2 <<= 1;
+ log2++;
+ }
+ var searchRange = maxPower2 * entrySize;
+ return {
+ range: searchRange,
+ entry: log2,
+ rangeShift: entrySize * entriesCount - searchRange
+ };
+ };
+
+ var OTF_HEADER_SIZE = 12;
+ var OTF_TABLE_ENTRY_SIZE = 16;
+
+ OpenTypeFileBuilder.prototype = {
+ toArray: function OpenTypeFileBuilder_toArray() {
+ var sfnt = this.sfnt;
+
+ // Tables needs to be written by ascendant alphabetic order
+ var tables = this.tables;
+ var tablesNames = Object.keys(tables);
+ tablesNames.sort();
+ var numTables = tablesNames.length;
+
+ var i, j, jj, table, tableName;
+ // layout the tables data
+ var offset = OTF_HEADER_SIZE + numTables * OTF_TABLE_ENTRY_SIZE;
+ var tableOffsets = [offset];
+ for (i = 0; i < numTables; i++) {
+ table = tables[tablesNames[i]];
+ var paddedLength = ((table.length + 3) & ~3) >>> 0;
+ offset += paddedLength;
+ tableOffsets.push(offset);
+ }
+
+ var file = new Uint8Array(offset);
+ // write the table data first (mostly for checksum)
+ for (i = 0; i < numTables; i++) {
+ table = tables[tablesNames[i]];
+ writeData(file, tableOffsets[i], table);
+ }
+
+ // sfnt version (4 bytes)
+ if (sfnt === 'true') {
+ // Windows hates the Mac TrueType sfnt version number
+ sfnt = string32(0x00010000);
+ }
+ file[0] = sfnt.charCodeAt(0) & 0xFF;
+ file[1] = sfnt.charCodeAt(1) & 0xFF;
+ file[2] = sfnt.charCodeAt(2) & 0xFF;
+ file[3] = sfnt.charCodeAt(3) & 0xFF;
+
+ // numTables (2 bytes)
+ writeInt16(file, 4, numTables);
+
+ var searchParams = OpenTypeFileBuilder.getSearchParams(numTables, 16);
+
+ // searchRange (2 bytes)
+ writeInt16(file, 6, searchParams.range);
+ // entrySelector (2 bytes)
+ writeInt16(file, 8, searchParams.entry);
+ // rangeShift (2 bytes)
+ writeInt16(file, 10, searchParams.rangeShift);
+
+ offset = OTF_HEADER_SIZE;
+ // writing table entries
+ for (i = 0; i < numTables; i++) {
+ tableName = tablesNames[i];
+ file[offset] = tableName.charCodeAt(0) & 0xFF;
+ file[offset + 1] = tableName.charCodeAt(1) & 0xFF;
+ file[offset + 2] = tableName.charCodeAt(2) & 0xFF;
+ file[offset + 3] = tableName.charCodeAt(3) & 0xFF;
+
+ // checksum
+ var checksum = 0;
+ for (j = tableOffsets[i], jj = tableOffsets[i + 1]; j < jj; j += 4) {
+ var quad = (file[j] << 24) + (file[j + 1] << 16) +
+ (file[j + 2] << 8) + file[j + 3];
+ checksum = (checksum + quad) | 0;
+ }
+ writeInt32(file, offset + 4, checksum);
+
+ // offset
+ writeInt32(file, offset + 8, tableOffsets[i]);
+ // length
+ writeInt32(file, offset + 12, tables[tableName].length);
+
+ offset += OTF_TABLE_ENTRY_SIZE;
+ }
+ return file;
+ },
+
+ addTable: function OpenTypeFileBuilder_addTable(tag, data) {
+ if (tag in this.tables) {
+ throw new Error('Table ' + tag + ' already exists');
+ }
+ this.tables[tag] = data;
+ }
+ };
+
+ return OpenTypeFileBuilder;
+})();
+
/**
* 'Font' is the class the outside world should use, it encapsulate all the font
* decoding logics whatever type it is (assuming the font type is supported).
@@ -18399,13 +16434,15 @@ function adjustWidths(properties) {
*/
var Font = (function FontClosure() {
function Font(name, file, properties) {
+ var charCode, glyphName, fontChar;
this.name = name;
this.loadedName = properties.loadedName;
- this.coded = properties.coded;
- this.loadCharProcs = properties.coded;
+ this.isType3Font = properties.isType3Font;
this.sizes = [];
+ this.glyphCache = {};
+
var names = name.split('+');
names = names.length > 1 ? names[1] : names[0];
names = names.split(/[-,_]/g)[0];
@@ -18414,27 +16451,35 @@ var Font = (function FontClosure() {
this.isMonospace = !!(properties.flags & FontFlags.FixedPitch);
var type = properties.type;
+ var subtype = properties.subtype;
this.type = type;
- this.fallbackName = this.isMonospace ? 'monospace' :
- this.isSerifFont ? 'serif' : 'sans-serif';
+ this.fallbackName = (this.isMonospace ? 'monospace' :
+ (this.isSerifFont ? 'serif' : 'sans-serif'));
this.differences = properties.differences;
this.widths = properties.widths;
this.defaultWidth = properties.defaultWidth;
this.composite = properties.composite;
this.wideChars = properties.wideChars;
- this.hasEncoding = properties.hasEncoding;
- this.cmap = properties.cmap;
-
+ this.cMap = properties.cMap;
+ this.ascent = properties.ascent / PDF_GLYPH_SPACE_UNITS;
+ this.descent = properties.descent / PDF_GLYPH_SPACE_UNITS;
this.fontMatrix = properties.fontMatrix;
- if (properties.type == 'Type3') {
- this.encoding = properties.baseEncoding;
+
+ this.toUnicode = properties.toUnicode = this.buildToUnicode(properties);
+
+ this.toFontChar = [];
+
+ if (properties.type === 'Type3') {
+ for (charCode = 0; charCode < 256; charCode++) {
+ this.toFontChar[charCode] = (this.differences[charCode] ||
+ properties.defaultEncoding[charCode]);
+ }
+ this.fontType = FontType.TYPE3;
return;
}
- // Trying to fix encoding using glyph CIDSystemInfo.
- this.loadCidToUnicode(properties);
this.cidEncoding = properties.cidEncoding;
this.vertical = properties.vertical;
if (this.vertical) {
@@ -18442,33 +16487,30 @@ var Font = (function FontClosure() {
this.defaultVMetrics = properties.defaultVMetrics;
}
- if (properties.toUnicode && properties.toUnicode.length > 0)
- this.toUnicode = properties.toUnicode;
- else
- this.rebuildToUnicode(properties);
+ if (!file || file.isEmpty) {
+ if (file) {
+ // Some bad PDF generators will include empty font files,
+ // attempting to recover by assuming that no file exists.
+ warn('Font file is empty in "' + name + '" (' + this.loadedName + ')');
+ }
- this.toFontChar = this.buildToFontChar(this.toUnicode);
-
- if (!file) {
+ this.missingFile = true;
// The file data is not specified. Trying to fix the font name
// to be used with the canvas.font.
var fontName = name.replace(/[,_]/g, '-');
var isStandardFont = fontName in stdFontMap;
fontName = stdFontMap[fontName] || nonStdFontMap[fontName] || fontName;
- this.bold = (fontName.search(/bold/gi) != -1);
- this.italic = (fontName.search(/oblique/gi) != -1) ||
- (fontName.search(/italic/gi) != -1);
+ this.bold = (fontName.search(/bold/gi) !== -1);
+ this.italic = ((fontName.search(/oblique/gi) !== -1) ||
+ (fontName.search(/italic/gi) !== -1));
// Use 'name' instead of 'fontName' here because the original
// name ArialBlack for example will be replaced by Helvetica.
- this.black = (name.search(/Black/g) != -1);
+ this.black = (name.search(/Black/g) !== -1);
// if at least one width is present, remeasure all chars when exists
this.remeasure = Object.keys(this.widths).length > 0;
-
- this.encoding = properties.baseEncoding;
- this.noUnicodeAdaptation = true;
if (isStandardFont && type === 'CIDFontType2' &&
properties.cidEncoding.indexOf('Identity-') === 0) {
// Standard fonts might be embedded as CID font without glyph mapping.
@@ -18477,20 +16519,82 @@ var Font = (function FontClosure() {
for (var code in GlyphMapForStandardFonts) {
map[+code] = GlyphMapForStandardFonts[code];
}
+ var isIdentityUnicode = this.toUnicode instanceof IdentityToUnicodeMap;
+ if (!isIdentityUnicode) {
+ this.toUnicode.forEach(function(charCode, unicodeCharCode) {
+ map[+charCode] = unicodeCharCode;
+ });
+ }
this.toFontChar = map;
- this.toUnicode = map;
+ this.toUnicode = new ToUnicodeMap(map);
+ } else if (/Symbol/i.test(fontName)) {
+ var symbols = Encodings.SymbolSetEncoding;
+ for (charCode in symbols) {
+ fontChar = GlyphsUnicode[symbols[charCode]];
+ if (!fontChar) {
+ continue;
+ }
+ this.toFontChar[charCode] = fontChar;
+ }
+ for (charCode in properties.differences) {
+ fontChar = GlyphsUnicode[properties.differences[charCode]];
+ if (!fontChar) {
+ continue;
+ }
+ this.toFontChar[charCode] = fontChar;
+ }
+ } else if (/Dingbats/i.test(fontName)) {
+ var dingbats = Encodings.ZapfDingbatsEncoding;
+ for (charCode in dingbats) {
+ fontChar = DingbatsGlyphsUnicode[dingbats[charCode]];
+ if (!fontChar) {
+ continue;
+ }
+ this.toFontChar[charCode] = fontChar;
+ }
+ for (charCode in properties.differences) {
+ fontChar = DingbatsGlyphsUnicode[properties.differences[charCode]];
+ if (!fontChar) {
+ continue;
+ }
+ this.toFontChar[charCode] = fontChar;
+ }
+ } else if (isStandardFont) {
+ this.toFontChar = [];
+ for (charCode in properties.defaultEncoding) {
+ glyphName = (properties.differences[charCode] ||
+ properties.defaultEncoding[charCode]);
+ this.toFontChar[charCode] = GlyphsUnicode[glyphName];
+ }
+ } else {
+ var unicodeCharCode, notCidFont = (type.indexOf('CIDFontType') === -1);
+ this.toUnicode.forEach(function(charCode, unicodeCharCode) {
+ if (notCidFont) {
+ glyphName = (properties.differences[charCode] ||
+ properties.defaultEncoding[charCode]);
+ unicodeCharCode = (GlyphsUnicode[glyphName] || unicodeCharCode);
+ }
+ this.toFontChar[charCode] = unicodeCharCode;
+ }.bind(this));
}
this.loadedName = fontName.split('-')[0];
this.loading = false;
+ this.fontType = getFontType(type, subtype);
return;
}
// Some fonts might use wrong font types for Type1C or CIDFontType0C
- var subtype = properties.subtype;
- if (subtype == 'Type1C' && (type != 'Type1' && type != 'MMType1'))
- type = 'Type1';
- if (subtype == 'CIDFontType0C' && type != 'CIDFontType0')
+ if (subtype === 'Type1C' && (type !== 'Type1' && type !== 'MMType1')) {
+ // Some TrueType fonts by mistake claim Type1C
+ if (isTrueTypeFile(file)) {
+ subtype = 'TrueType';
+ } else {
+ type = 'Type1';
+ }
+ }
+ if (subtype === 'CIDFontType0C' && type !== 'CIDFontType0') {
type = 'CIDFontType0';
+ }
// XXX: Temporarily change the type for open type so we trigger a warning.
// This should be removed when we add support for open type.
if (subtype === 'OpenType') {
@@ -18499,11 +16603,14 @@ var Font = (function FontClosure() {
var data;
switch (type) {
+ case 'MMType1':
+ info('MMType1 font (' + name + '), falling back to Type1.');
+ /* falls through */
case 'Type1':
case 'CIDFontType0':
this.mimetype = 'font/opentype';
- var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
+ var cff = (subtype === 'Type1C' || subtype === 'CIDFontType0C') ?
new CFFFont(file, properties) : new Type1Font(name, file, properties);
adjustWidths(properties);
@@ -18520,6 +16627,9 @@ var Font = (function FontClosure() {
// Repair the TrueType file. It is can be damaged in the point of
// view of the sanitizer
data = this.checkAndRepair(name, file, properties);
+ if (this.isOpenType) {
+ type = 'OpenType';
+ }
break;
default:
@@ -18528,6 +16638,7 @@ var Font = (function FontClosure() {
}
this.data = data;
+ this.fontType = getFontType(type, subtype);
// Transfer some properties again that could change during font conversion
this.fontMatrix = properties.fontMatrix;
@@ -18539,144 +16650,140 @@ var Font = (function FontClosure() {
this.loading = true;
}
- var numFonts = 0;
- function getUniqueName() {
- return 'pdfFont' + numFonts++;
+ Font.getFontID = (function () {
+ var ID = 1;
+ return function Font_getFontID() {
+ return String(ID++);
+ };
+ })();
+
+ function int16(b0, b1) {
+ return (b0 << 8) + b1;
}
- function stringToArray(str) {
- var array = [];
- for (var i = 0, ii = str.length; i < ii; ++i)
- array[i] = str.charCodeAt(i);
-
- return array;
- }
-
- function arrayToString(arr) {
- var str = '';
- for (var i = 0, ii = arr.length; i < ii; ++i)
- str += String.fromCharCode(arr[i]);
-
- return str;
- }
-
- function int16(bytes) {
- return (bytes[0] << 8) + (bytes[1] & 0xff);
- }
-
- function int32(bytes) {
- return (bytes[0] << 24) + (bytes[1] << 16) +
- (bytes[2] << 8) + (bytes[3] & 0xff);
- }
-
- function getMaxPower2(number) {
- var maxPower = 0;
- var value = number;
- while (value >= 2) {
- value /= 2;
- maxPower++;
- }
-
- value = 2;
- for (var i = 1; i < maxPower; i++)
- value *= 2;
- return value;
+ function int32(b0, b1, b2, b3) {
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
}
function string16(value) {
- return String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
+ return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
}
function safeString16(value) {
// clamp value to the 16-bit int range
- value = value > 0x7FFF ? 0x7FFF : value < -0x8000 ? -0x8000 : value;
- return String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
+ value = (value > 0x7FFF ? 0x7FFF : (value < -0x8000 ? -0x8000 : value));
+ return String.fromCharCode((value >> 8) & 0xff, value & 0xff);
}
- function string32(value) {
- return String.fromCharCode((value >> 24) & 0xff) +
- String.fromCharCode((value >> 16) & 0xff) +
- String.fromCharCode((value >> 8) & 0xff) +
- String.fromCharCode(value & 0xff);
+ function isTrueTypeFile(file) {
+ var header = file.peekBytes(4);
+ return readUint32(header, 0) === 0x00010000;
}
- function createOpenTypeHeader(sfnt, file, numTables) {
- // Windows hates the Mac TrueType sfnt version number
- if (sfnt == 'true')
- sfnt = string32(0x00010000);
+ /**
+ * Rebuilds the char code to glyph ID map by trying to replace the char codes
+ * with their unicode value. It also moves char codes that are in known
+ * problematic locations.
+ * @return {Object} Two properties:
+ * 'toFontChar' - maps original char codes(the value that will be read
+ * from commands such as show text) to the char codes that will be used in the
+ * font that we build
+ * 'charCodeToGlyphId' - maps the new font char codes to glyph ids
+ */
+ function adjustMapping(charCodeToGlyphId, properties) {
+ var toUnicode = properties.toUnicode;
+ var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
+ var isIdentityUnicode =
+ properties.toUnicode instanceof IdentityToUnicodeMap;
+ var isCidFontType2 = (properties.type === 'CIDFontType2');
+ var newMap = Object.create(null);
+ var toFontChar = [];
+ var usedFontCharCodes = [];
+ var nextAvailableFontCharCode = PRIVATE_USE_OFFSET_START;
+ for (var originalCharCode in charCodeToGlyphId) {
+ originalCharCode |= 0;
+ var glyphId = charCodeToGlyphId[originalCharCode];
+ var fontCharCode = originalCharCode;
+ // First try to map the value to a unicode position if a non identity map
+ // was created.
+ if (!isIdentityUnicode) {
+ if (toUnicode.get(originalCharCode) !== undefined) {
+ var unicode = toUnicode.get(fontCharCode);
+ // TODO: Try to map ligatures to the correct spot.
+ if (unicode.length === 1) {
+ fontCharCode = unicode.charCodeAt(0);
+ }
+ } else if (isCidFontType2) {
+ // For CIDFontType2, move characters not present in toUnicode
+ // to the private use area (fixes bug 1028735 and issue 4881).
+ fontCharCode = nextAvailableFontCharCode;
+ }
+ }
+ // Try to move control characters, special characters and already mapped
+ // characters to the private use area since they will not be drawn by
+ // canvas if left in their current position. Also, move characters if the
+ // font was symbolic and there is only an identity unicode map since the
+ // characters probably aren't in the correct position (fixes an issue
+ // with firefox and thuluthfont).
+ if ((usedFontCharCodes[fontCharCode] !== undefined ||
+ fontCharCode <= 0x1f || // Control chars
+ fontCharCode === 0x7F || // Control char
+ fontCharCode === 0xAD || // Soft hyphen
+ (fontCharCode >= 0x80 && fontCharCode <= 0x9F) || // Control chars
+ // Prevent drawing characters in the specials unicode block.
+ (fontCharCode >= 0xFFF0 && fontCharCode <= 0xFFFF) ||
+ (isSymbolic && isIdentityUnicode)) &&
+ nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left.
+ // Loop to try and find a free spot in the private use area.
+ do {
+ fontCharCode = nextAvailableFontCharCode++;
- // sfnt version (4 bytes)
- var header = sfnt;
+ if (SKIP_PRIVATE_USE_RANGE_F000_TO_F01F && fontCharCode === 0xF000) {
+ fontCharCode = 0xF020;
+ nextAvailableFontCharCode = fontCharCode + 1;
+ }
- // numTables (2 bytes)
- header += string16(numTables);
+ } while (usedFontCharCodes[fontCharCode] !== undefined &&
+ nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END);
+ }
- // searchRange (2 bytes)
- var tablesMaxPower2 = getMaxPower2(numTables);
- var searchRange = tablesMaxPower2 * 16;
- header += string16(searchRange);
-
- // entrySelector (2 bytes)
- header += string16(Math.log(tablesMaxPower2) / Math.log(2));
-
- // rangeShift (2 bytes)
- header += string16(numTables * 16 - searchRange);
-
- file.file += header;
- file.virtualOffset += header.length;
+ newMap[fontCharCode] = glyphId;
+ toFontChar[originalCharCode] = fontCharCode;
+ usedFontCharCodes[fontCharCode] = true;
+ }
+ return {
+ toFontChar: toFontChar,
+ charCodeToGlyphId: newMap,
+ nextAvailableFontCharCode: nextAvailableFontCharCode
+ };
}
- function createTableEntry(file, tag, data) {
- // offset
- var offset = file.virtualOffset;
-
- // length
- var length = data.length;
-
- // Per spec tables must be 4-bytes align so add padding as needed
- while (data.length & 3)
- data.push(0x00);
-
- while (file.virtualOffset & 3)
- file.virtualOffset++;
-
- // checksum
- var checksum = 0, n = data.length;
- for (var i = 0; i < n; i += 4)
- checksum = (checksum + int32([data[i], data[i + 1], data[i + 2],
- data[i + 3]])) | 0;
-
- var tableEntry = (tag + string32(checksum) +
- string32(offset) + string32(length));
- file.file += tableEntry;
- file.virtualOffset += data.length;
- }
-
- function getRanges(glyphs, deltas) {
+ function getRanges(glyphs) {
// Array.sort() sorts by characters, not numerically, so convert to an
// array of characters.
var codes = [];
- var length = glyphs.length;
- for (var n = 0; n < length; ++n)
- codes.push({ unicode: glyphs[n].unicode, code: n });
+ for (var charCode in glyphs) {
+ codes.push({ fontCharCode: charCode | 0, glyphId: glyphs[charCode] });
+ }
codes.sort(function fontGetRangesSort(a, b) {
- return a.unicode - b.unicode;
+ return a.fontCharCode - b.fontCharCode;
});
// Split the sorted codes into ranges.
var ranges = [];
+ var length = codes.length;
for (var n = 0; n < length; ) {
- var start = codes[n].unicode;
- var codeIndices = [deltas ? deltas[codes[n].code] : codes[n].code + 1];
+ var start = codes[n].fontCharCode;
+ var codeIndices = [codes[n].glyphId];
++n;
var end = start;
- while (n < length && end + 1 == codes[n].unicode) {
- codeIndices.push(deltas ? deltas[codes[n].code] : codes[n].code + 1);
+ while (n < length && end + 1 === codes[n].fontCharCode) {
+ codeIndices.push(codes[n].glyphId);
++end;
++n;
- if (end === 0xFFFF) { break; }
+ if (end === 0xFFFF) {
+ break;
+ }
}
ranges.push([start, end, codeIndices]);
}
@@ -18684,9 +16791,8 @@ var Font = (function FontClosure() {
return ranges;
}
- function createCmapTable(glyphs, deltas) {
- var ranges = getRanges(glyphs, deltas);
-
+ function createCmapTable(glyphs) {
+ var ranges = getRanges(glyphs);
var numTables = ranges[ranges.length - 1][1] > 0xFFFF ? 2 : 1;
var cmap = '\x00\x00' + // version
string16(numTables) + // numTables
@@ -18694,7 +16800,8 @@ var Font = (function FontClosure() {
'\x00\x01' + // encodingID
string32(4 + numTables * 8); // start of the table record
- for (var i = ranges.length - 1; i >= 0; --i) {
+ var i, ii, j, jj;
+ for (i = ranges.length - 1; i >= 0; --i) {
if (ranges[i][0] <= 0xFFFF) { break; }
}
var bmpLength = i + 1;
@@ -18704,10 +16811,7 @@ var Font = (function FontClosure() {
}
var trailingRangesCount = ranges[i][1] < 0xFFFF ? 1 : 0;
var segCount = bmpLength + trailingRangesCount;
- var segCount2 = segCount * 2;
- var searchRange = getMaxPower2(segCount) * 2;
- var searchEntry = Math.log(segCount) / Math.log(2);
- var rangeShift = 2 * segCount - searchRange;
+ var searchParams = OpenTypeFileBuilder.getSearchParams(segCount, 2);
// Fill up the 4 parallel arrays describing the segments.
var startCount = '';
@@ -18717,15 +16821,16 @@ var Font = (function FontClosure() {
var glyphsIds = '';
var bias = 0;
- for (var i = 0, ii = bmpLength; i < ii; i++) {
- var range = ranges[i];
- var start = range[0];
- var end = range[1];
+ var range, start, end, codes;
+ for (i = 0, ii = bmpLength; i < ii; i++) {
+ range = ranges[i];
+ start = range[0];
+ end = range[1];
startCount += string16(start);
endCount += string16(end);
- var codes = range[2];
+ codes = range[2];
var contiguous = true;
- for (var j = 1, jj = codes.length; j < jj; ++j) {
+ for (j = 1, jj = codes.length; j < jj; ++j) {
if (codes[j] !== codes[j - 1] + 1) {
contiguous = false;
break;
@@ -18738,7 +16843,7 @@ var Font = (function FontClosure() {
idDeltas += string16(0);
idRangeOffsets += string16(offset);
- for (var j = 0, jj = codes.length; j < jj; ++j) {
+ for (j = 0, jj = codes.length; j < jj; ++j) {
glyphsIds += string16(codes[j]);
}
} else {
@@ -18757,10 +16862,10 @@ var Font = (function FontClosure() {
}
var format314 = '\x00\x00' + // language
- string16(segCount2) +
- string16(searchRange) +
- string16(searchEntry) +
- string16(rangeShift) +
+ string16(2 * segCount) +
+ string16(searchParams.range) +
+ string16(searchParams.entry) +
+ string16(searchParams.rangeShift) +
endCount + '\x00\x00' + startCount +
idDeltas + idRangeOffsets + glyphsIds;
@@ -18772,14 +16877,14 @@ var Font = (function FontClosure() {
string32(4 + numTables * 8 +
4 + format314.length); // start of the table record
format31012 = '';
- for (var i = 0, ii = ranges.length; i < ii; i++) {
- var range = ranges[i];
- var start = range[0];
- var codes = range[2];
+ for (i = 0, ii = ranges.length; i < ii; i++) {
+ range = ranges[i];
+ start = range[0];
+ codes = range[2];
var code = codes[0];
- for (var j = 1, jj = codes.length; j < jj; ++j) {
+ for (j = 1, jj = codes.length; j < jj; ++j) {
if (codes[j] !== codes[j - 1] + 1) {
- var end = range[0] + j - 1;
+ end = range[0] + j - 1;
format31012 += string32(start) + // startCharCode
string32(end) + // endCharCode
string32(code); // startGlyphID
@@ -18798,29 +16903,28 @@ var Font = (function FontClosure() {
string32(format31012.length / 12); // nGroups
}
- return stringToArray(cmap +
- '\x00\x04' + // format
- string16(format314.length + 4) + // length
- format314 + header31012 + format31012);
+ return cmap + '\x00\x04' + // format
+ string16(format314.length + 4) + // length
+ format314 + header31012 + format31012;
}
function validateOS2Table(os2) {
var stream = new Stream(os2.data);
- var version = int16(stream.getBytes(2));
+ var version = stream.getUint16();
// TODO verify all OS/2 tables fields, but currently we validate only those
// that give us issues
stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges
- var selection = int16(stream.getBytes(2));
+ var selection = stream.getUint16();
if (version < 4 && (selection & 0x0300)) {
return false;
}
- var firstChar = int16(stream.getBytes(2));
- var lastChar = int16(stream.getBytes(2));
+ var firstChar = stream.getUint16();
+ var lastChar = stream.getUint16();
if (firstChar > lastChar) {
return false;
}
stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
- var usWinAscent = int16(stream.getBytes(2));
+ var usWinAscent = stream.getUint16();
if (usWinAscent === 0) { // makes font unreadable by windows
return false;
}
@@ -18848,12 +16952,14 @@ var Font = (function FontClosure() {
var lastCharIndex = 0;
if (charstrings) {
- for (var i = 0; i < charstrings.length; ++i) {
- var code = charstrings[i].unicode;
- if (firstCharIndex > code || !firstCharIndex)
+ for (var code in charstrings) {
+ code |= 0;
+ if (firstCharIndex > code || !firstCharIndex) {
firstCharIndex = code;
- if (lastCharIndex < code)
+ }
+ if (lastCharIndex < code) {
lastCharIndex = code;
+ }
var position = getUnicodeRangeFor(code);
if (position < 32) {
@@ -18875,18 +16981,18 @@ var Font = (function FontClosure() {
}
var bbox = properties.bbox || [0, 0, 0, 0];
- var unitsPerEm = override.unitsPerEm ||
- 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
+ var unitsPerEm = (override.unitsPerEm ||
+ 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0]);
// if the font units differ to the PDF glyph space units
// then scale up the values
- var scale = properties.ascentScaled ? 1.0 :
- unitsPerEm / PDF_GLYPH_SPACE_UNITS;
+ var scale = (properties.ascentScaled ? 1.0 :
+ unitsPerEm / PDF_GLYPH_SPACE_UNITS);
- var typoAscent = override.ascent || Math.round(scale *
- (properties.ascent || bbox[3]));
- var typoDescent = override.descent || Math.round(scale *
- (properties.descent || bbox[1]));
+ var typoAscent = (override.ascent ||
+ Math.round(scale * (properties.ascent || bbox[3])));
+ var typoDescent = (override.descent ||
+ Math.round(scale * (properties.descent || bbox[1])));
if (typoDescent > 0 && properties.descent > 0 && bbox[1] < 0) {
typoDescent = -typoDescent; // fixing incorrect descent
}
@@ -18937,15 +17043,15 @@ var Font = (function FontClosure() {
function createPostTable(properties) {
var angle = Math.floor(properties.italicAngle * (Math.pow(2, 16)));
- return '\x00\x03\x00\x00' + // Version number
- string32(angle) + // italicAngle
- '\x00\x00' + // underlinePosition
- '\x00\x00' + // underlineThickness
- string32(properties.fixedPitch) + // isFixedPitch
- '\x00\x00\x00\x00' + // minMemType42
- '\x00\x00\x00\x00' + // maxMemType42
- '\x00\x00\x00\x00' + // minMemType1
- '\x00\x00\x00\x00'; // maxMemType1
+ return ('\x00\x03\x00\x00' + // Version number
+ string32(angle) + // italicAngle
+ '\x00\x00' + // underlinePosition
+ '\x00\x00' + // underlineThickness
+ string32(properties.fixedPitch) + // isFixedPitch
+ '\x00\x00\x00\x00' + // minMemType42
+ '\x00\x00\x00\x00' + // maxMemType42
+ '\x00\x00\x00\x00' + // minMemType1
+ '\x00\x00\x00\x00'); // maxMemType1
}
function createNameTable(name, proto) {
@@ -18969,13 +17075,15 @@ var Font = (function FontClosure() {
// Mac want 1-byte per character strings while Windows want
// 2-bytes per character, so duplicate the names table
var stringsUnicode = [];
- for (var i = 0, ii = strings.length; i < ii; i++) {
- var str = proto[1][i] || strings[i];
+ var i, ii, j, jj, str;
+ for (i = 0, ii = strings.length; i < ii; i++) {
+ str = proto[1][i] || strings[i];
- var strUnicode = '';
- for (var j = 0, jj = str.length; j < jj; j++)
- strUnicode += string16(str.charCodeAt(j));
- stringsUnicode.push(strUnicode);
+ var strBufUnicode = [];
+ for (j = 0, jj = str.length; j < jj; j++) {
+ strBufUnicode.push(string16(str.charCodeAt(j)));
+ }
+ stringsUnicode.push(strBufUnicode.join(''));
}
var names = [strings, stringsUnicode];
@@ -18991,10 +17099,10 @@ var Font = (function FontClosure() {
// Build the name records field
var strOffset = 0;
- for (var i = 0, ii = platforms.length; i < ii; i++) {
+ for (i = 0, ii = platforms.length; i < ii; i++) {
var strs = names[i];
- for (var j = 0, jj = strs.length; j < jj; j++) {
- var str = strs[j];
+ for (j = 0, jj = strs.length; j < jj; j++) {
+ str = strs[j];
var nameRecord =
platforms[i] + // platform ID
encodings[i] + // encoding ID
@@ -19011,37 +17119,6 @@ var Font = (function FontClosure() {
return nameTable;
}
- // Normalize the charcodes in the cmap table into unicode values
- // that will work with the (3, 1) cmap table we will write out.
- function cmapCharcodeToUnicode(charcode, symbolic, platformId, encodingId) {
- var unicode;
- if (symbolic) {
- // These codes will be shifted into the range
- // SYMBOLIC_FONT_GLYPH_OFFSET to (SYMBOLIC_FONT_GLYPH_OFFSET + 0xFF)
- // so that they are not in the control character range that could
- // be displayed as spaces by browsers.
- if (platformId === 3 && encodingId === 0 ||
- platformId === 1 && encodingId === 0) {
- unicode = SYMBOLIC_FONT_GLYPH_OFFSET | (charcode & 0xFF);
- }
- } else {
- if (platformId === 3 && encodingId === 1) {
- // A (3, 1) table is alredy unicode (Microsoft Unicode format)
- unicode = charcode;
- } else if (platformId === 1 && encodingId === 0) {
- // TODO(mack): Should apply the changes to convert the
- // MacRomanEncoding to Mac OS Roman encoding in 9.6.6.4
- // table 115 of the pdf spec
- var glyphName = Encodings.MacRomanEncoding[charcode];
- if (glyphName) {
- unicode = GlyphsUnicode[glyphName];
- }
- }
- }
- return unicode;
- }
-
-
Font.prototype = {
name: null,
font: null,
@@ -19055,23 +17132,20 @@ var Font = (function FontClosure() {
exportData: function Font_exportData() {
var data = {};
for (var i in this) {
- if (this.hasOwnProperty(i))
+ if (this.hasOwnProperty(i)) {
data[i] = this[i];
+ }
}
return data;
},
checkAndRepair: function Font_checkAndRepair(name, font, properties) {
function readTableEntry(file) {
- var tag = file.getBytes(4);
- tag = String.fromCharCode(tag[0]) +
- String.fromCharCode(tag[1]) +
- String.fromCharCode(tag[2]) +
- String.fromCharCode(tag[3]);
+ var tag = bytesToString(file.getBytes(4));
- var checksum = int32(file.getBytes(4));
- var offset = int32(file.getBytes(4));
- var length = int32(file.getBytes(4));
+ var checksum = file.getInt32();
+ var offset = file.getInt32() >>> 0;
+ var length = file.getInt32() >>> 0;
// Read the table associated data
var previousPosition = file.pos;
@@ -19080,7 +17154,7 @@ var Font = (function FontClosure() {
var data = file.getBytes(length);
file.pos = previousPosition;
- if (tag == 'head') {
+ if (tag === 'head') {
// clearing checksum adjustment
data[8] = data[9] = data[10] = data[11] = 0;
data[17] |= 0x20; //Set font optimized for cleartype flag
@@ -19097,116 +17171,57 @@ var Font = (function FontClosure() {
function readOpenTypeHeader(ttf) {
return {
- version: arrayToString(ttf.getBytes(4)),
- numTables: int16(ttf.getBytes(2)),
- searchRange: int16(ttf.getBytes(2)),
- entrySelector: int16(ttf.getBytes(2)),
- rangeShift: int16(ttf.getBytes(2))
+ version: bytesToString(ttf.getBytes(4)),
+ numTables: ttf.getUint16(),
+ searchRange: ttf.getUint16(),
+ entrySelector: ttf.getUint16(),
+ rangeShift: ttf.getUint16()
};
}
- function createGlyphNameMap(glyphs, ids, properties) {
- var glyphNames = properties.glyphNames;
- if (!glyphNames) {
- properties.glyphNameMap = {};
- return;
- }
- var glyphsLength = glyphs.length;
- var glyphNameMap = {};
- var encoding = [];
- for (var i = 0; i < glyphsLength; ++i) {
- var glyphName = glyphNames[ids[i]];
- if (!glyphName)
- continue;
- var unicode = glyphs[i].unicode;
- glyphNameMap[glyphName] = unicode;
- var code = glyphs[i].code;
- encoding[code] = glyphName;
- }
- properties.glyphNameMap = glyphNameMap;
- if (properties.overridableEncoding)
- properties.baseEncoding = encoding;
- }
-
/**
* Read the appropriate subtable from the cmap according to 9.6.6.4 from
* PDF spec
*/
- function readCmapTable(cmap, font, hasEncoding, isSymbolicFont) {
+ function readCmapTable(cmap, font, isSymbolicFont) {
+ var segment;
var start = (font.start ? font.start : 0) + cmap.offset;
font.pos = start;
- var version = int16(font.getBytes(2));
- var numTables = int16(font.getBytes(2));
+ var version = font.getUint16();
+ var numTables = font.getUint16();
var potentialTable;
- var foundPreferredTable;
- // There's an order of preference in terms of which cmap subtable we
- // want to use. So scan through them to find our preferred table.
+ var canBreak = false;
+ // There's an order of preference in terms of which cmap subtable to
+ // use:
+ // - non-symbolic fonts the preference is a 3,1 table then a 1,0 table
+ // - symbolic fonts the preference is a 3,0 table then a 1,0 table
+ // The following takes advantage of the fact that the tables are sorted
+ // to work.
for (var i = 0; i < numTables; i++) {
- var platformId = int16(font.getBytes(2));
- var encodingId = int16(font.getBytes(2));
- var offset = int32(font.getBytes(4));
+ var platformId = font.getUint16();
+ var encodingId = font.getUint16();
+ var offset = font.getInt32() >>> 0;
var useTable = false;
- var canBreak = false;
- // The following block implements the following from the spec:
- //
- // When the font has no Encoding entry, or the font descriptor’s
- // Symbolic flag is set (in which case the Encoding entry
- // is ignored), this shall occur:
- // - If the font contains a (3, 0) subtable, the range of
- // - Otherwise, the (1, 0) subtable will be used.
- // Otherwise, if the font does have an encoding:
- // - Use the (3, 1) cmap subtable
- // - Otherwise, use the (1, 0) subtable if present
- //
- // The following diverges slightly from the above spec in order
- // to handle the case that hasEncoding and isSymbolicFont are both
- // true. In this, based on the ordering of the rules in the spec,
- // my interpretation is that we should be acting as if the font is
- // symbolic.
- //
- // However, in this case, the test pdf 'preistabelle.pdf'
- // is interpreting this case as a non-symbolic font. In this case
- // though, 'presitabelle.pdf' does contain a (3, 1) table and does
- // not contain a (3, 0) table which indicates it is non-symbolic.
- //
- // Thus, I am using this heurisitic of looking at which table is
- // found to truly determine whether or not the font is symbolic.
- // That is, if the specific symbolic/non-symbolic font specific
- // tables (3, 0) or (3, 1) is found, that information is used for
- // deciding if the font is symbolic or not.
- //
- // TODO(mack): This section needs some more thought on whether the
- // heuristic is good enough. For now, it passes all the regression
- // tests.
- if (isSymbolicFont && platformId === 3 && encodingId === 0) {
+ if (platformId === 1 && encodingId === 0) {
+ useTable = true;
+ // Continue the loop since there still may be a higher priority
+ // table.
+ } else if (!isSymbolicFont && platformId === 3 && encodingId === 1) {
useTable = true;
canBreak = true;
- foundPreferredTable = true;
- } else if (hasEncoding && platformId === 3 && encodingId === 1) {
+ } else if (isSymbolicFont && platformId === 3 && encodingId === 0) {
useTable = true;
canBreak = true;
- foundPreferredTable = true;
- // Update the isSymbolicFont based on this heuristic
- isSymbolicFont = false;
- } else if (platformId === 1 && encodingId === 0 &&
- !foundPreferredTable) {
- useTable = true;
- foundPreferredTable = true;
- } else if (!potentialTable) {
- // We will use an arbitrary table if we cannot find a preferred
- // table
- useTable = true;
}
if (useTable) {
potentialTable = {
platformId: platformId,
encodingId: encodingId,
- offset: offset,
- isSymbolicFont: isSymbolicFont
+ offset: offset
};
}
if (canBreak) {
@@ -19215,35 +17230,33 @@ var Font = (function FontClosure() {
}
if (!potentialTable) {
- error('Could not find a cmap table');
- return;
- }
-
- if (!foundPreferredTable) {
- warn('Did not find a cmap of suitable format. Interpreting (' +
- potentialTable.platformId + ', ' + potentialTable.encodingId +
- ') as (3, 1) table');
- potentialTable.platformId = 3;
- potentialTable.encodingId = 1;
+ warn('Could not find a preferred cmap table.');
+ return {
+ platformId: -1,
+ encodingId: -1,
+ mappings: [],
+ hasShortCmap: false
+ };
}
font.pos = start + potentialTable.offset;
- var format = int16(font.getBytes(2));
- var length = int16(font.getBytes(2));
- var language = int16(font.getBytes(2));
+ var format = font.getUint16();
+ var length = font.getUint16();
+ var language = font.getUint16();
var hasShortCmap = false;
var mappings = [];
+ var j, glyphId;
// TODO(mack): refactor this cmap subtable reading logic out
if (format === 0) {
- for (var j = 0; j < 256; j++) {
+ for (j = 0; j < 256; j++) {
var index = font.getByte();
if (!index) {
continue;
}
mappings.push({
- charcode: j,
+ charCode: j,
glyphId: index
});
}
@@ -19251,25 +17264,25 @@ var Font = (function FontClosure() {
} else if (format === 4) {
// re-creating the table in format 4 since the encoding
// might be changed
- var segCount = (int16(font.getBytes(2)) >> 1);
+ var segCount = (font.getUint16() >> 1);
font.getBytes(6); // skipping range fields
var segIndex, segments = [];
for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments.push({ end: int16(font.getBytes(2)) });
+ segments.push({ end: font.getUint16() });
}
- font.getBytes(2);
+ font.getUint16();
for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments[segIndex].start = int16(font.getBytes(2));
+ segments[segIndex].start = font.getUint16();
}
for (segIndex = 0; segIndex < segCount; segIndex++) {
- segments[segIndex].delta = int16(font.getBytes(2));
+ segments[segIndex].delta = font.getUint16();
}
var offsetsCount = 0;
for (segIndex = 0; segIndex < segCount; segIndex++) {
- var segment = segments[segIndex];
- var rangeOffset = int16(font.getBytes(2));
+ segment = segments[segIndex];
+ var rangeOffset = font.getUint16();
if (!rangeOffset) {
segment.offsetIndex = -1;
continue;
@@ -19278,53 +17291,53 @@ var Font = (function FontClosure() {
var offsetIndex = (rangeOffset >> 1) - (segCount - segIndex);
segment.offsetIndex = offsetIndex;
offsetsCount = Math.max(offsetsCount, offsetIndex +
- segment.end - segment.start + 1);
+ segment.end - segment.start + 1);
}
var offsets = [];
- for (var j = 0; j < offsetsCount; j++) {
- offsets.push(int16(font.getBytes(2)));
+ for (j = 0; j < offsetsCount; j++) {
+ offsets.push(font.getUint16());
}
for (segIndex = 0; segIndex < segCount; segIndex++) {
- var segment = segments[segIndex];
- var start = segment.start, end = segment.end;
- var delta = segment.delta, offsetIndex = segment.offsetIndex;
+ segment = segments[segIndex];
+ start = segment.start;
+ var end = segment.end;
+ var delta = segment.delta;
+ offsetIndex = segment.offsetIndex;
- for (var j = start; j <= end; j++) {
- if (j == 0xFFFF) {
+ for (j = start; j <= end; j++) {
+ if (j === 0xFFFF) {
continue;
}
- var glyphId = offsetIndex < 0 ? j :
- offsets[offsetIndex + j - start];
+ glyphId = (offsetIndex < 0 ?
+ j : offsets[offsetIndex + j - start]);
glyphId = (glyphId + delta) & 0xFFFF;
if (glyphId === 0) {
continue;
}
mappings.push({
- charcode: j,
+ charCode: j,
glyphId: glyphId
});
}
}
- } else if (format == 6) {
+ } else if (format === 6) {
// Format 6 is a 2-bytes dense mapping, which means the font data
// lives glue together even if they are pretty far in the unicode
// table. (This looks weird, so I can have missed something), this
// works on Linux but seems to fails on Mac so let's rewrite the
// cmap table to a 3-1-4 style
- var firstCode = int16(font.getBytes(2));
- var entryCount = int16(font.getBytes(2));
+ var firstCode = font.getUint16();
+ var entryCount = font.getUint16();
- var glyphs = [];
- var ids = [];
- for (var j = 0; j < entryCount; j++) {
- var glyphId = int16(font.getBytes(2));
- var charcode = firstCode + j;
+ for (j = 0; j < entryCount; j++) {
+ glyphId = font.getUint16();
+ var charCode = firstCode + j;
mappings.push({
- charcode: charcode,
+ charCode: charCode,
glyphId: glyphId
});
}
@@ -19334,10 +17347,10 @@ var Font = (function FontClosure() {
// removing duplicate entries
mappings.sort(function (a, b) {
- return a.charcode - b.charcode;
+ return a.charCode - b.charCode;
});
- for (var i = 1; i < mappings.length; i++) {
- if (mappings[i - 1].charcode === mappings[i].charcode) {
+ for (i = 1; i < mappings.length; i++) {
+ if (mappings[i - 1].charCode === mappings[i].charCode) {
mappings.splice(i, 1);
i--;
}
@@ -19346,7 +17359,6 @@ var Font = (function FontClosure() {
return {
platformId: potentialTable.platformId,
encodingId: potentialTable.encodingId,
- isSymbolicFont: potentialTable.isSymbolicFont,
mappings: mappings,
hasShortCmap: hasShortCmap
};
@@ -19362,7 +17374,7 @@ var Font = (function FontClosure() {
font.pos = (font.start ? font.start : 0) + header.offset;
font.pos += header.length - 2;
- var numOfMetrics = int16(font.getBytes(2));
+ var numOfMetrics = font.getUint16();
if (numOfMetrics > numGlyphs) {
info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
@@ -19378,13 +17390,12 @@ var Font = (function FontClosure() {
((metrics.length - numOfMetrics * 4) >> 1);
if (numMissing > 0) {
- font.pos = (font.start ? font.start : 0) + metrics.offset;
- var entries = '';
- for (var i = 0, ii = metrics.length; i < ii; i++)
- entries += String.fromCharCode(font.getByte());
- for (var i = 0; i < numMissing; i++)
- entries += '\x00\x00';
- metrics.data = stringToArray(entries);
+ // For each missing glyph, we set both the width and lsb to 0 (zero).
+ // Since we need to add two properties for each glyph, this explains
+ // the use of |numMissing * 2| when initializing the typed array.
+ var entries = new Uint8Array(metrics.length + numMissing * 2);
+ entries.set(metrics.data);
+ metrics.data = entries;
}
}
@@ -19402,8 +17413,8 @@ var Font = (function FontClosure() {
return glyf.length;
}
- var j = 10, flagsCount = 0;
- for (var i = 0; i < contoursCount; i++) {
+ var i, j = 10, flagsCount = 0;
+ for (i = 0; i < contoursCount; i++) {
var endPoint = (glyf[j] << 8) | glyf[j + 1];
flagsCount = endPoint + 1;
j += 2;
@@ -19415,7 +17426,7 @@ var Font = (function FontClosure() {
var instructionsEnd = j;
// validating flags
var coordinatesLength = 0;
- for (var i = 0; i < flagsCount; i++) {
+ for (i = 0; i < flagsCount; i++) {
var flag = glyf[j++];
if (flag & 0xC0) {
// reserved flags must be zero, cleaning up
@@ -19466,7 +17477,7 @@ var Font = (function FontClosure() {
// Validate version:
// Should always be 0x00010000
- var version = int32([data[0], data[1], data[2], data[3]]);
+ var version = int32(data[0], data[1], data[2], data[3]);
if (version >> 16 !== 1) {
info('Attempting to fix invalid version in head table: ' + version);
data[0] = 0;
@@ -19475,7 +17486,7 @@ var Font = (function FontClosure() {
data[3] = 0;
}
- var indexToLocFormat = int16([data[50], data[51]]);
+ var indexToLocFormat = int16(data[50], data[51]);
if (indexToLocFormat < 0 || indexToLocFormat > 1) {
info('Attempting to fix invalid indexToLocFormat in head table: ' +
indexToLocFormat);
@@ -19546,8 +17557,15 @@ var Font = (function FontClosure() {
var startOffset = itemDecode(locaData, 0);
var writeOffset = 0;
itemEncode(locaData, 0, writeOffset);
- for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
+ var i, j;
+ for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
var endOffset = itemDecode(locaData, j);
+ if (endOffset > oldGlyfDataLength &&
+ ((oldGlyfDataLength + 3) & ~3) === endOffset) {
+ // Aspose breaks fonts by aligning the glyphs to the qword, but not
+ // the glyf table size, which makes last glyph out of range.
+ endOffset = oldGlyfDataLength;
+ }
if (endOffset > oldGlyfDataLength) {
// glyph end offset points outside glyf data, rejecting the glyph
itemEncode(locaData, j, writeOffset);
@@ -19567,8 +17585,9 @@ var Font = (function FontClosure() {
// to have single glyph with one point
var simpleGlyph = new Uint8Array(
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0]);
- for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize)
+ for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
itemEncode(locaData, j, simpleGlyph.length);
+ }
glyf.data = simpleGlyph;
return;
}
@@ -19594,25 +17613,27 @@ var Font = (function FontClosure() {
font.pos = start;
var length = post.length, end = start + length;
- var version = int32(font.getBytes(4));
+ var version = font.getInt32();
// skip rest to the tables
font.getBytes(28);
var glyphNames;
var valid = true;
+ var i;
+
switch (version) {
case 0x00010000:
glyphNames = MacStandardGlyphOrdering;
break;
case 0x00020000:
- var numGlyphs = int16(font.getBytes(2));
- if (numGlyphs != maxpNumGlyphs) {
+ var numGlyphs = font.getUint16();
+ if (numGlyphs !== maxpNumGlyphs) {
valid = false;
break;
}
var glyphNameIndexes = [];
- for (var i = 0; i < numGlyphs; ++i) {
- var index = int16(font.getBytes(2));
+ for (i = 0; i < numGlyphs; ++i) {
+ var index = font.getUint16();
if (index >= 32768) {
valid = false;
break;
@@ -19623,16 +17644,17 @@ var Font = (function FontClosure() {
break;
}
var customNames = [];
+ var strBuf = [];
while (font.pos < end) {
var stringLength = font.getByte();
- var string = '';
- for (var i = 0; i < stringLength; ++i) {
- string += String.fromCharCode(font.getByte());
+ strBuf.length = stringLength;
+ for (i = 0; i < stringLength; ++i) {
+ strBuf[i] = String.fromCharCode(font.getByte());
}
- customNames.push(string);
+ customNames.push(strBuf.join(''));
}
glyphNames = [];
- for (var i = 0; i < numGlyphs; ++i) {
+ for (i = 0; i < numGlyphs; ++i) {
var j = glyphNameIndexes[i];
if (j < 258) {
glyphNames.push(MacStandardGlyphOrdering[j]);
@@ -19658,33 +17680,35 @@ var Font = (function FontClosure() {
var names = [[], []];
var length = nameTable.length, end = start + length;
- var format = int16(font.getBytes(2));
+ var format = font.getUint16();
var FORMAT_0_HEADER_LENGTH = 6;
if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
// unsupported name table format or table "too" small
return names;
}
- var numRecords = int16(font.getBytes(2));
- var stringsStart = int16(font.getBytes(2));
+ var numRecords = font.getUint16();
+ var stringsStart = font.getUint16();
var records = [];
var NAME_RECORD_LENGTH = 12;
- for (var i = 0; i < numRecords &&
+ var i, ii;
+
+ for (i = 0; i < numRecords &&
font.pos + NAME_RECORD_LENGTH <= end; i++) {
var r = {
- platform: int16(font.getBytes(2)),
- encoding: int16(font.getBytes(2)),
- language: int16(font.getBytes(2)),
- name: int16(font.getBytes(2)),
- length: int16(font.getBytes(2)),
- offset: int16(font.getBytes(2))
+ platform: font.getUint16(),
+ encoding: font.getUint16(),
+ language: font.getUint16(),
+ name: font.getUint16(),
+ length: font.getUint16(),
+ offset: font.getUint16()
};
// using only Macintosh and Windows platform/encoding names
- if ((r.platform == 1 && r.encoding === 0 && r.language === 0) ||
- (r.platform == 3 && r.encoding == 1 && r.language == 0x409)) {
+ if ((r.platform === 1 && r.encoding === 0 && r.language === 0) ||
+ (r.platform === 3 && r.encoding === 1 && r.language === 0x409)) {
records.push(r);
}
}
- for (var i = 0, ii = records.length; i < ii; i++) {
+ for (i = 0, ii = records.length; i < ii; i++) {
var record = records[i];
var pos = start + stringsStart + record.offset;
if (pos + record.length > end) {
@@ -19692,12 +17716,11 @@ var Font = (function FontClosure() {
}
font.pos = pos;
var nameIndex = record.name;
- var encoding = record.encoding ? 1 : 0;
if (record.encoding) {
// unicode
var str = '';
for (var j = 0, jj = record.length; j < jj; j += 2) {
- str += String.fromCharCode(int16(font.getBytes(2)));
+ str += String.fromCharCode(font.getUint16());
}
names[1][nameIndex] = str;
} else {
@@ -19721,7 +17744,7 @@ var Font = (function FontClosure() {
function sanitizeTTProgram(table, ttContext) {
var data = table.data;
- var i = 0, n, lastEndf = 0, lastDeff = 0;
+ var i = 0, j, n, b, funcId, pc, lastEndf = 0, lastDeff = 0;
var stack = [];
var callstack = [];
var functionsCalled = [];
@@ -19737,7 +17760,7 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n;
} else {
- for (var j = 0; j < n; j++) {
+ for (j = 0; j < n; j++) {
stack.push(data[i++]);
}
}
@@ -19746,8 +17769,8 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n * 2;
} else {
- for (var j = 0; j < n; j++) {
- var b = data[i++];
+ for (j = 0; j < n; j++) {
+ b = data[i++];
stack.push((b << 8) | data[i++]);
}
}
@@ -19756,7 +17779,7 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n;
} else {
- for (var j = 0; j < n; j++) {
+ for (j = 0; j < n; j++) {
stack.push(data[i++]);
}
}
@@ -19765,15 +17788,15 @@ var Font = (function FontClosure() {
if (inFDEF || inELSE) {
i += n * 2;
} else {
- for (var j = 0; j < n; j++) {
- var b = data[i++];
+ for (j = 0; j < n; j++) {
+ b = data[i++];
stack.push((b << 8) | data[i++]);
}
}
} else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
if (!inFDEF && !inELSE) {
// collecting inforamtion about which functions are used
- var funcId = stack[stack.length - 1];
+ funcId = stack[stack.length - 1];
ttContext.functionsUsed[funcId] = true;
if (funcId in ttContext.functionsStackDeltas) {
stack.length += ttContext.functionsStackDeltas[funcId];
@@ -19781,7 +17804,7 @@ var Font = (function FontClosure() {
functionsCalled.indexOf(funcId) < 0) {
callstack.push({data: data, i: i, stackTop: stack.length - 1});
functionsCalled.push(funcId);
- var pc = ttContext.functionsDefined[funcId];
+ pc = ttContext.functionsDefined[funcId];
if (!pc) {
warn('TT: CALL non-existent function');
ttContext.hintsValid = false;
@@ -19799,20 +17822,20 @@ var Font = (function FontClosure() {
inFDEF = true;
// collecting inforamtion about which functions are defined
lastDeff = i;
- var funcId = stack.pop();
+ funcId = stack.pop();
ttContext.functionsDefined[funcId] = {data: data, i: i};
} else if (op === 0x2D) { // ENDF - end of function
if (inFDEF) {
inFDEF = false;
lastEndf = i;
} else {
- var pc = callstack.pop();
+ pc = callstack.pop();
if (!pc) {
warn('TT: ENDF bad stack');
ttContext.hintsValid = false;
return;
}
- var funcId = functionsCalled.pop();
+ funcId = functionsCalled.pop();
data = pc.data;
i = pc.i;
ttContext.functionsStackDeltas[funcId] =
@@ -19836,9 +17859,13 @@ var Font = (function FontClosure() {
}
--ifLevel;
} else if (op === 0x1C) { // JMPR
- var offset = stack[stack.length - 1];
- // only jumping forward to prevent infinite loop
- if (offset > 0) { i += offset - 1; }
+ if (!inFDEF && !inELSE) {
+ var offset = stack[stack.length - 1];
+ // only jumping forward to prevent infinite loop
+ if (offset > 0) {
+ i += offset - 1;
+ }
+ }
}
// Adjusting stack not extactly, but just enough to get function id
if (!inFDEF && !inELSE) {
@@ -19878,6 +17905,11 @@ var Font = (function FontClosure() {
if (ttContext.tooComplexToFollowFunctions) {
return;
}
+ if (ttContext.functionsDefined.length > maxFunctionDefs) {
+ warn('TT: more functions defined than expected');
+ ttContext.hintsValid = false;
+ return;
+ }
for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
if (j > maxFunctionDefs) {
warn('TT: invalid function id: ' + j);
@@ -19896,13 +17928,14 @@ var Font = (function FontClosure() {
if (content.length > 1) {
// concatenating the content items
var newLength = 0;
- for (var j = 0, jj = content.length; j < jj; j++) {
+ var j, jj;
+ for (j = 0, jj = content.length; j < jj; j++) {
newLength += content[j].length;
}
newLength = (newLength + 3) & ~3;
var result = new Uint8Array(newLength);
var pos = 0;
- for (var j = 0, jj = content.length; j < jj; j++) {
+ for (j = 0, jj = content.length; j < jj; j++) {
result.set(content[j], pos);
pos += content[j].length;
}
@@ -19944,11 +17977,13 @@ var Font = (function FontClosure() {
var header = readOpenTypeHeader(font);
var numTables = header.numTables;
+ var cff, cffFile;
var tables = { 'OS/2': null, cmap: null, head: null, hhea: null,
- hmtx: null, maxp: null, name: null, post: null};
+ hmtx: null, maxp: null, name: null, post: null };
+ var table;
for (var i = 0; i < numTables; i++) {
- var table = readTableEntry(font);
+ table = readTableEntry(font);
if (VALID_TABLES.indexOf(table.tag) < 0) {
continue; // skipping table if it's not a required or optional table
}
@@ -19963,8 +17998,8 @@ var Font = (function FontClosure() {
// OpenType font
if (!tables.head || !tables.hhea || !tables.maxp || !tables.post) {
// no major tables: throwing everything at CFFFont
- var cffFile = new Stream(tables['CFF '].data);
- var cff = new CFFFont(cffFile, properties);
+ cffFile = new Stream(tables['CFF '].data);
+ cff = new CFFFont(cffFile, properties);
return this.convert(name, cff, properties);
}
@@ -19974,10 +18009,12 @@ var Font = (function FontClosure() {
delete tables.fpgm;
delete tables.prep;
delete tables['cvt '];
+ this.isOpenType = true;
} else {
if (!tables.glyf || !tables.loca) {
error('Required "glyf" or "loca" tables are not found');
}
+ this.isOpenType = false;
}
if (!tables.maxp) {
@@ -19985,24 +18022,24 @@ var Font = (function FontClosure() {
}
font.pos = (font.start || 0) + tables.maxp.offset;
- var version = int32(font.getBytes(4));
- var numGlyphs = int16(font.getBytes(2));
+ var version = font.getInt32();
+ var numGlyphs = font.getUint16();
var maxFunctionDefs = 0;
if (version >= 0x00010000 && tables.maxp.length >= 22) {
// maxZones can be invalid
font.pos += 8;
- var maxZones = int16(font.getBytes(2));
+ var maxZones = font.getUint16();
if (maxZones > 2) { // reset to 2 if font has invalid maxZones
tables.maxp.data[14] = 0;
tables.maxp.data[15] = 2;
}
font.pos += 4;
- maxFunctionDefs = int16(font.getBytes(2));
+ maxFunctionDefs = font.getUint16();
}
var dupFirstEntry = false;
- if (properties.type == 'CIDFontType2' && properties.toUnicode &&
- properties.toUnicode[0] > '\u0000') {
+ if (properties.type === 'CIDFontType2' && properties.toUnicode &&
+ properties.toUnicode.get(0) > '\u0000') {
// oracle's defect (see 3427), duplicating first entry
dupFirstEntry = true;
numGlyphs++;
@@ -20018,24 +18055,6 @@ var Font = (function FontClosure() {
delete tables['cvt '];
}
- // Tables needs to be written by ascendant alphabetic order
- var tablesNames = Object.keys(tables);
- tablesNames.sort();
-
- numTables = tablesNames.length;
-
- // header and new offsets. Table entry information is appended to the
- // end of file. The virtualOffset represents where to put the actual
- // data of a particular table;
- var ttf = {
- file: '',
- virtualOffset: numTables * (4 * 4)
- };
-
- // The new numbers of tables will be the last one plus the num
- // of missing tables
- createOpenTypeHeader(header.version, ttf, numTables);
-
// Ensure the hmtx table contains the advance width and
// sidebearings information for numGlyphs in the maxp table
sanitizeMetrics(font, tables.hhea, tables.hmtx, numGlyphs);
@@ -20047,8 +18066,8 @@ var Font = (function FontClosure() {
sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
if (isTrueType) {
- var isGlyphLocationsLong = int16([tables.head.data[50],
- tables.head.data[51]]);
+ var isGlyphLocationsLong = int16(tables.head.data[50],
+ tables.head.data[51]);
sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs,
isGlyphLocationsLong, hintsValid, dupFirstEntry);
}
@@ -20072,244 +18091,142 @@ var Font = (function FontClosure() {
}
}
- var glyphs, ids;
- if (properties.type == 'CIDFontType2') {
- // Replace the old CMAP table with a shiny new one
- // Type2 composite fonts map characters directly to glyphs so the cmap
- // table must be replaced.
- // canvas fillText will reencode some characters even if the font has a
- // glyph at that position - e.g. newline is converted to a space and
- // U+00AD (soft hyphen) is not drawn.
- // So, offset all the glyphs by 0xFF to avoid these cases and use
- // the encoding to map incoming characters to the new glyph positions
- if (!tables.cmap) {
- tables.cmap = {
- tag: 'cmap',
- data: null
- };
- }
-
+ var charCodeToGlyphId = [], charCode;
+ if (properties.type === 'CIDFontType2') {
var cidToGidMap = properties.cidToGidMap || [];
- var gidToCidMap = [0];
- if (cidToGidMap.length > 0) {
- for (var j = cidToGidMap.length - 1; j >= 0; j--) {
- var gid = cidToGidMap[j];
- if (gid)
- gidToCidMap[gid] = j;
+ var cidToGidMapLength = cidToGidMap.length;
+ properties.cMap.forEach(function(charCode, cid) {
+ assert(cid <= 0xffff, 'Max size of CID is 65,535');
+ var glyphId = -1;
+ if (cidToGidMapLength === 0) {
+ glyphId = charCode;
+ } else if (cidToGidMap[cid] !== undefined) {
+ glyphId = cidToGidMap[cid];
}
- // filling the gaps using CID above the CIDs currently used in font
- var nextCid = cidToGidMap.length;
- for (var i = 1; i < numGlyphs; i++) {
- if (!gidToCidMap[i])
- gidToCidMap[i] = nextCid++;
- }
- } else {
- for (var i = 1; i < numGlyphs; i++) {
- gidToCidMap[i] = i;
- }
- if (dupFirstEntry) {
- gidToCidMap[numGlyphs - 1] = 0;
- }
- }
-
- glyphs = [];
- ids = [];
-
- var usedUnicodes = [];
- var unassignedUnicodeItems = [];
- var toFontChar = this.cidToFontChar || this.toFontChar;
- for (var i = 1; i < numGlyphs; i++) {
- var cid = gidToCidMap[i];
- var unicode = toFontChar[cid];
- if (!unicode || typeof unicode !== 'number' ||
- isSpecialUnicode(unicode) || unicode in usedUnicodes) {
- unassignedUnicodeItems.push(i);
- continue;
- }
- usedUnicodes[unicode] = true;
- glyphs.push({ unicode: unicode, code: cid });
- ids.push(i);
- }
-
- // unassigned codepoints will never be used for non-Identity CMap
- // because the input will be Unicode
- if (!this.cidToFontChar) {
- // trying to fit as many unassigned symbols as we can
- // in the range allocated for the user defined symbols
- var unusedUnicode = CMAP_GLYPH_OFFSET;
- for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; j++) {
- var i = unassignedUnicodeItems[j];
- var cid = gidToCidMap[i];
- while (unusedUnicode in usedUnicodes)
- unusedUnicode++;
- if (unusedUnicode >= CMAP_GLYPH_OFFSET + GLYPH_AREA_SIZE)
- break;
- var unicode = unusedUnicode++;
- this.toFontChar[cid] = unicode;
- usedUnicodes[unicode] = true;
- glyphs.push({ unicode: unicode, code: cid });
- ids.push(i);
+ if (glyphId >= 0 && glyphId < numGlyphs) {
+ charCodeToGlyphId[charCode] = glyphId;
}
+ });
+ if (dupFirstEntry) {
+ charCodeToGlyphId[0] = numGlyphs - 1;
}
} else {
- this.useToFontChar = true;
// Most of the following logic in this code branch is based on the
// 9.6.6.4 of the PDF spec.
-
- // TODO(mack):
- // We are using this.hasEncoding to mean that the encoding is either
- // MacRomanEncoding or WinAnsiEncoding (following spec in 9.6.6.4),
- // but this.hasEncoding is currently true for any encodings on the
- // Encodings object (e.g. MacExpertEncoding). So should consider using
- // better check for this.
- var cmapTable = readCmapTable(tables.cmap, font, this.hasEncoding,
- this.isSymbolicFont);
-
- // TODO(mack): If the (3, 0) cmap table used, then the font is
- // symbolic. The range of charcodes in the cmap table should be
- // one of the following:
- // -> 0x0000 - 0x00FF
- // -> 0xF000 - 0xF0FF
- // -> 0xF100 - 0xF1FF
- // -> 0xF200 - 0xF2FF
- // If it is not, we should change not consider this a symbolic font
- this.isSymbolicFont = cmapTable.isSymbolicFont;
-
+ var cmapTable = readCmapTable(tables.cmap, font, this.isSymbolicFont);
var cmapPlatformId = cmapTable.platformId;
var cmapEncodingId = cmapTable.encodingId;
var cmapMappings = cmapTable.mappings;
var cmapMappingsLength = cmapMappings.length;
- var glyphs = [];
- var ids = [];
- for (var i = 0; i < cmapMappingsLength; ++i) {
- var cmapMapping = cmapMappings[i];
- var charcode = cmapMapping.charcode;
- var unicode = cmapCharcodeToUnicode(charcode, this.isSymbolicFont,
- cmapPlatformId, cmapEncodingId);
+ var hasEncoding = properties.differences.length ||
+ !!properties.baseEncodingName;
- if (!unicode) {
- // TODO(mack): gotta check if skipping mappings where we cannot find
- // a unicode is the correct behaviour
- continue;
+ // The spec seems to imply that if the font is symbolic the encoding
+ // should be ignored, this doesn't appear to work for 'preistabelle.pdf'
+ // where the the font is symbolic and it has an encoding.
+ if (hasEncoding &&
+ (cmapPlatformId === 3 && cmapEncodingId === 1 ||
+ cmapPlatformId === 1 && cmapEncodingId === 0) ||
+ (cmapPlatformId === -1 && cmapEncodingId === -1 && // Temporary hack
+ !!Encodings[properties.baseEncodingName])) { // Temporary hack
+ // When no preferred cmap table was found and |baseEncodingName| is
+ // one of the predefined encodings, we seem to obtain a better
+ // |charCodeToGlyphId| map from the code below (fixes bug 1057544).
+ // TODO: Note that this is a hack which should be removed as soon as
+ // we have proper support for more exotic cmap tables.
+
+ var baseEncoding = [];
+ if (properties.baseEncodingName === 'MacRomanEncoding' ||
+ properties.baseEncodingName === 'WinAnsiEncoding') {
+ baseEncoding = Encodings[properties.baseEncodingName];
}
- glyphs.push({
- code: charcode,
- unicode: unicode
- });
- ids.push(cmapMapping.glyphId);
- }
-
- var hasShortCmap = cmapTable.hasShortCmap;
- var toFontChar = this.toFontChar;
-
- if (hasShortCmap && ids.length == numGlyphs) {
- // Fixes the short cmap tables -- some generators use incorrect
- // glyph id.
- for (var i = 0, ii = ids.length; i < ii; i++) {
- ids[i] = i;
- }
- }
-
- // Rewrite the whole toFontChar dictionary with a new one using the
- // information from the mappings in the cmap table.
- var newToFontChar = [];
- if (this.isSymbolicFont) {
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var glyph = glyphs[i];
- // For (3, 0) cmap tables:
- // The charcode key being stored in toFontChar is the lower byte
- // of the two-byte charcodes of the cmap table since according to
- // the spec: 'each byte from the string shall be prepended with the
- // high byte of the range [of charcodes in the cmap table], to form
- // a two-byte character, which shall be used to select the
- // associated glyph description from the subtable'.
- //
- // For (1, 0) cmap tables:
- // 'single bytes from the string shall be used to look up the
- // associated glyph descriptions from the subtable'. This means
- // charcodes in the cmap will be single bytes, so no-op since
- // glyph.code & 0xFF === glyph.code
- newToFontChar[glyph.code & 0xFF] = glyph.unicode;
- }
- } else {
-
- var encoding = properties.baseEncoding;
- var differences = properties.differences;
-
- // TODO(mack): check if it is necessary to shift control characters
- // for non-symbolic fonts so that browsers dont't render them using
- // space characters
-
- var glyphCodeMapping = cmapTable.glyphCodeMapping;
- for (var charcode = 0; charcode < encoding.length; ++charcode) {
- if (!encoding.hasOwnProperty(charcode)) {
+ for (charCode = 0; charCode < 256; charCode++) {
+ var glyphName;
+ if (this.differences && charCode in this.differences) {
+ glyphName = this.differences[charCode];
+ } else if (charCode in baseEncoding &&
+ baseEncoding[charCode] !== '') {
+ glyphName = baseEncoding[charCode];
+ } else {
+ glyphName = Encodings.StandardEncoding[charCode];
+ }
+ if (!glyphName) {
continue;
}
-
- // Since the cmap table that we will be writing out is a (3, 1)
- // unicode table, in this section we will rewrites the charcodes
- // in the pdf into unicodes
-
- var glyphName = encoding[charcode];
- // A nonsymbolic font should not have a Differences array, but
- // if it does have one, we should still use it
- if (charcode in differences) {
- glyphName = differences[charcode];
+ var unicodeOrCharCode;
+ if (cmapPlatformId === 3 && cmapEncodingId === 1) {
+ unicodeOrCharCode = GlyphsUnicode[glyphName];
+ } else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
+ // TODO: the encoding needs to be updated with mac os table.
+ unicodeOrCharCode = Encodings.MacRomanEncoding.indexOf(glyphName);
}
- // Finally, any undefined entries in the table shall be filled
- // using StandardEncoding
- if (!glyphName) {
- glyphName = Encodings.StandardEncoding[charcode];
+ var found = false;
+ for (i = 0; i < cmapMappingsLength; ++i) {
+ if (cmapMappings[i].charCode === unicodeOrCharCode) {
+ charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
+ found = true;
+ break;
+ }
}
-
- // TODO(mack): Handle the case that the glyph name cannot be
- // mapped as specified, in which case the glyph name shall be
- // looked up in the font program's 'post' table (if one is
- // present) and the associated glyph id shall be used.
- //
- // For now, we're just using the '.notdef' glyph name in this
- // case.
- glyphName = glyphName || '.notdef';
-
- var unicode = GlyphsUnicode[glyphName];
- newToFontChar[charcode] = unicode;
+ if (!found && properties.glyphNames) {
+ // Try to map using the post table. There are currently no known
+ // pdfs that this fixes.
+ var glyphId = properties.glyphNames.indexOf(glyphName);
+ if (glyphId > 0) {
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ }
+ }
+ } else {
+ // For (3, 0) cmap tables:
+ // The charcode key being stored in charCodeToGlyphId is the lower
+ // byte of the two-byte charcodes of the cmap table since according to
+ // the spec: 'each byte from the string shall be prepended with the
+ // high byte of the range [of charcodes in the cmap table], to form
+ // a two-byte character, which shall be used to select the
+ // associated glyph description from the subtable'.
+ //
+ // For (1, 0) cmap tables:
+ // 'single bytes from the string shall be used to look up the
+ // associated glyph descriptions from the subtable'. This means
+ // charcodes in the cmap will be single bytes, so no-op since
+ // glyph.charCode & 0xFF === glyph.charCode
+ for (i = 0; i < cmapMappingsLength; ++i) {
+ charCode = cmapMappings[i].charCode & 0xFF;
+ charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
}
}
- this.toFontChar = toFontChar = newToFontChar;
-
- createGlyphNameMap(glyphs, ids, properties);
- this.glyphNameMap = properties.glyphNameMap;
}
- if (glyphs.length === 0) {
+ if (charCodeToGlyphId.length === 0) {
// defines at least one glyph
- glyphs.push({ unicode: 0xF000, code: 0xF000, glyph: '.notdef' });
- ids.push(0);
+ charCodeToGlyphId[0] = 0;
}
// Converting glyphs and ids into font's cmap table
- tables.cmap.data = createCmapTable(glyphs, ids);
- var unicodeIsEnabled = [];
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- unicodeIsEnabled[glyphs[i].unicode] = true;
- }
- this.unicodeIsEnabled = unicodeIsEnabled;
+ var newMapping = adjustMapping(charCodeToGlyphId, properties);
+ this.toFontChar = newMapping.toFontChar;
+ tables.cmap = {
+ tag: 'cmap',
+ data: createCmapTable(newMapping.charCodeToGlyphId)
+ };
if (!tables['OS/2'] || !validateOS2Table(tables['OS/2'])) {
// extract some more font properties from the OpenType head and
// hhea tables; yMin and descent value are always negative
var override = {
- unitsPerEm: int16([tables.head.data[18], tables.head.data[19]]),
- yMax: int16([tables.head.data[42], tables.head.data[43]]),
- yMin: int16([tables.head.data[38], tables.head.data[39]]) - 0x10000,
- ascent: int16([tables.hhea.data[4], tables.hhea.data[5]]),
- descent: int16([tables.hhea.data[6], tables.hhea.data[7]]) - 0x10000
+ unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),
+ yMax: int16(tables.head.data[42], tables.head.data[43]),
+ yMin: int16(tables.head.data[38], tables.head.data[39]) - 0x10000,
+ ascent: int16(tables.hhea.data[4], tables.hhea.data[5]),
+ descent: int16(tables.hhea.data[6], tables.hhea.data[7]) - 0x10000
};
tables['OS/2'] = {
tag: 'OS/2',
- data: stringToArray(createOS2Table(properties, glyphs, override))
+ data: createOS2Table(properties, newMapping.charCodeToGlyphId,
+ override)
};
}
@@ -20317,16 +18234,16 @@ var Font = (function FontClosure() {
if (!tables.post) {
tables.post = {
tag: 'post',
- data: stringToArray(createPostTable(properties))
+ data: createPostTable(properties)
};
}
if (!isTrueType) {
try {
// Trying to repair CFF file
- var cffFile = new Stream(tables['CFF '].data);
+ cffFile = new Stream(tables['CFF '].data);
var parser = new CFFParser(cffFile, properties);
- var cff = parser.parse();
+ cff = parser.parse();
var compiler = new CFFCompiler(cff);
tables['CFF '].data = compiler.compile();
} catch (e) {
@@ -20338,330 +18255,304 @@ var Font = (function FontClosure() {
if (!tables.name) {
tables.name = {
tag: 'name',
- data: stringToArray(createNameTable(this.name))
+ data: createNameTable(this.name)
};
} else {
// ... using existing 'name' table as prototype
var namePrototype = readNameTable(tables.name);
- tables.name.data = stringToArray(createNameTable(name, namePrototype));
+ tables.name.data = createNameTable(name, namePrototype);
}
- // rewrite the tables but tweak offsets
- for (var i = 0; i < numTables; i++) {
- var table = tables[tablesNames[i]];
- var data = [];
-
- var tableData = table.data;
- for (var j = 0, jj = tableData.length; j < jj; j++)
- data.push(tableData[j]);
- createTableEntry(ttf, table.tag, data);
+ var builder = new OpenTypeFileBuilder(header.version);
+ for (var tableTag in tables) {
+ builder.addTable(tableTag, tables[tableTag].data);
}
-
- // Add the table datas
- for (var i = 0; i < numTables; i++) {
- var table = tables[tablesNames[i]];
- var tableData = table.data;
- ttf.file += arrayToString(tableData);
-
- // 4-byte aligned data
- while (ttf.file.length & 3)
- ttf.file += String.fromCharCode(0);
- }
-
- return stringToArray(ttf.file);
+ return builder.toArray();
},
convert: function Font_convert(fontName, font, properties) {
- function isFixedPitch(glyphs) {
- for (var i = 0, ii = glyphs.length - 1; i < ii; i++) {
- if (glyphs[i] != glyphs[i + 1])
- return false;
+ // TODO: Check the charstring widths to determine this.
+ properties.fixedPitch = false;
+
+ var mapping = font.getGlyphMapping(properties);
+ var newMapping = adjustMapping(mapping, properties);
+ this.toFontChar = newMapping.toFontChar;
+ var numGlyphs = font.numGlyphs;
+
+ function getCharCodes(charCodeToGlyphId, glyphId) {
+ var charCodes = null;
+ for (var charCode in charCodeToGlyphId) {
+ if (glyphId === charCodeToGlyphId[charCode]) {
+ if (!charCodes) {
+ charCodes = [];
+ }
+ charCodes.push(charCode | 0);
+ }
}
- return true;
+ return charCodes;
}
- // The offsets object holds at the same time a representation of where
- // to write the table entry information about a table and another offset
- // representing the offset where to draw the actual data of a particular
- // table
- var REQ_TABLES_CNT = 9;
-
- var otf = {
- file: '',
- virtualOffset: 9 * (4 * 4)
- };
-
- createOpenTypeHeader('\x4F\x54\x54\x4F', otf, 9);
-
- var charstrings = font.charstrings;
- properties.fixedPitch = isFixedPitch(charstrings);
-
- var glyphNameMap = {};
- for (var i = 0; i < charstrings.length; ++i) {
- var charstring = charstrings[i];
- glyphNameMap[charstring.glyph] = charstring.unicode;
+ function createCharCode(charCodeToGlyphId, glyphId) {
+ for (var charCode in charCodeToGlyphId) {
+ if (glyphId === charCodeToGlyphId[charCode]) {
+ return charCode | 0;
+ }
+ }
+ newMapping.charCodeToGlyphId[newMapping.nextAvailableFontCharCode] =
+ glyphId;
+ return newMapping.nextAvailableFontCharCode++;
}
- this.glyphNameMap = glyphNameMap;
var seacs = font.seacs;
- if (SEAC_ANALYSIS_ENABLED && seacs) {
- var seacMap = [];
+ if (SEAC_ANALYSIS_ENABLED && seacs && seacs.length) {
var matrix = properties.fontMatrix || FONT_IDENTITY_MATRIX;
- for (var i = 0; i < charstrings.length; ++i) {
- var charstring = charstrings[i];
- var seac = seacs[charstring.gid];
- if (!seac) {
- continue;
- }
+ var charset = font.getCharset();
+ var seacMap = Object.create(null);
+ for (var glyphId in seacs) {
+ glyphId |= 0;
+ var seac = seacs[glyphId];
var baseGlyphName = Encodings.StandardEncoding[seac[2]];
- var baseUnicode = glyphNameMap[baseGlyphName];
var accentGlyphName = Encodings.StandardEncoding[seac[3]];
- var accentUnicode = glyphNameMap[accentGlyphName];
- if (!baseUnicode || !accentUnicode) {
+ var baseGlyphId = charset.indexOf(baseGlyphName);
+ var accentGlyphId = charset.indexOf(accentGlyphName);
+ if (baseGlyphId < 0 || accentGlyphId < 0) {
continue;
}
var accentOffset = {
x: seac[0] * matrix[0] + seac[1] * matrix[2] + matrix[4],
y: seac[0] * matrix[1] + seac[1] * matrix[3] + matrix[5]
};
- seacMap[charstring.unicode] = {
- baseUnicode: baseUnicode,
- accentUnicode: accentUnicode,
- accentOffset: accentOffset
- };
+
+ var charCodes = getCharCodes(mapping, glyphId);
+ if (!charCodes) {
+ // There's no point in mapping it if the char code was never mapped
+ // to begin with.
+ continue;
+ }
+ for (var i = 0, ii = charCodes.length; i < ii; i++) {
+ var charCode = charCodes[i];
+ // Find a fontCharCode that maps to the base and accent glyphs.
+ // If one doesn't exists, create it.
+ var charCodeToGlyphId = newMapping.charCodeToGlyphId;
+ var baseFontCharCode = createCharCode(charCodeToGlyphId,
+ baseGlyphId);
+ var accentFontCharCode = createCharCode(charCodeToGlyphId,
+ accentGlyphId);
+ seacMap[charCode] = {
+ baseFontCharCode: baseFontCharCode,
+ accentFontCharCode: accentFontCharCode,
+ accentOffset: accentOffset
+ };
+ }
}
properties.seacMap = seacMap;
}
- if (properties.overridableEncoding && (properties.subtype == 'Type1C' ||
- properties.subtype == 'CIDFontType0C')) {
- var encoding = [];
- for (var i = 0; i < charstrings.length; ++i) {
- var charstring = charstrings[i];
- encoding[charstring.code] = charstring.glyph;
- }
- properties.baseEncoding = encoding;
- }
- if (properties.subtype == 'CIDFontType0C') {
- var toFontChar = [];
- for (var i = 0; i < charstrings.length; ++i) {
- var charstring = charstrings[i];
- toFontChar[charstring.code] = charstring.unicode;
- }
- this.toFontChar = toFontChar;
- }
var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
- var fields = {
- // PostScript Font Program
- 'CFF ': font.data,
+ var builder = new OpenTypeFileBuilder('\x4F\x54\x54\x4F');
+ // PostScript Font Program
+ builder.addTable('CFF ', font.data);
+ // OS/2 and Windows Specific metrics
+ builder.addTable('OS/2', createOS2Table(properties,
+ newMapping.charCodeToGlyphId));
+ // Character to glyphs mapping
+ builder.addTable('cmap', createCmapTable(newMapping.charCodeToGlyphId));
+ // Font header
+ builder.addTable('head',
+ '\x00\x01\x00\x00' + // Version number
+ '\x00\x00\x10\x00' + // fontRevision
+ '\x00\x00\x00\x00' + // checksumAdjustement
+ '\x5F\x0F\x3C\xF5' + // magicNumber
+ '\x00\x00' + // Flags
+ safeString16(unitsPerEm) + // unitsPerEM
+ '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
+ '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
+ '\x00\x00' + // xMin
+ safeString16(properties.descent) + // yMin
+ '\x0F\xFF' + // xMax
+ safeString16(properties.ascent) + // yMax
+ string16(properties.italicAngle ? 2 : 0) + // macStyle
+ '\x00\x11' + // lowestRecPPEM
+ '\x00\x00' + // fontDirectionHint
+ '\x00\x00' + // indexToLocFormat
+ '\x00\x00'); // glyphDataFormat
- // OS/2 and Windows Specific metrics
- 'OS/2': stringToArray(createOS2Table(properties, charstrings)),
+ // Horizontal header
+ builder.addTable('hhea',
+ '\x00\x01\x00\x00' + // Version number
+ safeString16(properties.ascent) + // Typographic Ascent
+ safeString16(properties.descent) + // Typographic Descent
+ '\x00\x00' + // Line Gap
+ '\xFF\xFF' + // advanceWidthMax
+ '\x00\x00' + // minLeftSidebearing
+ '\x00\x00' + // minRightSidebearing
+ '\x00\x00' + // xMaxExtent
+ safeString16(properties.capHeight) + // caretSlopeRise
+ safeString16(Math.tan(properties.italicAngle) *
+ properties.xHeight) + // caretSlopeRun
+ '\x00\x00' + // caretOffset
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // -reserved-
+ '\x00\x00' + // metricDataFormat
+ string16(numGlyphs)); // Number of HMetrics
- // Character to glyphs mapping
- 'cmap': createCmapTable(charstrings.slice(),
- ('glyphIds' in font) ? font.glyphIds : null),
-
- // Font header
- 'head': (function fontFieldsHead() {
- return stringToArray(
- '\x00\x01\x00\x00' + // Version number
- '\x00\x00\x10\x00' + // fontRevision
- '\x00\x00\x00\x00' + // checksumAdjustement
- '\x5F\x0F\x3C\xF5' + // magicNumber
- '\x00\x00' + // Flags
- safeString16(unitsPerEm) + // unitsPerEM
- '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // creation date
- '\x00\x00\x00\x00\x9e\x0b\x7e\x27' + // modifification date
- '\x00\x00' + // xMin
- safeString16(properties.descent) + // yMin
- '\x0F\xFF' + // xMax
- safeString16(properties.ascent) + // yMax
- string16(properties.italicAngle ? 2 : 0) + // macStyle
- '\x00\x11' + // lowestRecPPEM
- '\x00\x00' + // fontDirectionHint
- '\x00\x00' + // indexToLocFormat
- '\x00\x00'); // glyphDataFormat
- })(),
-
- // Horizontal header
- 'hhea': (function fontFieldsHhea() {
- return stringToArray(
- '\x00\x01\x00\x00' + // Version number
- safeString16(properties.ascent) + // Typographic Ascent
- safeString16(properties.descent) + // Typographic Descent
- '\x00\x00' + // Line Gap
- '\xFF\xFF' + // advanceWidthMax
- '\x00\x00' + // minLeftSidebearing
- '\x00\x00' + // minRightSidebearing
- '\x00\x00' + // xMaxExtent
- safeString16(properties.capHeight) + // caretSlopeRise
- safeString16(Math.tan(properties.italicAngle) *
- properties.xHeight) + // caretSlopeRun
- '\x00\x00' + // caretOffset
- '\x00\x00' + // -reserved-
- '\x00\x00' + // -reserved-
- '\x00\x00' + // -reserved-
- '\x00\x00' + // -reserved-
- '\x00\x00' + // metricDataFormat
- string16(charstrings.length + 1)); // Number of HMetrics
- })(),
-
- // Horizontal metrics
- 'hmtx': (function fontFieldsHmtx() {
+ // Horizontal metrics
+ builder.addTable('hmtx', (function fontFieldsHmtx() {
+ var charstrings = font.charstrings;
+ var cffWidths = font.cff ? font.cff.widths : null;
var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
- for (var i = 0, ii = charstrings.length; i < ii; i++) {
- var charstring = charstrings[i];
- var width = 'width' in charstring ? charstring.width : 0;
+ for (var i = 1, ii = numGlyphs; i < ii; i++) {
+ var width = 0;
+ if (charstrings) {
+ var charstring = charstrings[i - 1];
+ width = 'width' in charstring ? charstring.width : 0;
+ } else if (cffWidths) {
+ width = Math.ceil(cffWidths[i] || 0);
+ }
hmtx += string16(width) + string16(0);
}
- return stringToArray(hmtx);
- })(),
+ return hmtx;
+ })());
- // Maximum profile
- 'maxp': (function fontFieldsMaxp() {
- return stringToArray(
- '\x00\x00\x50\x00' + // Version number
- string16(charstrings.length + 1)); // Num of glyphs
- })(),
+ // Maximum profile
+ builder.addTable('maxp',
+ '\x00\x00\x50\x00' + // Version number
+ string16(numGlyphs)); // Num of glyphs
- // Naming tables
- 'name': stringToArray(createNameTable(fontName)),
+ // Naming tables
+ builder.addTable('name', createNameTable(fontName));
- // PostScript informations
- 'post': stringToArray(createPostTable(properties))
- };
+ // PostScript informations
+ builder.addTable('post', createPostTable(properties));
- for (var field in fields)
- createTableEntry(otf, field, fields[field]);
-
- for (var field in fields) {
- var table = fields[field];
- otf.file += arrayToString(table);
- }
-
- return stringToArray(otf.file);
+ return builder.toArray();
},
- buildToFontChar: function Font_buildToFontChar(toUnicode) {
- var result = [];
- var unusedUnicode = CMAP_GLYPH_OFFSET;
- for (var i = 0, ii = toUnicode.length; i < ii; i++) {
- var unicode = toUnicode[i];
- var fontCharCode = typeof unicode === 'object' ? unusedUnicode++ :
- unicode;
- if (typeof unicode !== 'undefined') {
- if (isString(fontCharCode) && fontCharCode.length === 1) {
- fontCharCode = fontCharCode.charCodeAt(0);
- }
- result[i] = fontCharCode;
- }
+ /**
+ * Builds a char code to unicode map based on section 9.10 of the spec.
+ * @param {Object} properties Font properties object.
+ * @return {Object} A ToUnicodeMap object.
+ */
+ buildToUnicode: function Font_buildToUnicode(properties) {
+ // Section 9.10.2 Mapping Character Codes to Unicode Values
+ if (properties.toUnicode && properties.toUnicode.length !== 0) {
+ return properties.toUnicode;
}
- return result;
- },
-
- rebuildToUnicode: function Font_rebuildToUnicode(properties) {
- var firstChar = properties.firstChar, lastChar = properties.lastChar;
- var map = [];
- var toUnicode = this.toUnicode || this.cidToUnicode;
- if (toUnicode) {
- var isIdentityMap = toUnicode.length === 0;
- for (var i = firstChar, ii = lastChar; i <= ii; i++) {
- // TODO missing map the character according font's CMap
- map[i] = isIdentityMap ? String.fromCharCode(i) : toUnicode[i];
+ // According to the spec if the font is a simple font we should only map
+ // to unicode if the base encoding is MacRoman, MacExpert, or WinAnsi or
+ // the differences array only contains adobe standard or symbol set names,
+ // in pratice it seems better to always try to create a toUnicode
+ // map based of the default encoding.
+ var toUnicode, charcode;
+ if (!properties.composite /* is simple font */) {
+ toUnicode = [];
+ var encoding = properties.defaultEncoding.slice();
+ var baseEncodingName = properties.baseEncodingName;
+ // Merge in the differences array.
+ var differences = properties.differences;
+ for (charcode in differences) {
+ encoding[charcode] = differences[charcode];
}
- } else {
- for (var i = firstChar, ii = lastChar; i <= ii; i++) {
- var glyph = properties.differences[i];
- if (!glyph)
- glyph = properties.baseEncoding[i];
- if (!!glyph && (glyph in GlyphsUnicode))
- map[i] = String.fromCharCode(GlyphsUnicode[glyph]);
- }
- }
- this.toUnicode = map;
- },
-
- loadCidToUnicode: function Font_loadCidToUnicode(properties) {
- if (!properties.cidSystemInfo)
- return;
-
- var cidToUnicodeMap = [], unicodeToCIDMap = [];
- this.cidToUnicode = cidToUnicodeMap;
- this.unicodeToCID = unicodeToCIDMap;
-
- var cidEncoding = properties.cidEncoding;
- if (properties.toUnicode) {
- if (cidEncoding && cidEncoding.indexOf('Identity-') !== 0) {
- warn('Need to create a reverse mapping from \'ToUnicode\' CMap');
- }
- return; // 'ToUnicode' CMap will be used
- }
-
- var cidSystemInfo = properties.cidSystemInfo;
- var cidToUnicode;
- if (cidSystemInfo) {
- cidToUnicode = CIDToUnicodeMaps[
- cidSystemInfo.registry + '-' + cidSystemInfo.ordering];
- }
-
- if (!cidToUnicode)
- return; // identity encoding
-
- var overwrite = HalfwidthCMaps[cidEncoding];
- var cid = 1, i, j, k, ii;
- for (i = 0, ii = cidToUnicode.length; i < ii; ++i) {
- var unicode = cidToUnicode[i];
- if (isArray(unicode)) {
- var length = unicode.length;
- for (j = 0; j < length; j++) {
- cidToUnicodeMap[cid] = k = unicode[j];
- if (!unicodeToCIDMap[k] || overwrite) {
- unicodeToCIDMap[k] = cid;
+ for (charcode in encoding) {
+ // a) Map the character code to a character name.
+ var glyphName = encoding[charcode];
+ // b) Look up the character name in the Adobe Glyph List (see the
+ // Bibliography) to obtain the corresponding Unicode value.
+ if (glyphName === '') {
+ continue;
+ } else if (GlyphsUnicode[glyphName] === undefined) {
+ // (undocumented) c) Few heuristics to recognize unknown glyphs
+ // NOTE: Adobe Reader does not do this step, but OSX Preview does
+ var code = 0;
+ switch (glyphName[0]) {
+ case 'G': // Gxx glyph
+ if (glyphName.length === 3) {
+ code = parseInt(glyphName.substr(1), 16);
+ }
+ break;
+ case 'g': // g00xx glyph
+ if (glyphName.length === 5) {
+ code = parseInt(glyphName.substr(1), 16);
+ }
+ break;
+ case 'C': // Cddd glyph
+ case 'c': // cddd glyph
+ if (glyphName.length >= 3) {
+ code = +glyphName.substr(1);
+ }
+ break;
}
- }
- cid++;
- } else if (typeof unicode === 'object') {
- var fillLength = unicode.f;
- if (fillLength) {
- k = unicode.c;
- for (j = 0; j < fillLength; ++j) {
- cidToUnicodeMap[cid] = k;
- if (!unicodeToCIDMap[k] || overwrite) {
- unicodeToCIDMap[k] = cid;
+ if (code) {
+ // If |baseEncodingName| is one the predefined encodings,
+ // and |code| equals |charcode|, using the glyph defined in the
+ // baseEncoding seems to yield a better |toUnicode| mapping
+ // (fixes issue 5070).
+ if (baseEncodingName && code === +charcode) {
+ var baseEncoding = Encodings[baseEncodingName];
+ if (baseEncoding && (glyphName = baseEncoding[charcode])) {
+ toUnicode[charcode] =
+ String.fromCharCode(GlyphsUnicode[glyphName]);
+ continue;
+ }
}
- cid++;
- k++;
+ toUnicode[charcode] = String.fromCharCode(code);
}
- } else
- cid += unicode.s;
- } else if (unicode) {
- cidToUnicodeMap[cid] = unicode;
- if (!unicodeToCIDMap[unicode] || overwrite) {
- unicodeToCIDMap[unicode] = cid;
+ continue;
}
- cid++;
- } else
- cid++;
+ toUnicode[charcode] = String.fromCharCode(GlyphsUnicode[glyphName]);
+ }
+ return new ToUnicodeMap(toUnicode);
+ }
+ // If the font is a composite font that uses one of the predefined CMaps
+ // listed in Table 118 (except Identity–H and Identity–V) or whose
+ // descendant CIDFont uses the Adobe-GB1, Adobe-CNS1, Adobe-Japan1, or
+ // Adobe-Korea1 character collection:
+ if (properties.composite && (
+ (properties.cMap.builtInCMap &&
+ !(properties.cMap instanceof IdentityCMap)) ||
+ (properties.cidSystemInfo.registry === 'Adobe' &&
+ (properties.cidSystemInfo.ordering === 'GB1' ||
+ properties.cidSystemInfo.ordering === 'CNS1' ||
+ properties.cidSystemInfo.ordering === 'Japan1' ||
+ properties.cidSystemInfo.ordering === 'Korea1')))) {
+ // Then:
+ // a) Map the character code to a character identifier (CID) according
+ // to the font’s CMap.
+ // b) Obtain the registry and ordering of the character collection used
+ // by the font’s CMap (for example, Adobe and Japan1) from its
+ // CIDSystemInfo dictionary.
+ var registry = properties.cidSystemInfo.registry;
+ var ordering = properties.cidSystemInfo.ordering;
+ // c) Construct a second CMap name by concatenating the registry and
+ // ordering obtained in step (b) in the format registry–ordering–UCS2
+ // (for example, Adobe–Japan1–UCS2).
+ var ucs2CMapName = new Name(registry + '-' + ordering + '-UCS2');
+ // d) Obtain the CMap with the name constructed in step (c) (available
+ // from the ASN Web site; see the Bibliography).
+ var ucs2CMap = CMapFactory.create(ucs2CMapName,
+ { url: PDFJS.cMapUrl, packed: PDFJS.cMapPacked }, null);
+ var cMap = properties.cMap;
+ toUnicode = [];
+ cMap.forEach(function(charcode, cid) {
+ assert(cid <= 0xffff, 'Max size of CID is 65,535');
+ // e) Map the CID obtained in step (a) according to the CMap obtained
+ // in step (d), producing a Unicode value.
+ var ucs2 = ucs2CMap.lookup(cid);
+ if (ucs2) {
+ toUnicode[charcode] =
+ String.fromCharCode((ucs2.charCodeAt(0) << 8) +
+ ucs2.charCodeAt(1));
+ }
+ });
+ return new ToUnicodeMap(toUnicode);
}
- if (!cidEncoding) {
- return;
- }
- if (cidEncoding.indexOf('Identity-') !== 0) {
- // input is already Unicode for non-Identity CMap encodings.
- this.cidToUnicode = [];
- // For CIDFontType2, however, we need cid-to-Unicode conversion
- // to rebuild cmap.
- if (properties.type == 'CIDFontType2') {
- this.cidToFontChar = cidToUnicodeMap;
- }
- } else {
- // We don't have to do reverse conversions if the string is
- // already CID.
- this.unicodeToCID = [];
- }
+ // The viewer's choice, just use an identity map.
+ return new IdentityToUnicodeMap(properties.firstChar,
+ properties.lastChar);
},
get spaceWidth() {
@@ -20682,18 +18573,24 @@ var Font = (function FontClosure() {
var glyphUnicode = GlyphsUnicode[glyphName];
// finding the charcode via unicodeToCID map
var charcode = 0;
- if (this.composite)
- charcode = this.unicodeToCID[glyphUnicode];
+ if (this.composite) {
+ if (this.cMap.contains(glyphUnicode)) {
+ charcode = this.cMap.lookup(glyphUnicode);
+ }
+ }
// ... via toUnicode map
- if (!charcode && 'toUnicode' in this)
- charcode = this.toUnicode.indexOf(glyphUnicode);
+ if (!charcode && 'toUnicode' in this) {
+ charcode = this.toUnicode.charCodeOf(glyphUnicode);
+ }
// setting it to unicode if negative or undefined
- if (charcode <= 0)
+ if (charcode <= 0) {
charcode = glyphUnicode;
+ }
// trying to get width via charcode
width = this.widths[charcode];
- if (width)
+ if (width) {
break; // the non-zero width found
+ }
}
width = width || this.defaultWidth;
// Do not shadow the property here. See discussion:
@@ -20703,153 +18600,87 @@ var Font = (function FontClosure() {
},
charToGlyph: function Font_charToGlyph(charcode) {
- var fontCharCode, width, operatorList, disabled;
+ var fontCharCode, width, operatorListId;
- var width = this.widths[charcode];
- var vmetric = this.vmetrics && this.vmetrics[charcode];
-
- switch (this.type) {
- case 'CIDFontType0':
- var cid = this.unicodeToCID[charcode] || charcode;
- if (this.unicodeToCID.length > 0) {
- width = this.widths[cid];
- vmetric = this.vmetrics && this.vmetrics[cid];
- }
- if (this.noUnicodeAdaptation) {
- fontCharCode = this.toFontChar[charcode] || charcode;
- break;
- }
- // CIDFontType0 is not encoded in Unicode.
- fontCharCode = this.toFontChar[cid] || cid;
- break;
- case 'CIDFontType2':
- if (this.unicodeToCID.length > 0) {
- var cid = this.unicodeToCID[charcode] || charcode;
- width = this.widths[cid];
- vmetric = this.vmetrics && this.vmetrics[cid];
- fontCharCode = charcode;
- break;
- }
- fontCharCode = this.toFontChar[charcode] || charcode;
- break;
- case 'MMType1': // XXX at the moment only "standard" fonts are supported
- case 'Type1':
- var glyphName = this.differences[charcode] || this.encoding[charcode];
- if (!isNum(width))
- width = this.widths[glyphName];
- if (this.noUnicodeAdaptation) {
- fontCharCode = mapPrivateUseChars(GlyphsUnicode[glyphName] ||
- charcode);
- break;
- }
- fontCharCode = this.glyphNameMap[glyphName] ||
- GlyphsUnicode[glyphName] || charcode;
- break;
- case 'Type3':
- var glyphName = this.differences[charcode] || this.encoding[charcode];
- operatorList = this.charProcOperatorList[glyphName];
- fontCharCode = charcode;
- break;
- case 'TrueType':
- if (this.useToFontChar) {
- fontCharCode = this.toFontChar[charcode] || charcode;
- break;
- }
- var glyphName = this.differences[charcode] || this.encoding[charcode];
- if (!glyphName)
- glyphName = Encodings.StandardEncoding[charcode];
- if (!isNum(width))
- width = this.widths[glyphName];
- if (this.noUnicodeAdaptation) {
- fontCharCode = GlyphsUnicode[glyphName] || charcode;
- break;
- }
- if (!this.hasEncoding || this.isSymbolicFont) {
- fontCharCode = this.useToFontChar ? this.toFontChar[charcode] :
- charcode;
- break;
- }
-
- // MacRoman encoding address by re-encoding the cmap table
-
- fontCharCode = glyphName in this.glyphNameMap ?
- this.glyphNameMap[glyphName] : GlyphsUnicode[glyphName];
- break;
- default:
- warn('Unsupported font type: ' + this.type);
- break;
+ var widthCode = charcode;
+ if (this.cMap && this.cMap.contains(charcode)) {
+ widthCode = this.cMap.lookup(charcode);
}
-
- var unicodeChars = !('toUnicode' in this) ? charcode :
- this.toUnicode[charcode] || charcode;
- if (typeof unicodeChars === 'number') {
- unicodeChars = String.fromCharCode(unicodeChars);
- }
-
+ width = this.widths[widthCode];
width = isNum(width) ? width : this.defaultWidth;
- disabled = this.unicodeIsEnabled ?
- !this.unicodeIsEnabled[fontCharCode] : false;
+ var vmetric = this.vmetrics && this.vmetrics[widthCode];
+
+ var unicode = this.toUnicode.get(charcode) || charcode;
+ if (typeof unicode === 'number') {
+ unicode = String.fromCharCode(unicode);
+ }
+
+ // First try the toFontChar map, if it's not there then try falling
+ // back to the char code.
+ fontCharCode = this.toFontChar[charcode] || charcode;
+ if (this.missingFile) {
+ fontCharCode = mapSpecialUnicodeValues(fontCharCode);
+ }
+
+ if (this.isType3Font) {
+ // Font char code in this case is actually a glyph name.
+ operatorListId = fontCharCode;
+ }
var accent = null;
- if (this.seacMap && this.seacMap[fontCharCode]) {
- var seac = this.seacMap[fontCharCode];
- fontCharCode = seac.baseUnicode;
+ if (this.seacMap && this.seacMap[charcode]) {
+ var seac = this.seacMap[charcode];
+ fontCharCode = seac.baseFontCharCode;
accent = {
- fontChar: String.fromCharCode(seac.accentUnicode),
+ fontChar: String.fromCharCode(seac.accentFontCharCode),
offset: seac.accentOffset
};
}
- return {
- fontChar: String.fromCharCode(fontCharCode),
- unicode: unicodeChars,
- accent: accent,
- width: width,
- vmetric: vmetric,
- disabled: disabled,
- operatorList: operatorList
- };
+ var fontChar = String.fromCharCode(fontCharCode);
+
+ var glyph = this.glyphCache[charcode];
+ if (!glyph ||
+ !glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
+ operatorListId)) {
+ glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
+ operatorListId);
+ this.glyphCache[charcode] = glyph;
+ }
+ return glyph;
},
charsToGlyphs: function Font_charsToGlyphs(chars) {
var charsCache = this.charsCache;
- var glyphs;
+ var glyphs, glyph, charcode;
// if we translated this string before, just grab it from the cache
if (charsCache) {
glyphs = charsCache[chars];
- if (glyphs)
+ if (glyphs) {
return glyphs;
+ }
}
// lazily create the translation cache
- if (!charsCache)
+ if (!charsCache) {
charsCache = this.charsCache = Object.create(null);
+ }
glyphs = [];
var charsCacheKey = chars;
+ var i = 0, ii;
- var converter;
- var cidEncoding = this.cidEncoding;
- if (cidEncoding) {
- converter = CMapConverterList[cidEncoding];
- if (converter) {
- chars = converter(chars);
- } else if (cidEncoding.indexOf('Uni') !== 0 &&
- cidEncoding.indexOf('Identity-') !== 0) {
- warn('Unsupported CMap: ' + cidEncoding);
- }
- }
- if (!converter && this.cmap) {
- var i = 0;
+ if (this.cMap) {
// composite fonts have multi-byte strings convert the string from
// single-byte to multi-byte
+ var c = {};
while (i < chars.length) {
- var c = this.cmap.readCharCode(chars, i);
- var charcode = c[0];
- var length = c[1];
+ this.cMap.readCharCode(chars, i, c);
+ charcode = c.charcode;
+ var length = c.length;
i += length;
- var glyph = this.charToGlyph(charcode);
+ glyph = this.charToGlyph(charcode);
glyphs.push(glyph);
// placing null after each word break charcode (ASCII SPACE)
// Ignore occurences of 0x20 in multiple-byte codes.
@@ -20857,14 +18688,14 @@ var Font = (function FontClosure() {
glyphs.push(null);
}
}
- }
- else {
- for (var i = 0, ii = chars.length; i < ii; ++i) {
- var charcode = chars.charCodeAt(i);
- var glyph = this.charToGlyph(charcode);
+ } else {
+ for (i = 0, ii = chars.length; i < ii; ++i) {
+ charcode = chars.charCodeAt(i);
+ glyph = this.charToGlyph(charcode);
glyphs.push(glyph);
- if (charcode == 0x20)
+ if (charcode === 0x20) {
glyphs.push(null);
+ }
}
}
@@ -20879,6 +18710,8 @@ var Font = (function FontClosure() {
var ErrorFont = (function ErrorFontClosure() {
function ErrorFont(error) {
this.error = error;
+ this.loadedName = 'g_font_error';
+ this.loading = false;
}
ErrorFont.prototype = {
@@ -20893,6 +18726,61 @@ var ErrorFont = (function ErrorFontClosure() {
return ErrorFont;
})();
+/**
+ * Shared logic for building a char code to glyph id mapping for Type1 and
+ * simple CFF fonts. See section 9.6.6.2 of the spec.
+ * @param {Object} properties Font properties object.
+ * @param {Object} builtInEncoding The encoding contained within the actual font
+ * data.
+ * @param {Array} Array of glyph names where the index is the glyph ID.
+ * @returns {Object} A char code to glyph ID map.
+ */
+function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) {
+ var charCodeToGlyphId = Object.create(null);
+ var glyphId, charCode, baseEncoding;
+
+ if (properties.baseEncodingName) {
+ // If a valid base encoding name was used, the mapping is initialized with
+ // that.
+ baseEncoding = Encodings[properties.baseEncodingName];
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ if (glyphId >= 0) {
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ }
+ } else if (!!(properties.flags & FontFlags.Symbolic)) {
+ // For a symbolic font the encoding should be the fonts built-in
+ // encoding.
+ for (charCode in builtInEncoding) {
+ charCodeToGlyphId[charCode] = builtInEncoding[charCode];
+ }
+ } else {
+ // For non-symbolic fonts that don't have a base encoding the standard
+ // encoding should be used.
+ baseEncoding = Encodings.StandardEncoding;
+ for (charCode = 0; charCode < baseEncoding.length; charCode++) {
+ glyphId = glyphNames.indexOf(baseEncoding[charCode]);
+ if (glyphId >= 0) {
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ }
+ }
+
+ // Lastly, merge in the differences.
+ var differences = properties.differences;
+ if (differences) {
+ for (charCode in differences) {
+ var glyphName = differences[charCode];
+ glyphId = glyphNames.indexOf(glyphName);
+ if (glyphId >= 0) {
+ charCodeToGlyphId[charCode] = glyphId;
+ }
+ }
+ }
+ return charCodeToGlyphId;
+}
+
/*
* CharStrings are encoded following the the CharString Encoding sequence
* describe in Chapter 6 of the "Adobe Type1 Font Format" specification.
@@ -20962,6 +18850,7 @@ var Type1CharString = (function Type1CharStringClosure() {
convert: function Type1CharString_convert(encoded, subrs) {
var count = encoded.length;
var error = false;
+ var wx, sbx, subrNumber;
for (var i = 0; i < count; i++) {
var value = encoded[i];
if (value < 32) {
@@ -21019,7 +18908,7 @@ var Type1CharString = (function Type1CharStringClosure() {
error = true;
break;
}
- var subrNumber = this.stack.pop();
+ subrNumber = this.stack.pop();
error = this.convert(subrs[subrNumber], subrs);
break;
case 11: // return
@@ -21031,12 +18920,12 @@ var Type1CharString = (function Type1CharStringClosure() {
}
// To convert to type2 we have to move the width value to the
// first part of the charstring and then use hmoveto with lsb.
- var wx = this.stack.pop();
- var sbx = this.stack.pop();
+ wx = this.stack.pop();
+ sbx = this.stack.pop();
this.lsb = sbx;
this.width = wx;
- this.stack.push(sbx);
- error = this.executeCommand(1, COMMAND_MAP.hmoveto);
+ this.stack.push(wx, sbx);
+ error = this.executeCommand(2, COMMAND_MAP.hmoveto);
break;
case 14: // endchar
this.output.push(COMMAND_MAP.endchar[0]);
@@ -21105,13 +18994,13 @@ var Type1CharString = (function Type1CharStringClosure() {
// (dx, dy). The height argument will not be used for vmtx and
// vhea tables reconstruction -- ignoring it.
var wy = this.stack.pop();
- var wx = this.stack.pop();
+ wx = this.stack.pop();
var sby = this.stack.pop();
- var sbx = this.stack.pop();
+ sbx = this.stack.pop();
this.lsb = sbx;
this.width = wx;
- this.stack.push(sbx, sby);
- error = this.executeCommand(2, COMMAND_MAP.rmoveto);
+ this.stack.push(wx, sbx, sby);
+ error = this.executeCommand(3, COMMAND_MAP.rmoveto);
break;
case (12 << 8) + 12: // div
if (this.stack.length < 2) {
@@ -21127,7 +19016,7 @@ var Type1CharString = (function Type1CharStringClosure() {
error = true;
break;
}
- var subrNumber = this.stack.pop();
+ subrNumber = this.stack.pop();
var numArgs = this.stack.pop();
if (subrNumber === 0 && numArgs === 3) {
var flexArgs = this.stack.splice(this.stack.length - 17, 17);
@@ -21208,7 +19097,7 @@ var Type1CharString = (function Type1CharStringClosure() {
if (keepStack) {
this.stack.splice(start, howManyArgs);
} else {
- this.stack = [];
+ this.stack.length = 0;
}
return false;
}
@@ -21234,18 +19123,46 @@ var Type1Parser = (function Type1ParserClosure() {
var EEXEC_ENCRYPT_KEY = 55665;
var CHAR_STRS_ENCRYPT_KEY = 4330;
- function decrypt(stream, key, discardNumber) {
- var r = key, c1 = 52845, c2 = 22719;
- var decryptedString = [];
+ function isHexDigit(code) {
+ return code >= 48 && code <= 57 || // '0'-'9'
+ code >= 65 && code <= 70 || // 'A'-'F'
+ code >= 97 && code <= 102; // 'a'-'f'
+ }
- var value = '';
- var count = stream.length;
+ function decrypt(data, key, discardNumber) {
+ var r = key | 0, c1 = 52845, c2 = 22719;
+ var count = data.length;
+ var decrypted = new Uint8Array(count);
for (var i = 0; i < count; i++) {
- value = stream[i];
- decryptedString[i] = value ^ (r >> 8);
+ var value = data[i];
+ decrypted[i] = value ^ (r >> 8);
r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
}
- return decryptedString.slice(discardNumber);
+ return Array.prototype.slice.call(decrypted, discardNumber);
+ }
+
+ function decryptAscii(data, key, discardNumber) {
+ var r = key | 0, c1 = 52845, c2 = 22719;
+ var count = data.length, maybeLength = count >>> 1;
+ var decrypted = new Uint8Array(maybeLength);
+ var i, j;
+ for (i = 0, j = 0; i < count; i++) {
+ var digit1 = data[i];
+ if (!isHexDigit(digit1)) {
+ continue;
+ }
+ i++;
+ var digit2;
+ while (i < count && !isHexDigit(digit2 = data[i])) {
+ i++;
+ }
+ if (i < count) {
+ var value = parseInt(String.fromCharCode(digit1, digit2), 16);
+ decrypted[j++] = value ^ (r >> 8);
+ r = ((value + r) * c1 + c2) & ((1 << 16) - 1);
+ }
+ }
+ return Array.prototype.slice.call(decrypted, discardNumber, j);
}
function isSpecial(c) {
@@ -21257,7 +19174,11 @@ var Type1Parser = (function Type1ParserClosure() {
function Type1Parser(stream, encrypted) {
if (encrypted) {
- stream = new Stream(decrypt(stream.getBytes(), EEXEC_ENCRYPT_KEY, 4));
+ var data = stream.getBytes();
+ var isBinary = !(isHexDigit(data[0]) && isHexDigit(data[1]) &&
+ isHexDigit(data[2]) && isHexDigit(data[3]));
+ stream = new Stream(isBinary ? decrypt(data, EEXEC_ENCRYPT_KEY, 4) :
+ decryptAscii(data, EEXEC_ENCRYPT_KEY, 4));
}
this.stream = stream;
this.nextChar();
@@ -21349,7 +19270,7 @@ var Type1Parser = (function Type1ParserClosure() {
}
}
};
- var token;
+ var token, length, data, lenIV, encoded;
while ((token = this.getToken()) !== null) {
if (token !== '/') {
continue;
@@ -21373,12 +19294,11 @@ var Type1Parser = (function Type1ParserClosure() {
continue;
}
var glyph = this.getToken();
- var length = this.readInt();
+ length = this.readInt();
this.getToken(); // read in 'RD' or '-|'
- var data = stream.makeSubStream(stream.pos, length);
- var lenIV = program.properties.privateData['lenIV'];
- var encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY,
- lenIV);
+ data = stream.makeSubStream(stream.pos, length);
+ lenIV = program.properties.privateData['lenIV'];
+ encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
// Skip past the required space and binary data.
stream.skip(length);
this.nextChar();
@@ -21397,12 +19317,11 @@ var Type1Parser = (function Type1ParserClosure() {
this.getToken(); // read in 'array'
while ((token = this.getToken()) === 'dup') {
var index = this.readInt();
- var length = this.readInt();
+ length = this.readInt();
this.getToken(); // read in 'RD' or '-|'
- var data = stream.makeSubStream(stream.pos, length);
- var lenIV = program.properties.privateData['lenIV'];
- var encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY,
- lenIV);
+ data = stream.makeSubStream(stream.pos, length);
+ lenIV = program.properties.privateData['lenIV'];
+ encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV);
// Skip past the required space and binary data.
stream.skip(length);
this.nextChar();
@@ -21449,8 +19368,8 @@ var Type1Parser = (function Type1ParserClosure() {
}
for (var i = 0; i < charstrings.length; i++) {
- var glyph = charstrings[i].glyph;
- var encoded = charstrings[i].encoded;
+ glyph = charstrings[i].glyph;
+ encoded = charstrings[i].encoded;
var charString = new Type1CharString();
var error = charString.convert(encoded, subrs);
var output = charString.output;
@@ -21461,11 +19380,11 @@ var Type1Parser = (function Type1ParserClosure() {
output = [14];
}
program.charstrings.push({
- glyph: glyph,
- data: output,
- seac: charString.seac,
+ glyphName: glyph,
+ charstring: output,
+ width: charString.width,
lsb: charString.lsb,
- width: charString.width
+ seac: charString.seac
});
}
@@ -21496,7 +19415,7 @@ var Type1Parser = (function Type1ParserClosure() {
this.getToken(); // read in 'array'
for (var j = 0; j < size; j++) {
- var token = this.getToken();
+ token = this.getToken();
// skipping till first dup or def (e.g. ignoring for statement)
while (token !== 'dup' && token !== 'def') {
token = this.getToken();
@@ -21514,10 +19433,7 @@ var Type1Parser = (function Type1ParserClosure() {
this.getToken(); // read the in 'put'
}
}
- if (properties.overridableEncoding && encoding) {
- properties.baseEncoding = encoding;
- break;
- }
+ properties.builtInEncoding = encoding;
break;
case 'FontBBox':
var fontBBox = this.readNumberArray();
@@ -21572,7 +19488,7 @@ var CFFStandardStrings = [
'odieresis', 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex',
'udieresis', 'ugrave', 'yacute', 'ydieresis', 'zcaron', 'exclamsmall',
'Hungarumlautsmall', 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall',
- 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', '266 ff',
+ 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
'onedotenleader', 'zerooldstyle', 'oneoldstyle', 'twooldstyle',
'threeoldstyle', 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle',
'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'commasuperior',
@@ -21615,7 +19531,7 @@ var Type1Font = function Type1Font(name, file, properties) {
var headerBlockLength = properties.length1;
var eexecBlockLength = properties.length2;
var pfbHeader = file.peekBytes(PFB_HEADER_SIZE);
- var pfbHeaderPresent = pfbHeader[0] == 0x80 && pfbHeader[1] == 0x01;
+ var pfbHeaderPresent = pfbHeader[0] === 0x80 && pfbHeader[1] === 0x01;
if (pfbHeaderPresent) {
file.skip(PFB_HEADER_SIZE);
headerBlockLength = (pfbHeader[5] << 24) | (pfbHeader[4] << 16) |
@@ -21637,10 +19553,11 @@ var Type1Font = function Type1Font(name, file, properties) {
var eexecBlock = new Stream(file.getBytes(eexecBlockLength));
var eexecBlockParser = new Type1Parser(eexecBlock, true);
var data = eexecBlockParser.extractFontProgram();
- for (var info in data.properties)
+ for (var info in data.properties) {
properties[info] = data.properties[info];
+ }
- var charstrings = this.getOrderedCharStrings(data.charstrings, properties);
+ var charstrings = data.charstrings;
var type2Charstrings = this.getType2Charstrings(charstrings);
var subrs = this.getType2Subrs(data.subrs);
@@ -21651,35 +19568,37 @@ var Type1Font = function Type1Font(name, file, properties) {
};
Type1Font.prototype = {
- getOrderedCharStrings: function Type1Font_getOrderedCharStrings(glyphs,
- properties) {
- var charstrings = [];
- var usedUnicodes = [];
- var i, length, glyphName;
- var unusedUnicode = CMAP_GLYPH_OFFSET;
- for (i = 0, length = glyphs.length; i < length; i++) {
- var item = glyphs[i];
- var glyphName = item.glyph;
- var unicode = glyphName in GlyphsUnicode ?
- GlyphsUnicode[glyphName] : unusedUnicode++;
- while (usedUnicodes[unicode]) {
- unicode = unusedUnicode++;
+ get numGlyphs() {
+ return this.charstrings.length + 1;
+ },
+
+ getCharset: function Type1Font_getCharset() {
+ var charset = ['.notdef'];
+ var charstrings = this.charstrings;
+ for (var glyphId = 0; glyphId < charstrings.length; glyphId++) {
+ charset.push(charstrings[glyphId].glyphName);
+ }
+ return charset;
+ },
+
+ getGlyphMapping: function Type1Font_getGlyphMapping(properties) {
+ var charstrings = this.charstrings;
+ var glyphNames = ['.notdef'], glyphId;
+ for (glyphId = 0; glyphId < charstrings.length; glyphId++) {
+ glyphNames.push(charstrings[glyphId].glyphName);
+ }
+ var encoding = properties.builtInEncoding;
+ if (encoding) {
+ var builtInEncoding = {};
+ for (var charCode in encoding) {
+ glyphId = glyphNames.indexOf(encoding[charCode]);
+ if (glyphId >= 0) {
+ builtInEncoding[charCode] = glyphId;
+ }
}
- usedUnicodes[unicode] = true;
- charstrings.push({
- glyph: glyphName,
- unicode: unicode,
- gid: i,
- charstring: item.data,
- width: item.width,
- lsb: item.lsb
- });
}
- charstrings.sort(function charstrings_sort(a, b) {
- return a.unicode - b.unicode;
- });
- return charstrings;
+ return type1FontGlyphMapping(properties, builtInEncoding, glyphNames);
},
getSeacs: function Type1Font_getSeacs(charstrings) {
@@ -21688,7 +19607,8 @@ Type1Font.prototype = {
for (i = 0, ii = charstrings.length; i < ii; i++) {
var charstring = charstrings[i];
if (charstring.seac) {
- seacMap[i] = charstring.seac;
+ // Offset by 1 for .notdef
+ seacMap[i + 1] = charstring.seac;
}
}
return seacMap;
@@ -21706,19 +19626,22 @@ Type1Font.prototype = {
getType2Subrs: function Type1Font_getType2Subrs(type1Subrs) {
var bias = 0;
var count = type1Subrs.length;
- if (count < 1133)
+ if (count < 1133) {
bias = 107;
- else if (count < 33769)
+ } else if (count < 33769) {
bias = 1131;
- else
+ } else {
bias = 32768;
+ }
// Add a bunch of empty subrs to deal with the Type2 bias
var type2Subrs = [];
- for (var i = 0; i < bias; i++)
+ var i;
+ for (i = 0; i < bias; i++) {
type2Subrs.push([0x0B]);
+ }
- for (var i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
type2Subrs.push(type1Subrs[i]);
}
@@ -21759,22 +19682,23 @@ Type1Font.prototype = {
var count = glyphs.length;
var charsetArray = [0];
- for (var i = 0; i < count; i++) {
- var index = CFFStandardStrings.indexOf(charstrings[i].glyph);
- // Some characters like asterikmath && circlecopyrt are
- // missing from the original strings, for the moment let's
- // map them to .notdef and see later if it cause any
- // problems
- if (index == -1)
+ var i, ii;
+ for (i = 0; i < count; i++) {
+ var index = CFFStandardStrings.indexOf(charstrings[i].glyphName);
+ // TODO: Insert the string and correctly map it. Previously it was
+ // thought mapping names that aren't in the standard strings to .notdef
+ // was fine, however in issue818 when mapping them all to .notdef the
+ // adieresis glyph no longer worked.
+ if (index === -1) {
index = 0;
-
+ }
charsetArray.push((index >> 8) & 0xff, index & 0xff);
}
cff.charset = new CFFCharset(false, 0, [], charsetArray);
var charStringsIndex = new CFFIndex();
charStringsIndex.add([0x8B, 0x0E]); // .notdef
- for (var i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
charStringsIndex.add(glyphs[i]);
}
cff.charStrings = charStringsIndex;
@@ -21797,10 +19721,11 @@ Type1Font.prototype = {
'StdHW',
'StdVW'
];
- for (var i = 0, ii = fields.length; i < ii; i++) {
+ for (i = 0, ii = fields.length; i < ii; i++) {
var field = fields[i];
- if (!properties.privateData.hasOwnProperty(field))
+ if (!properties.privateData.hasOwnProperty(field)) {
continue;
+ }
var value = properties.privateData[field];
if (isArray(value)) {
// All of the private dictionary array data in CFF must be stored as
@@ -21814,7 +19739,7 @@ Type1Font.prototype = {
cff.topDict.privateDict = privateDict;
var subrIndex = new CFFIndex();
- for (var i = 0, ii = subrs.length; i < ii; i++) {
+ for (i = 0, ii = subrs.length; i < ii; i++) {
subrIndex.add(subrs[i]);
}
privateDict.subrsIndex = subrIndex;
@@ -21831,7 +19756,7 @@ var CFFFont = (function CFFFontClosure() {
var parser = new CFFParser(file, properties);
this.cff = parser.parse();
var compiler = new CFFCompiler(this.cff);
- this.readExtra();
+ this.seacs = this.cff.seacs;
try {
this.data = compiler.compile();
} catch (e) {
@@ -21843,111 +19768,42 @@ var CFFFont = (function CFFFontClosure() {
}
CFFFont.prototype = {
- readExtra: function CFFFont_readExtra() {
- // charstrings contains info about glyphs (one element per glyph
- // containing mappings for {unicode, width})
- var charstrings = this.getCharStrings();
-
- // create the mapping between charstring and glyph id
- var glyphIds = [];
- for (var i = 0, ii = charstrings.length; i < ii; i++)
- glyphIds.push(charstrings[i].gid);
-
- this.charstrings = charstrings;
- this.glyphIds = glyphIds;
- this.seacs = this.cff.seacs;
+ get numGlyphs() {
+ return this.cff.charStrings.count;
},
- getCharStrings: function CFFFont_getCharStrings() {
+ getCharset: function CFFFont_getCharset() {
+ return this.cff.charset.charset;
+ },
+ getGlyphMapping: function CFFFont_getGlyphMapping() {
var cff = this.cff;
+ var properties = this.properties;
var charsets = cff.charset.charset;
- var encoding = cff.encoding ? cff.encoding.encoding : null;
- var charstrings = [];
- var unicodeUsed = [];
- var unassignedUnicodeItems = [];
- var inverseEncoding = [];
- var gidStart = 0;
- if (charsets[0] === '.notdef') {
- gidStart = 1;
- }
- // According to section 9.7.4.2 CIDFontType0C glyph selection should be
- // handled differently.
- if (this.properties.subtype === 'CIDFontType0C') {
- if (this.cff.isCIDFont) {
+ var charCodeToGlyphId;
+ var glyphId;
+
+ if (properties.composite) {
+ charCodeToGlyphId = Object.create(null);
+ if (cff.isCIDFont) {
// If the font is actually a CID font then we should use the charset
// to map CIDs to GIDs.
- inverseEncoding = charsets;
+ for (glyphId = 0; glyphId < charsets.length; glyphId++) {
+ var cid = charsets[glyphId];
+ var charCode = properties.cMap.charCodeOf(cid);
+ charCodeToGlyphId[charCode] = glyphId;
+ }
} else {
// If it is NOT actually a CID font then CIDs should be mapped
// directly to GIDs.
- inverseEncoding = [];
- for (var i = 0, ii = cff.charStrings.count; i < ii; i++) {
- inverseEncoding.push(i);
- }
- // Use the identity map for charsets as well.
- charsets = inverseEncoding;
- }
- } else {
- for (var charcode in encoding) {
- var gid = encoding[charcode];
- if (gid in inverseEncoding) {
- // Glyphs can be multiply-encoded if there was an encoding
- // supplement. Convert to an array and append the charcode.
- var previousCharcode = inverseEncoding[gid];
- if (!isArray(previousCharcode)) {
- inverseEncoding[gid] = [previousCharcode];
- }
- inverseEncoding[gid].push(charcode | 0);
- } else {
- inverseEncoding[gid] = charcode | 0;
+ for (glyphId = 0; glyphId < cff.charStrings.count; glyphId++) {
+ charCodeToGlyphId[glyphId] = glyphId;
}
}
+ return charCodeToGlyphId;
}
- for (var i = gidStart, ii = charsets.length; i < ii; i++) {
- var glyph = charsets[i];
-
- var codes = inverseEncoding[i];
- if (!isArray(codes)) {
- codes = [codes];
- }
-
- for (var j = 0; j < codes.length; j++) {
- var code = codes[j];
-
- if (!code || isSpecialUnicode(code)) {
- unassignedUnicodeItems.push(i, code);
- continue;
- }
- charstrings.push({
- unicode: code,
- code: code,
- gid: i,
- glyph: glyph
- });
- unicodeUsed[code] = true;
- }
- }
-
- var nextUnusedUnicode = CMAP_GLYPH_OFFSET;
- for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; j += 2) {
- var i = unassignedUnicodeItems[j];
- // giving unicode value anyway
- while (nextUnusedUnicode in unicodeUsed)
- nextUnusedUnicode++;
- var unicode = nextUnusedUnicode++;
- charstrings.push({
- unicode: unicode,
- code: unassignedUnicodeItems[j + 1] || 0,
- gid: i,
- glyph: charsets[i]
- });
- }
-
- // sort the array by the unicode value (again)
- charstrings.sort(function getCharStringsSort(a, b) {
- return a.unicode - b.unicode;
- });
- return charstrings;
+ var encoding = cff.encoding ? cff.encoding.encoding : null;
+ charCodeToGlyphId = type1FontGlyphMapping(properties, encoding, charsets);
+ return charCodeToGlyphId;
}
};
@@ -21957,10 +19813,10 @@ var CFFFont = (function CFFFontClosure() {
var CFFParser = (function CFFParserClosure() {
var CharstringValidationData = [
null,
- { id: 'hstem', min: 2, resetStack: true, stem: true },
+ { id: 'hstem', min: 2, stackClearing: true, stem: true },
null,
- { id: 'vstem', min: 2, resetStack: true, stem: true },
- { id: 'vmoveto', min: 1, resetStack: true },
+ { id: 'vstem', min: 2, stackClearing: true, stem: true },
+ { id: 'vmoveto', min: 1, stackClearing: true },
{ id: 'rlineto', min: 2, resetStack: true },
{ id: 'hlineto', min: 1, resetStack: true },
{ id: 'vlineto', min: 1, resetStack: true },
@@ -21970,16 +19826,16 @@ var CFFParser = (function CFFParserClosure() {
{ id: 'return', min: 0, undefStack: true },
null, // 12
null,
- null, // endchar
+ { id: 'endchar', min: 0, stackClearing: true },
null,
null,
null,
- { id: 'hstemhm', min: 2, resetStack: true, stem: true },
- null, // hintmask
- null, // cntrmask
- { id: 'rmoveto', min: 2, resetStack: true },
- { id: 'hmoveto', min: 1, resetStack: true },
- { id: 'vstemhm', min: 2, resetStack: true, stem: true },
+ { id: 'hstemhm', min: 2, stackClearing: true, stem: true },
+ { id: 'hintmask', min: 0, stackClearing: true },
+ { id: 'cntrmask', min: 0, stackClearing: true },
+ { id: 'rmoveto', min: 2, stackClearing: true },
+ { id: 'hmoveto', min: 1, stackClearing: true },
+ { id: 'vstemhm', min: 2, stackClearing: true, stem: true },
{ id: 'rcurveline', min: 8, resetStack: true },
{ id: 'rlinecurve', min: 8, resetStack: true },
{ id: 'vvcurveto', min: 4, resetStack: true },
@@ -22085,6 +19941,7 @@ var CFFParser = (function CFFParserClosure() {
var charStringsAndSeacs = this.parseCharStrings(charStringOffset);
cff.charStrings = charStringsAndSeacs.charStrings;
cff.seacs = charStringsAndSeacs.seacs;
+ cff.widths = charStringsAndSeacs.widths;
var fontMatrix = topDict.getByName('FontMatrix');
if (fontMatrix) {
@@ -22129,12 +19986,17 @@ var CFFParser = (function CFFParserClosure() {
},
parseHeader: function CFFParser_parseHeader() {
var bytes = this.bytes;
+ var bytesLength = bytes.length;
var offset = 0;
- while (bytes[offset] != 1)
+ // Prevent an infinite loop, by checking that the offset is within the
+ // bounds of the bytes array. Necessary in empty, or invalid, font files.
+ while (offset < bytesLength && bytes[offset] !== 1) {
++offset;
-
- if (offset !== 0) {
+ }
+ if (offset >= bytesLength) {
+ error('Invalid CFF header');
+ } else if (offset !== 0) {
info('cff data is shifted');
bytes = bytes.subarray(offset);
this.bytes = bytes;
@@ -22144,7 +20006,7 @@ var CFFParser = (function CFFParserClosure() {
var hdrSize = bytes[2];
var offSize = bytes[3];
var header = new CFFHeader(major, minor, hdrSize, offSize);
- return {obj: header, endPos: hdrSize};
+ return { obj: header, endPos: hdrSize };
},
parseDict: function CFFParser_parseDict(dict) {
var pos = 0;
@@ -22186,12 +20048,14 @@ var CFFParser = (function CFFParserClosure() {
var b1 = b >> 4;
var b2 = b & 15;
- if (b1 == eof)
+ if (b1 === eof) {
break;
+ }
str += lookup[b1];
- if (b2 == eof)
+ if (b2 === eof) {
break;
+ }
str += lookup[b2];
}
return parseFloat(str);
@@ -22200,13 +20064,14 @@ var CFFParser = (function CFFParserClosure() {
var operands = [];
var entries = [];
- var pos = 0;
+ pos = 0;
var end = dict.length;
while (pos < end) {
var b = dict[pos];
if (b <= 21) {
- if (b === 12)
+ if (b === 12) {
b = (b << 8) | dict[++pos];
+ }
entries.push([b, operands]);
operands = [];
++pos;
@@ -22221,15 +20086,15 @@ var CFFParser = (function CFFParserClosure() {
var bytes = this.bytes;
var count = (bytes[pos++] << 8) | bytes[pos++];
var offsets = [];
- var start = pos;
var end = pos;
+ var i, ii;
if (count !== 0) {
var offsetSize = bytes[pos++];
// add 1 for offset to determine size of last object
var startPos = pos + ((count + 1) * offsetSize) - 1;
- for (var i = 0, ii = count + 1; i < ii; ++i) {
+ for (i = 0, ii = count + 1; i < ii; ++i) {
var offset = 0;
for (var j = 0; j < offsetSize; ++j) {
offset <<= 8;
@@ -22239,7 +20104,7 @@ var CFFParser = (function CFFParserClosure() {
}
end = offsets[count];
}
- for (var i = 0, ii = offsets.length - 1; i < ii; ++i) {
+ for (i = 0, ii = offsets.length - 1; i < ii; ++i) {
var offsetStart = offsets[i];
var offsetEnd = offsets[i + 1];
cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
@@ -22263,13 +20128,13 @@ var CFFParser = (function CFFParserClosure() {
if ((c < 33 || c > 126) || c === 91 /* [ */ || c === 93 /* ] */ ||
c === 40 /* ( */ || c === 41 /* ) */ || c === 123 /* { */ ||
c === 125 /* } */ || c === 60 /* < */ || c === 62 /* > */ ||
- c === 47 /* / */ || c === 37 /* % */) {
+ c === 47 /* / */ || c === 37 /* % */ || c === 35 /* # */) {
data[j] = 95;
continue;
}
data[j] = c;
}
- names.push(String.fromCharCode.apply(null, data));
+ names.push(bytesToString(data));
}
return names;
},
@@ -22277,14 +20142,12 @@ var CFFParser = (function CFFParserClosure() {
var strings = new CFFStrings();
for (var i = 0, ii = index.count; i < ii; ++i) {
var data = index.get(i);
- strings.add(String.fromCharCode.apply(null, data));
+ strings.add(bytesToString(data));
}
return strings;
},
createDict: function CFFParser_createDict(Type, dict, strings) {
var cffDict = new Type(strings);
- var types = cffDict.types;
-
for (var i = 0, ii = dict.length; i < ii; ++i) {
var pair = dict[i];
var key = pair[0];
@@ -22296,6 +20159,7 @@ var CFFParser = (function CFFParserClosure() {
parseCharStrings: function CFFParser_parseCharStrings(charStringOffset) {
var charStrings = this.parseIndex(charStringOffset).obj;
var seacs = [];
+ var widths = [];
var count = charStrings.count;
for (var i = 0; i < count; i++) {
var charstring = charStrings.get(i);
@@ -22307,10 +20171,11 @@ var CFFParser = (function CFFParserClosure() {
var valid = true;
var data = charstring;
var length = data.length;
+ var firstStackClearing = true;
for (var j = 0; j < length;) {
var value = data[j++];
var validationCommand = null;
- if (value == 12) {
+ if (value === 12) {
var q = data[j++];
if (q === 0) {
// The CFF specification state that the 'dotsection' command
@@ -22328,7 +20193,7 @@ var CFFParser = (function CFFParserClosure() {
stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16)) >> 16;
j += 2;
stackSize++;
- } else if (value == 14) {
+ } else if (value === 14) {
if (stackSize >= 4) {
stackSize -= 4;
if (SEAC_ANALYSIS_ENABLED) {
@@ -22336,24 +20201,26 @@ var CFFParser = (function CFFParserClosure() {
valid = false;
}
}
+ validationCommand = CharstringValidationData[value];
} else if (value >= 32 && value <= 246) { // number
stack[stackSize] = value - 139;
stackSize++;
} else if (value >= 247 && value <= 254) { // number (+1 bytes)
- stack[stackSize] = value < 251 ?
- ((value - 247) << 8) + data[j] + 108 :
- -((value - 251) << 8) - data[j] - 108;
+ stack[stackSize] = (value < 251 ?
+ ((value - 247) << 8) + data[j] + 108 :
+ -((value - 251) << 8) - data[j] - 108);
j++;
stackSize++;
- } else if (value == 255) { // number (32 bit)
+ } else if (value === 255) { // number (32 bit)
stack[stackSize] = ((data[j] << 24) | (data[j + 1] << 16) |
- (data[j + 2] << 8) | data[j + 3]) / 65536;
+ (data[j + 2] << 8) | data[j + 3]) / 65536;
j += 4;
stackSize++;
- } else if (value == 19 || value == 20) {
+ } else if (value === 19 || value === 20) {
hints += stackSize >> 1;
j += (hints + 7) >> 3; // skipping right amount of hints flag data
- stackSize = 0;
+ stackSize %= 2;
+ validationCommand = CharstringValidationData[value];
} else {
validationCommand = CharstringValidationData[value];
}
@@ -22370,17 +20237,35 @@ var CFFParser = (function CFFParserClosure() {
break;
}
}
+ if (firstStackClearing && validationCommand.stackClearing) {
+ firstStackClearing = false;
+ // the optional character width can be found before the first
+ // stack-clearing command arguments
+ stackSize -= validationCommand.min;
+ if (stackSize >= 2 && validationCommand.stem) {
+ // there are even amount of arguments for stem commands
+ stackSize %= 2;
+ } else if (stackSize > 1) {
+ warn('Found too many parameters for stack-clearing command');
+ }
+ if (stackSize > 0 && stack[stackSize - 1] >= 0) {
+ widths[i] = stack[stackSize - 1];
+ }
+ }
if ('stackDelta' in validationCommand) {
if ('stackFn' in validationCommand) {
validationCommand.stackFn(stack, stackSize);
}
stackSize += validationCommand.stackDelta;
+ } else if (validationCommand.stackClearing) {
+ stackSize = 0;
} else if (validationCommand.resetStack) {
stackSize = 0;
undefStack = false;
} else if (validationCommand.undefStack) {
stackSize = 0;
undefStack = true;
+ firstStackClearing = false;
}
}
}
@@ -22389,7 +20274,7 @@ var CFFParser = (function CFFParserClosure() {
charStrings.set(i, new Uint8Array([14]));
}
}
- return { charStrings: charStrings, seacs: seacs };
+ return { charStrings: charStrings, seacs: seacs, widths: widths };
},
emptyPrivateDictionary:
function CFFParser_emptyPrivateDictionary(parentDict) {
@@ -22426,8 +20311,9 @@ var CFFParser = (function CFFParserClosure() {
parentDict.privateDict = privateDict;
// Parse the Subrs index also since it's relative to the private dict.
- if (!privateDict.getByName('Subrs'))
+ if (!privateDict.getByName('Subrs')) {
return;
+ }
var subrsOffset = privateDict.getByName('Subrs');
var relativeOffset = offset + subrsOffset;
// Validate the offset.
@@ -22442,10 +20328,10 @@ var CFFParser = (function CFFParserClosure() {
if (pos === 0) {
return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE,
ISOAdobeCharset);
- } else if (pos == 1) {
+ } else if (pos === 1) {
return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT,
ExpertCharset);
- } else if (pos == 2) {
+ } else if (pos === 2) {
return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET,
ExpertSubsetCharset);
}
@@ -22454,31 +20340,34 @@ var CFFParser = (function CFFParserClosure() {
var start = pos;
var format = bytes[pos++];
var charset = ['.notdef'];
+ var id, count, i;
// subtract 1 for the .notdef glyph
length -= 1;
switch (format) {
case 0:
- for (var i = 0; i < length; i++) {
- var id = (bytes[pos++] << 8) | bytes[pos++];
+ for (i = 0; i < length; i++) {
+ id = (bytes[pos++] << 8) | bytes[pos++];
charset.push(cid ? id : strings.get(id));
}
break;
case 1:
while (charset.length <= length) {
- var id = (bytes[pos++] << 8) | bytes[pos++];
- var count = bytes[pos++];
- for (var i = 0; i <= count; i++)
+ id = (bytes[pos++] << 8) | bytes[pos++];
+ count = bytes[pos++];
+ for (i = 0; i <= count; i++) {
charset.push(cid ? id++ : strings.get(id++));
+ }
}
break;
case 2:
while (charset.length <= length) {
- var id = (bytes[pos++] << 8) | bytes[pos++];
- var count = (bytes[pos++] << 8) | bytes[pos++];
- for (var i = 0; i <= count; i++)
+ id = (bytes[pos++] << 8) | bytes[pos++];
+ count = (bytes[pos++] << 8) | bytes[pos++];
+ for (i = 0; i <= count; i++) {
charset.push(cid ? id++ : strings.get(id++));
+ }
}
break;
default:
@@ -22498,47 +20387,49 @@ var CFFParser = (function CFFParserClosure() {
var bytes = this.bytes;
var predefined = false;
var hasSupplement = false;
- var format;
+ var format, i, ii;
var raw = null;
function readSupplement() {
var supplementsCount = bytes[pos++];
- for (var i = 0; i < supplementsCount; i++) {
+ for (i = 0; i < supplementsCount; i++) {
var code = bytes[pos++];
var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
encoding[code] = charset.indexOf(strings.get(sid));
}
}
- if (pos === 0 || pos == 1) {
+ if (pos === 0 || pos === 1) {
predefined = true;
format = pos;
var baseEncoding = pos ? Encodings.ExpertEncoding :
Encodings.StandardEncoding;
- for (var i = 0, ii = charset.length; i < ii; i++) {
+ for (i = 0, ii = charset.length; i < ii; i++) {
var index = baseEncoding.indexOf(charset[i]);
- if (index != -1) {
+ if (index !== -1) {
encoding[index] = i;
}
}
} else {
var dataStart = pos;
- var format = bytes[pos++];
+ format = bytes[pos++];
switch (format & 0x7f) {
case 0:
var glyphsCount = bytes[pos++];
- for (var i = 1; i <= glyphsCount; i++)
+ for (i = 1; i <= glyphsCount; i++) {
encoding[bytes[pos++]] = i;
+ }
break;
case 1:
var rangesCount = bytes[pos++];
var gid = 1;
- for (var i = 0; i < rangesCount; i++) {
+ for (i = 0; i < rangesCount; i++) {
var start = bytes[pos++];
var left = bytes[pos++];
- for (var j = start; j <= start + left; j++)
+ for (var j = start; j <= start + left; j++) {
encoding[j] = gid++;
+ }
}
break;
@@ -22567,21 +20458,24 @@ var CFFParser = (function CFFParserClosure() {
var bytes = this.bytes;
var format = bytes[pos++];
var fdSelect = [];
+ var i;
+
switch (format) {
case 0:
- for (var i = 0; i < length; ++i) {
+ for (i = 0; i < length; ++i) {
var id = bytes[pos++];
fdSelect.push(id);
}
break;
case 3:
var rangesCount = (bytes[pos++] << 8) | bytes[pos++];
- for (var i = 0; i < rangesCount; ++i) {
+ for (i = 0; i < rangesCount; ++i) {
var first = (bytes[pos++] << 8) | bytes[pos++];
var fdIndex = bytes[pos++];
var next = (bytes[pos] << 8) | bytes[pos + 1];
- for (var j = first; j < next; ++j)
+ for (var j = first; j < next; ++j) {
fdSelect.push(fdIndex);
+ }
}
// Advance past the sentinel(next).
pos += 2;
@@ -22635,10 +20529,12 @@ var CFFStrings = (function CFFStringsClosure() {
}
CFFStrings.prototype = {
get: function CFFStrings_get(index) {
- if (index >= 0 && index <= 390)
+ if (index >= 0 && index <= 390) {
return CFFStandardStrings[index];
- if (index - 391 <= this.strings.length)
+ }
+ if (index - 391 <= this.strings.length) {
return this.strings[index - 391];
+ }
return CFFStandardStrings[0];
},
add: function CFFStrings_add(value) {
@@ -22689,15 +20585,18 @@ var CFFDict = (function CFFDictClosure() {
CFFDict.prototype = {
// value should always be an array
setByKey: function CFFDict_setByKey(key, value) {
- if (!(key in this.keyToNameMap))
+ if (!(key in this.keyToNameMap)) {
return false;
+ }
// ignore empty values
- if (value.length === 0)
+ if (value.length === 0) {
return true;
+ }
var type = this.types[key];
// remove the array wrapping these types of values
- if (type === 'num' || type === 'sid' || type === 'offset')
+ if (type === 'num' || type === 'sid' || type === 'offset') {
value = value[0];
+ }
this.values[key] = value;
return true;
},
@@ -22711,11 +20610,13 @@ var CFFDict = (function CFFDictClosure() {
return this.nameToKeyMap[name] in this.values;
},
getByName: function CFFDict_getByName(name) {
- if (!(name in this.nameToKeyMap))
+ if (!(name in this.nameToKeyMap)) {
error('Invalid dictionary name "' + name + '"');
+ }
var key = this.nameToKeyMap[name];
- if (!(key in this.values))
+ if (!(key in this.values)) {
return this.defaults[key];
+ }
return this.values[key];
},
removeByName: function CFFDict_removeByName(name) {
@@ -22788,8 +20689,9 @@ var CFFTopDict = (function CFFTopDictClosure() {
];
var tables = null;
function CFFTopDict(strings) {
- if (tables === null)
+ if (tables === null) {
tables = CFFDict.createTables(layout);
+ }
CFFDict.call(this, tables, strings);
this.privateDict = null;
}
@@ -22820,8 +20722,9 @@ var CFFPrivateDict = (function CFFPrivateDictClosure() {
];
var tables = null;
function CFFPrivateDict(strings) {
- if (tables === null)
+ if (tables === null) {
tables = CFFDict.createTables(layout);
+ }
CFFDict.call(this, tables, strings);
this.subrsIndex = null;
}
@@ -22834,11 +20737,6 @@ var CFFCharsetPredefinedTypes = {
EXPERT: 1,
EXPERT_SUBSET: 2
};
-var CFFCharsetEmbeddedTypes = {
- FORMAT0: 0,
- FORMAT1: 1,
- FORMAT2: 2
-};
var CFFCharset = (function CFFCharsetClosure() {
function CFFCharset(predefined, format, charset, raw) {
this.predefined = predefined;
@@ -22849,14 +20747,6 @@ var CFFCharset = (function CFFCharsetClosure() {
return CFFCharset;
})();
-var CFFEncodingPredefinedTypes = {
- STANDARD: 0,
- EXPERT: 1
-};
-var CFFCharsetEmbeddedTypes = {
- FORMAT0: 0,
- FORMAT1: 1
-};
var CFFEncoding = (function CFFEncodingClosure() {
function CFFEncoding(predefined, format, encoding, raw) {
this.predefined = predefined;
@@ -22886,8 +20776,9 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
return key in this.offsets;
},
track: function CFFOffsetTracker_track(key, location) {
- if (key in this.offsets)
+ if (key in this.offsets) {
error('Already tracking location of ' + key);
+ }
this.offsets[key] = location;
},
offset: function CFFOffsetTracker_offset(value) {
@@ -22898,8 +20789,9 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
setEntryLocation: function CFFOffsetTracker_setEntryLocation(key,
values,
output) {
- if (!(key in this.offsets))
+ if (!(key in this.offsets)) {
error('Not tracking location of ' + key);
+ }
var data = output.data;
var dataOffset = this.offsets[key];
var size = 5;
@@ -22911,8 +20803,9 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
var offset4 = offset0 + 4;
// It's easy to screw up offsets so perform this sanity check.
if (data[offset0] !== 0x1d || data[offset1] !== 0 ||
- data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0)
+ data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {
error('writing to an offset that is not empty');
+ }
var value = values[i];
data[offset0] = 0x1d;
data[offset1] = (value >> 24) & 0xFF;
@@ -22927,13 +20820,6 @@ var CFFOffsetTracker = (function CFFOffsetTrackerClosure() {
// Takes a CFF and converts it to the binary representation.
var CFFCompiler = (function CFFCompilerClosure() {
- function stringToArray(str) {
- var array = [];
- for (var i = 0, ii = str.length; i < ii; ++i)
- array[i] = str.charCodeAt(i);
-
- return array;
- }
function CFFCompiler(cff) {
this.cff = cff;
}
@@ -23030,7 +20916,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
output.add(fdSelect);
// It is unclear if the sub font dictionary can have CID related
// dictionary keys, but the sanitizer doesn't like them so remove them.
- var compiled = this.compileTopDicts(cff.fdArray, output.length, true);
+ compiled = this.compileTopDicts(cff.fdArray, output.length, true);
topDictTracker.setEntryLocation('FDArray', [output.length], output);
output.add(compiled.output);
var fontDictTrackers = compiled.trackers;
@@ -23047,10 +20933,11 @@ var CFFCompiler = (function CFFCompilerClosure() {
return output.data;
},
encodeNumber: function CFFCompiler_encodeNumber(value) {
- if (parseFloat(value) == parseInt(value, 10) && !isNaN(value)) // isInt
+ if (parseFloat(value) === parseInt(value, 10) && !isNaN(value)) { // isInt
return this.encodeInteger(value);
- else
+ } else {
return this.encodeFloat(value);
+ }
},
encodeFloat: function CFFCompiler_encodeFloat(num) {
var value = num.toString();
@@ -23063,7 +20950,8 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
var nibbles = '';
- for (var i = 0, ii = value.length; i < ii; ++i) {
+ var i, ii;
+ for (i = 0, ii = value.length; i < ii; ++i) {
var a = value[i];
if (a === 'e') {
nibbles += value[++i] === '-' ? 'c' : 'b';
@@ -23077,7 +20965,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
nibbles += (nibbles.length & 1) ? 'f' : 'ff';
var out = [30];
- for (var i = 0, ii = nibbles.length; i < ii; i += 2) {
+ for (i = 0, ii = nibbles.length; i < ii; i += 2) {
out.push(parseInt(nibbles.substr(i, 2), 16));
}
return out;
@@ -23113,8 +21001,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
},
compileNameIndex: function CFFCompiler_compileNameIndex(names) {
var nameIndex = new CFFIndex();
- for (var i = 0, ii = names.length; i < ii; ++i)
- nameIndex.add(stringToArray(names[i]));
+ for (var i = 0, ii = names.length; i < ii; ++i) {
+ nameIndex.add(stringToBytes(names[i]));
+ }
return this.compileIndex(nameIndex);
},
compileTopDicts: function CFFCompiler_compileTopDicts(dicts,
@@ -23182,16 +21071,22 @@ var CFFCompiler = (function CFFCompilerClosure() {
var order = dict.order;
for (var i = 0; i < order.length; ++i) {
var key = order[i];
- if (!(key in dict.values))
+ if (!(key in dict.values)) {
continue;
+ }
var values = dict.values[key];
var types = dict.types[key];
- if (!isArray(types)) types = [types];
- if (!isArray(values)) values = [values];
+ if (!isArray(types)) {
+ types = [types];
+ }
+ if (!isArray(values)) {
+ values = [values];
+ }
// Remove any empty dict values.
- if (values.length === 0)
+ if (values.length === 0) {
continue;
+ }
for (var j = 0, jj = types.length; j < jj; ++j) {
var type = types[j];
@@ -23208,15 +21103,17 @@ var CFFCompiler = (function CFFCompilerClosure() {
var name = dict.keyToNameMap[key];
// Some offsets have the offset and the length, so just record the
// position of the first one.
- if (!offsetTracker.isTracking(name))
+ if (!offsetTracker.isTracking(name)) {
offsetTracker.track(name, out.length);
+ }
out = out.concat([0x1d, 0, 0, 0, 0]);
break;
case 'array':
case 'delta':
out = out.concat(this.encodeNumber(value));
- for (var k = 1, kk = values.length; k < kk; ++k)
+ for (var k = 1, kk = values.length; k < kk; ++k) {
out = out.concat(this.encodeNumber(values[k]));
+ }
break;
default:
error('Unknown data type of ' + type);
@@ -23229,8 +21126,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
},
compileStringIndex: function CFFCompiler_compileStringIndex(strings) {
var stringIndex = new CFFIndex();
- for (var i = 0, ii = strings.length; i < ii; ++i)
- stringIndex.add(stringToArray(strings[i]));
+ for (var i = 0, ii = strings.length; i < ii; ++i) {
+ stringIndex.add(stringToBytes(strings[i]));
+ }
return this.compileIndex(stringIndex);
},
compileGlobalSubrIndex: function CFFCompiler_compileGlobalSubrIndex() {
@@ -23251,8 +21149,9 @@ var CFFCompiler = (function CFFCompilerClosure() {
},
compileTypedArray: function CFFCompiler_compileTypedArray(data) {
var out = [];
- for (var i = 0, ii = data.length; i < ii; ++i)
+ for (var i = 0, ii = data.length; i < ii; ++i) {
out[i] = data[i];
+ }
return out;
},
compileIndex: function CFFCompiler_compileIndex(index, trackers) {
@@ -23263,31 +21162,34 @@ var CFFCompiler = (function CFFCompilerClosure() {
// If there is no object, just create an index. This technically
// should just be [0, 0] but OTS has an issue with that.
- if (count === 0)
+ if (count === 0) {
return [0, 0, 0];
+ }
var data = [(count >> 8) & 0xFF, count & 0xff];
- var lastOffset = 1;
- for (var i = 0; i < count; ++i)
+ var lastOffset = 1, i;
+ for (i = 0; i < count; ++i) {
lastOffset += objects[i].length;
+ }
var offsetSize;
- if (lastOffset < 0x100)
+ if (lastOffset < 0x100) {
offsetSize = 1;
- else if (lastOffset < 0x10000)
+ } else if (lastOffset < 0x10000) {
offsetSize = 2;
- else if (lastOffset < 0x1000000)
+ } else if (lastOffset < 0x1000000) {
offsetSize = 3;
- else
+ } else {
offsetSize = 4;
+ }
// Next byte contains the offset size use to reference object in the file
data.push(offsetSize);
// Add another offset after this one because we need a new offset
var relativeOffset = 1;
- for (var i = 0; i < count + 1; i++) {
+ for (i = 0; i < count + 1; i++) {
if (offsetSize === 1) {
data.push(relativeOffset & 0xFF);
} else if (offsetSize === 2) {
@@ -23304,17 +21206,19 @@ var CFFCompiler = (function CFFCompilerClosure() {
relativeOffset & 0xFF);
}
- if (objects[i])
+ if (objects[i]) {
relativeOffset += objects[i].length;
+ }
}
- var offset = data.length;
- for (var i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
// Notify the tracker where the object will be offset in the data.
- if (trackers[i])
+ if (trackers[i]) {
trackers[i].offset(data.length);
- for (var j = 0, jj = objects[i].length; j < jj; j++)
+ }
+ for (var j = 0, jj = objects[i].length; j < jj; j++) {
data.push(objects[i][j]);
+ }
}
return data;
}
@@ -23334,7 +21238,7 @@ var CFFCompiler = (function CFFCompilerClosure() {
// https://github.com/mozilla/pdf.js/issues/1689
(function checkChromeWindows() {
if (/Windows.*Chrome/.test(navigator.userAgent)) {
- SYMBOLIC_FONT_GLYPH_OFFSET = 0xF100;
+ SKIP_PRIVATE_USE_RANGE_F000_TO_F01F = true;
}
})();
@@ -23350,25 +21254,26 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
function parseCmap(data, start, end) {
- var offset = getUshort(data, start + 2) === 1 ? getLong(data, start + 8) :
- getLong(data, start + 16);
+ var offset = (getUshort(data, start + 2) === 1 ?
+ getLong(data, start + 8) : getLong(data, start + 16));
var format = getUshort(data, start + offset);
+ var length, ranges, p, i;
if (format === 4) {
- var length = getUshort(data, start + offset + 2);
+ length = getUshort(data, start + offset + 2);
var segCount = getUshort(data, start + offset + 6) >> 1;
- var p = start + offset + 14;
- var ranges = [];
- for (var i = 0; i < segCount; i++, p += 2) {
+ p = start + offset + 14;
+ ranges = [];
+ for (i = 0; i < segCount; i++, p += 2) {
ranges[i] = {end: getUshort(data, p)};
}
p += 2;
- for (var i = 0; i < segCount; i++, p += 2) {
+ for (i = 0; i < segCount; i++, p += 2) {
ranges[i].start = getUshort(data, p);
}
- for (var i = 0; i < segCount; i++, p += 2) {
+ for (i = 0; i < segCount; i++, p += 2) {
ranges[i].idDelta = getUshort(data, p);
}
- for (var i = 0; i < segCount; i++, p += 2) {
+ for (i = 0; i < segCount; i++, p += 2) {
var idOffset = getUshort(data, p);
if (idOffset === 0) {
continue;
@@ -23381,11 +21286,11 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
return ranges;
} else if (format === 12) {
- var length = getLong(data, start + offset + 4);
+ length = getLong(data, start + offset + 4);
var groups = getLong(data, start + offset + 12);
- var p = start + offset + 16;
- var ranges = [];
- for (var i = 0; i < groups; i++) {
+ p = start + offset + 16;
+ ranges = [];
+ for (i = 0; i < groups; i++) {
ranges.push({
start: getLong(data, p),
end: getLong(data, p + 4),
@@ -23400,13 +21305,13 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
function parseCff(data, start, end) {
var properties = {};
- var parser = new CFFParser(
- new Stream(data, start, end - start), properties);
+ var parser = new CFFParser(new Stream(data, start, end - start),
+ properties);
var cff = parser.parse();
return {
glyphs: cff.charStrings.objects,
- subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
- cff.topDict.privateDict.subrsIndex.objects,
+ subrs: (cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex &&
+ cff.topDict.privateDict.subrsIndex.objects),
gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects
};
}
@@ -23467,16 +21372,13 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
var i = 0;
var numberOfContours = ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
- var xMin = ((code[i + 2] << 24) | (code[i + 3] << 16)) >> 16;
- var yMin = ((code[i + 4] << 24) | (code[i + 5] << 16)) >> 16;
- var xMax = ((code[i + 6] << 24) | (code[i + 7] << 16)) >> 16;
- var yMax = ((code[i + 8] << 24) | (code[i + 9] << 16)) >> 16;
+ var flags;
+ var x = 0, y = 0;
i += 10;
if (numberOfContours < 0) {
// composite glyph
- var x = 0, y = 0;
do {
- var flags = (code[i] << 8) | code[i + 1];
+ flags = (code[i] << 8) | code[i + 1];
var glyphIndex = (code[i + 2] << 8) | code[i + 3];
i += 4;
var arg1, arg2;
@@ -23521,7 +21423,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
} else {
// simple glyph
var endPtsOfContours = [];
- for (var j = 0; j < numberOfContours; j++) {
+ var j, jj;
+ for (j = 0; j < numberOfContours; j++) {
endPtsOfContours.push((code[i] << 8) | code[i + 1]);
i += 2;
}
@@ -23530,7 +21433,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
var numberOfPoints = endPtsOfContours[endPtsOfContours.length - 1] + 1;
var points = [];
while (points.length < numberOfPoints) {
- var flags = code[i++], repeat = 1;
+ flags = code[i++];
+ var repeat = 1;
if ((flags & 0x08)) {
repeat += code[i++];
}
@@ -23538,8 +21442,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
points.push({flags: flags});
}
}
- var x = 0, y = 0;
- for (var j = 0; j < numberOfPoints; j++) {
+ for (j = 0; j < numberOfPoints; j++) {
switch (points[j].flags & 0x12) {
case 0x00:
x += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
@@ -23554,7 +21457,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
points[j].x = x;
}
- for (var j = 0; j < numberOfPoints; j++) {
+ for (j = 0; j < numberOfPoints; j++) {
switch (points[j].flags & 0x24) {
case 0x00:
y += ((code[i] << 24) | (code[i + 1] << 16)) >> 16;
@@ -23571,7 +21474,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
var startPoint = 0;
- for (var i = 0; i < numberOfContours; i++) {
+ for (i = 0; i < numberOfContours; i++) {
var endPoint = endPtsOfContours[i];
// contours might have implicit points, which is located in the middle
// between two neighboring off-curve points
@@ -23592,7 +21495,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
contour.push(p);
}
moveTo(contour[0].x, contour[0].y);
- for (var j = 1, jj = contour.length; j < jj; j++) {
+ for (j = 1, jj = contour.length; j < jj; j++) {
if ((contour[j].flags & 1)) {
lineTo(contour[j].x, contour[j].y);
} else if ((contour[j + 1].flags & 1)){
@@ -23631,6 +21534,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
while (i < code.length) {
var stackClean = false;
var v = code[i++];
+ var xa, xb, ya, yb, y1, y2, y3, n, subrCode;
switch (v) {
case 1: // hstem
stems += stack.length >> 1;
@@ -23676,15 +21580,15 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
case 8: // rrcurveto
while (stack.length > 0) {
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
}
break;
case 10: // callsubr
- var n = stack.pop() + font.subrsBias;
- var subrCode = font.subrs[n];
+ n = stack.pop() + font.subrsBias;
+ subrCode = font.subrs[n];
if (subrCode) {
parse(subrCode);
}
@@ -23695,49 +21599,50 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
v = code[i++];
switch (v) {
case 34: // flex
- var xa = x + stack.shift();
- var xb = xa + stack.shift(), y1 = y + stack.shift();
+ xa = x + stack.shift();
+ xb = xa + stack.shift(); y1 = y + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y, xb, y1, x, y1);
- var xa = x + stack.shift();
- var xb = xa + stack.shift();
+ xa = x + stack.shift();
+ xb = xa + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y1, xb, y, x, y);
break;
case 35: // flex
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
stack.pop(); // fd
break;
case 36: // hflex1
- var xa = x + stack.shift(), y1 = y + stack.shift();
- var xb = xa + stack.shift(), y2 = y1 + stack.shift();
+ xa = x + stack.shift(); y1 = y + stack.shift();
+ xb = xa + stack.shift(); y2 = y1 + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y1, xb, y2, x, y2);
- var xa = x + stack.shift();
- var xb = xa + stack.shift(), y3 = y2 + stack.shift();
+ xa = x + stack.shift();
+ xb = xa + stack.shift(); y3 = y2 + stack.shift();
x = xb + stack.shift();
bezierCurveTo(xa, y2, xb, y3, x, y);
break;
case 37: // flex1
var x0 = x, y0 = y;
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb; y = yb;
- if (Math.abs(x - x0) > Math.abs(y - y0))
+ if (Math.abs(x - x0) > Math.abs(y - y0)) {
x += stack.shift();
- else
+ } else {
y += stack.shift();
+ }
bezierCurveTo(xa, ya, xb, yb, x, y);
break;
default:
@@ -23793,8 +21698,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
case 24: // rcurveline
while (stack.length > 2) {
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
}
@@ -23808,8 +21713,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
y += stack.shift();
lineTo(x, y);
}
- var xa = x + stack.shift(), ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
break;
@@ -23818,8 +21723,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
x += stack.shift();
}
while (stack.length > 0) {
- var xa = x, ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x; ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb; y = yb + stack.shift();
bezierCurveTo(xa, ya, xb, yb, x, y);
}
@@ -23829,8 +21734,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
y += stack.shift();
}
while (stack.length > 0) {
- var xa = x + stack.shift(), ya = y;
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y;
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift(); y = yb;
bezierCurveTo(xa, ya, xb, yb, x, y);
}
@@ -23840,16 +21745,16 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
i += 2;
break;
case 29: // callgsubr
- var n = stack.pop() + font.gsubrsBias;
- var subrCode = font.gsubrs[n];
+ n = stack.pop() + font.gsubrsBias;
+ subrCode = font.gsubrs[n];
if (subrCode) {
parse(subrCode);
}
break;
case 30: // vhcurveto
while (stack.length > 0) {
- var xa = x, ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x; ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift();
y = yb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
@@ -23857,8 +21762,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
}
- var xa = x + stack.shift(), ya = y;
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y;
+ xb = xa + stack.shift(); yb = ya + stack.shift();
y = yb + stack.shift();
x = xb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
@@ -23866,8 +21771,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
case 31: // hvcurveto
while (stack.length > 0) {
- var xa = x + stack.shift(), ya = y;
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x + stack.shift(); ya = y;
+ xb = xa + stack.shift(); yb = ya + stack.shift();
y = yb + stack.shift();
x = xb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
@@ -23875,23 +21780,24 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
break;
}
- var xa = x, ya = y + stack.shift();
- var xb = xa + stack.shift(), yb = ya + stack.shift();
+ xa = x; ya = y + stack.shift();
+ xb = xa + stack.shift(); yb = ya + stack.shift();
x = xb + stack.shift();
y = yb + (stack.length === 1 ? stack.shift() : 0);
bezierCurveTo(xa, ya, xb, yb, x, y);
}
break;
default:
- if (v < 32)
+ if (v < 32) {
error('unknown operator: ' + v);
- if (v < 247)
+ }
+ if (v < 247) {
stack.push(v - 139);
- else if (v < 251)
+ } else if (v < 251) {
stack.push((v - 247) * 256 + code[i++] + 108);
- else if (v < 255)
+ } else if (v < 255) {
stack.push(-(v - 251) * 256 - code[i++] - 108);
- else {
+ } else {
stack.push(((code[i] << 24) | (code[i + 1] << 16) |
(code[i + 2] << 8) | code[i + 3]) / 65536);
i += 4;
@@ -23975,10 +21881,10 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
this.glyphNameMap = glyphNameMap || GlyphsUnicode;
this.compiledGlyphs = [];
- this.gsubrsBias = this.gsubrs.length < 1240 ? 107 :
- this.gsubrs.length < 33900 ? 1131 : 32768;
- this.subrsBias = this.subrs.length < 1240 ? 107 :
- this.subrs.length < 33900 ? 1131 : 32768;
+ this.gsubrsBias = (this.gsubrs.length < 1240 ?
+ 107 : (this.gsubrs.length < 33900 ? 1131 : 32768));
+ this.subrsBias = (this.subrs.length < 1240 ?
+ 107 : (this.subrs.length < 33900 ? 1131 : 32768));
}
Util.inherit(Type2Compiled, CompiledFont, {
@@ -23994,7 +21900,7 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
var cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
var numTables = getUshort(data, 4);
for (var i = 0, p = 12; i < numTables; i++, p += 16) {
- var tag = String.fromCharCode.apply(null, data.subarray(p, p + 4));
+ var tag = bytesToString(data.subarray(p, p + 4));
var offset = getLong(data, p + 8);
var length = getLong(data, p + 12);
switch (tag) {
@@ -24018,8 +21924,8 @@ var FontRendererFactory = (function FontRendererFactoryClosure() {
}
if (glyf) {
- var fontMatrix = !unitsPerEm ? font.fontMatrix :
- [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
+ var fontMatrix = (!unitsPerEm ? font.fontMatrix :
+ [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0]);
return new TrueTypeCompiled(
parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
} else {
@@ -28238,6 +26144,211 @@ var GlyphsUnicode = {
'.notdef': 0x0000
};
+var DingbatsGlyphsUnicode = {
+ space: 0x0020,
+ a1: 0x2701,
+ a2: 0x2702,
+ a202: 0x2703,
+ a3: 0x2704,
+ a4: 0x260E,
+ a5: 0x2706,
+ a119: 0x2707,
+ a118: 0x2708,
+ a117: 0x2709,
+ a11: 0x261B,
+ a12: 0x261E,
+ a13: 0x270C,
+ a14: 0x270D,
+ a15: 0x270E,
+ a16: 0x270F,
+ a105: 0x2710,
+ a17: 0x2711,
+ a18: 0x2712,
+ a19: 0x2713,
+ a20: 0x2714,
+ a21: 0x2715,
+ a22: 0x2716,
+ a23: 0x2717,
+ a24: 0x2718,
+ a25: 0x2719,
+ a26: 0x271A,
+ a27: 0x271B,
+ a28: 0x271C,
+ a6: 0x271D,
+ a7: 0x271E,
+ a8: 0x271F,
+ a9: 0x2720,
+ a10: 0x2721,
+ a29: 0x2722,
+ a30: 0x2723,
+ a31: 0x2724,
+ a32: 0x2725,
+ a33: 0x2726,
+ a34: 0x2727,
+ a35: 0x2605,
+ a36: 0x2729,
+ a37: 0x272A,
+ a38: 0x272B,
+ a39: 0x272C,
+ a40: 0x272D,
+ a41: 0x272E,
+ a42: 0x272F,
+ a43: 0x2730,
+ a44: 0x2731,
+ a45: 0x2732,
+ a46: 0x2733,
+ a47: 0x2734,
+ a48: 0x2735,
+ a49: 0x2736,
+ a50: 0x2737,
+ a51: 0x2738,
+ a52: 0x2739,
+ a53: 0x273A,
+ a54: 0x273B,
+ a55: 0x273C,
+ a56: 0x273D,
+ a57: 0x273E,
+ a58: 0x273F,
+ a59: 0x2740,
+ a60: 0x2741,
+ a61: 0x2742,
+ a62: 0x2743,
+ a63: 0x2744,
+ a64: 0x2745,
+ a65: 0x2746,
+ a66: 0x2747,
+ a67: 0x2748,
+ a68: 0x2749,
+ a69: 0x274A,
+ a70: 0x274B,
+ a71: 0x25CF,
+ a72: 0x274D,
+ a73: 0x25A0,
+ a74: 0x274F,
+ a203: 0x2750,
+ a75: 0x2751,
+ a204: 0x2752,
+ a76: 0x25B2,
+ a77: 0x25BC,
+ a78: 0x25C6,
+ a79: 0x2756,
+ a81: 0x25D7,
+ a82: 0x2758,
+ a83: 0x2759,
+ a84: 0x275A,
+ a97: 0x275B,
+ a98: 0x275C,
+ a99: 0x275D,
+ a100: 0x275E,
+ a101: 0x2761,
+ a102: 0x2762,
+ a103: 0x2763,
+ a104: 0x2764,
+ a106: 0x2765,
+ a107: 0x2766,
+ a108: 0x2767,
+ a112: 0x2663,
+ a111: 0x2666,
+ a110: 0x2665,
+ a109: 0x2660,
+ a120: 0x2460,
+ a121: 0x2461,
+ a122: 0x2462,
+ a123: 0x2463,
+ a124: 0x2464,
+ a125: 0x2465,
+ a126: 0x2466,
+ a127: 0x2467,
+ a128: 0x2468,
+ a129: 0x2469,
+ a130: 0x2776,
+ a131: 0x2777,
+ a132: 0x2778,
+ a133: 0x2779,
+ a134: 0x277A,
+ a135: 0x277B,
+ a136: 0x277C,
+ a137: 0x277D,
+ a138: 0x277E,
+ a139: 0x277F,
+ a140: 0x2780,
+ a141: 0x2781,
+ a142: 0x2782,
+ a143: 0x2783,
+ a144: 0x2784,
+ a145: 0x2785,
+ a146: 0x2786,
+ a147: 0x2787,
+ a148: 0x2788,
+ a149: 0x2789,
+ a150: 0x278A,
+ a151: 0x278B,
+ a152: 0x278C,
+ a153: 0x278D,
+ a154: 0x278E,
+ a155: 0x278F,
+ a156: 0x2790,
+ a157: 0x2791,
+ a158: 0x2792,
+ a159: 0x2793,
+ a160: 0x2794,
+ a161: 0x2192,
+ a163: 0x2194,
+ a164: 0x2195,
+ a196: 0x2798,
+ a165: 0x2799,
+ a192: 0x279A,
+ a166: 0x279B,
+ a167: 0x279C,
+ a168: 0x279D,
+ a169: 0x279E,
+ a170: 0x279F,
+ a171: 0x27A0,
+ a172: 0x27A1,
+ a173: 0x27A2,
+ a162: 0x27A3,
+ a174: 0x27A4,
+ a175: 0x27A5,
+ a176: 0x27A6,
+ a177: 0x27A7,
+ a178: 0x27A8,
+ a179: 0x27A9,
+ a193: 0x27AA,
+ a180: 0x27AB,
+ a199: 0x27AC,
+ a181: 0x27AD,
+ a200: 0x27AE,
+ a182: 0x27AF,
+ a201: 0x27B1,
+ a183: 0x27B2,
+ a184: 0x27B3,
+ a197: 0x27B4,
+ a185: 0x27B5,
+ a194: 0x27B6,
+ a198: 0x27B7,
+ a186: 0x27B8,
+ a195: 0x27B9,
+ a187: 0x27BA,
+ a188: 0x27BB,
+ a189: 0x27BC,
+ a190: 0x27BD,
+ a191: 0x27BE,
+ a89: 0x2768, // 0xF8D7
+ a90: 0x2769, // 0xF8D8
+ a93: 0x276A, // 0xF8D9
+ a94: 0x276B, // 0xF8DA
+ a91: 0x276C, // 0xF8DB
+ a92: 0x276D, // 0xF8DC
+ a205: 0x276E, // 0xF8DD
+ a85: 0x276F, // 0xF8DE
+ a206: 0x2770, // 0xF8DF
+ a86: 0x2771, // 0xF8E0
+ a87: 0x2772, // 0xF8E1
+ a88: 0x2773, // 0xF8E2
+ a95: 0x2774, // 0xF8E3
+ a96: 0x2775, // 0xF8E4
+ '.notdef': 0x0000
+};
var PDFImage = (function PDFImageClosure() {
@@ -28245,22 +26356,24 @@ var PDFImage = (function PDFImageClosure() {
* Decode the image in the main thread if it supported. Resovles the promise
* when the image data is ready.
*/
- function handleImageData(handler, xref, res, image, promise) {
+ function handleImageData(handler, xref, res, image) {
if (image instanceof JpegStream && image.isNativelyDecodable(xref, res)) {
// For natively supported jpegs send them to the main thread for decoding.
var dict = image.dict;
var colorSpace = dict.get('ColorSpace', 'CS');
colorSpace = ColorSpace.parse(colorSpace, xref, res);
var numComps = colorSpace.numComps;
- handler.send('JpegDecode', [image.getIR(), numComps], function(message) {
+ var decodePromise = handler.sendWithPromise('JpegDecode',
+ [image.getIR(), numComps]);
+ return decodePromise.then(function (message) {
var data = message.data;
- var stream = new Stream(data, 0, data.length, image.dict);
- promise.resolve(stream);
+ return new Stream(data, 0, data.length, image.dict);
});
} else {
- promise.resolve(image);
+ return Promise.resolve(image);
}
}
+
/**
* Decode and clamp a value. The formula is different from the spec because we
* don't decode to float range [0,1], we decode it in the [0,max] range.
@@ -28268,26 +26381,34 @@ var PDFImage = (function PDFImageClosure() {
function decodeAndClamp(value, addend, coefficient, max) {
value = addend + value * coefficient;
// Clamp the value to the range
- return value < 0 ? 0 : value > max ? max : value;
+ return (value < 0 ? 0 : (value > max ? max : value));
}
+
function PDFImage(xref, res, image, inline, smask, mask, isMask) {
this.image = image;
- if (image.getParams) {
- // JPX/JPEG2000 streams directly contain bits per component
- // and color space mode information.
- warn('get params from actual stream');
- // var bits = ...
- // var colorspace = ...
+ var dict = image.dict;
+ if (dict.has('Filter')) {
+ var filter = dict.get('Filter').name;
+ if (filter === 'JPXDecode') {
+ var jpxImage = new JpxImage();
+ jpxImage.parseImageProperties(image.stream);
+ image.stream.reset();
+ image.bitsPerComponent = jpxImage.bitsPerComponent;
+ image.numComps = jpxImage.componentsCount;
+ } else if (filter === 'JBIG2Decode') {
+ image.bitsPerComponent = 1;
+ image.numComps = 1;
+ }
}
// TODO cache rendered images?
- var dict = image.dict;
this.width = dict.get('Width', 'W');
this.height = dict.get('Height', 'H');
- if (this.width < 1 || this.height < 1)
+ if (this.width < 1 || this.height < 1) {
error('Invalid image width: ' + this.width + ' or height: ' +
this.height);
+ }
this.interpolate = dict.get('Interpolate', 'I') || false;
this.imageMask = dict.get('ImageMask', 'IM') || false;
@@ -28297,10 +26418,11 @@ var PDFImage = (function PDFImageClosure() {
if (!bitsPerComponent) {
bitsPerComponent = dict.get('BitsPerComponent', 'BPC');
if (!bitsPerComponent) {
- if (this.imageMask)
+ if (this.imageMask) {
bitsPerComponent = 1;
- else
+ } else {
error('Bits per component missing in image: ' + this.imageMask);
+ }
}
}
this.bpc = bitsPerComponent;
@@ -28308,8 +26430,21 @@ var PDFImage = (function PDFImageClosure() {
if (!this.imageMask) {
var colorSpace = dict.get('ColorSpace', 'CS');
if (!colorSpace) {
- warn('JPX images (which don"t require color spaces');
- colorSpace = new Name('DeviceRGB');
+ info('JPX images (which do not require color spaces)');
+ switch (image.numComps) {
+ case 1:
+ colorSpace = Name.get('DeviceGray');
+ break;
+ case 3:
+ colorSpace = Name.get('DeviceRGB');
+ break;
+ case 4:
+ colorSpace = Name.get('DeviceCMYK');
+ break;
+ default:
+ error('JPX images with ' + this.numComps +
+ ' color components not supported.');
+ }
}
this.colorSpace = ColorSpace.parse(colorSpace, xref, res);
this.numComps = this.colorSpace.numComps;
@@ -28345,51 +26480,47 @@ var PDFImage = (function PDFImageClosure() {
}
}
/**
- * Handles processing of image data and calls the callback with an argument
- * of a PDFImage when the image is ready to be used.
+ * Handles processing of image data and returns the Promise that is resolved
+ * with a PDFImage when the image is ready to be used.
*/
- PDFImage.buildImage = function PDFImage_buildImage(callback, handler, xref,
+ PDFImage.buildImage = function PDFImage_buildImage(handler, xref,
res, image, inline) {
- var imageDataPromise = new LegacyPromise();
- var smaskPromise = new LegacyPromise();
- var maskPromise = new LegacyPromise();
- // The image data and smask data may not be ready yet, wait till both are
- // resolved.
- Promise.all([imageDataPromise, smaskPromise, maskPromise]).then(
- function(results) {
- var imageData = results[0], smaskData = results[1], maskData = results[2];
- var image = new PDFImage(xref, res, imageData, inline, smaskData,
- maskData);
- callback(image);
- });
-
- handleImageData(handler, xref, res, image, imageDataPromise);
+ var imagePromise = handleImageData(handler, xref, res, image);
+ var smaskPromise;
+ var maskPromise;
var smask = image.dict.get('SMask');
var mask = image.dict.get('Mask');
if (smask) {
- handleImageData(handler, xref, res, smask, smaskPromise);
- maskPromise.resolve(null);
+ smaskPromise = handleImageData(handler, xref, res, smask);
+ maskPromise = Promise.resolve(null);
} else {
- smaskPromise.resolve(null);
+ smaskPromise = Promise.resolve(null);
if (mask) {
if (isStream(mask)) {
- handleImageData(handler, xref, res, mask, maskPromise);
+ maskPromise = handleImageData(handler, xref, res, mask);
} else if (isArray(mask)) {
- maskPromise.resolve(mask);
+ maskPromise = Promise.resolve(mask);
} else {
warn('Unsupported mask format.');
- maskPromise.resolve(null);
+ maskPromise = Promise.resolve(null);
}
} else {
- maskPromise.resolve(null);
+ maskPromise = Promise.resolve(null);
}
}
+ return Promise.all([imagePromise, smaskPromise, maskPromise]).then(
+ function(results) {
+ var imageData = results[0];
+ var smaskData = results[1];
+ var maskData = results[2];
+ return new PDFImage(xref, res, imageData, inline, smaskData, maskData);
+ });
};
/**
- * Resize an image using the nearest neighbor algorithm. Currently only
+ * Resize an image using the nearest neighbor algorithm. Currently only
* supports one and three component images.
* @param {TypedArray} pixels The original image with one component.
* @param {Number} bpc Number of bits per component.
@@ -28398,141 +26529,194 @@ var PDFImage = (function PDFImageClosure() {
* @param {Number} h1 Original height.
* @param {Number} w2 New width.
* @param {Number} h2 New height.
+ * @param {TypedArray} dest (Optional) The destination buffer.
+ * @param {Number} alpha01 (Optional) Size reserved for the alpha channel.
* @return {TypedArray} Resized image data.
*/
PDFImage.resize = function PDFImage_resize(pixels, bpc, components,
- w1, h1, w2, h2) {
+ w1, h1, w2, h2, dest, alpha01) {
+
+ if (components !== 1 && components !== 3) {
+ error('Unsupported component count for resizing.');
+ }
+
var length = w2 * h2 * components;
- var temp = bpc <= 8 ? new Uint8Array(length) :
- bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
+ var temp = dest ? dest : (bpc <= 8 ? new Uint8Array(length) :
+ (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
var xRatio = w1 / w2;
var yRatio = h1 / h2;
- var px, py, newIndex, oldIndex;
- for (var i = 0; i < h2; i++) {
- for (var j = 0; j < w2; j++) {
- px = Math.floor(j * xRatio);
- py = Math.floor(i * yRatio);
- newIndex = (i * w2) + j;
- oldIndex = ((py * w1) + px);
- if (components === 1) {
- temp[newIndex] = pixels[oldIndex];
- } else if (components === 3) {
- newIndex *= 3;
- oldIndex *= 3;
- temp[newIndex] = pixels[oldIndex];
- temp[newIndex + 1] = pixels[oldIndex + 1];
- temp[newIndex + 2] = pixels[oldIndex + 2];
+ var i, j, py, newIndex = 0, oldIndex;
+ var xScaled = new Uint16Array(w2);
+ var w1Scanline = w1 * components;
+ if (alpha01 !== 1) {
+ alpha01 = 0;
+ }
+
+ for (j = 0; j < w2; j++) {
+ xScaled[j] = Math.floor(j * xRatio) * components;
+ }
+
+ if (components === 1) {
+ for (i = 0; i < h2; i++) {
+ py = Math.floor(i * yRatio) * w1Scanline;
+ for (j = 0; j < w2; j++) {
+ oldIndex = py + xScaled[j];
+ temp[newIndex++] = pixels[oldIndex];
+ }
+ }
+ } else if (components === 3) {
+ for (i = 0; i < h2; i++) {
+ py = Math.floor(i * yRatio) * w1Scanline;
+ for (j = 0; j < w2; j++) {
+ oldIndex = py + xScaled[j];
+ temp[newIndex++] = pixels[oldIndex++];
+ temp[newIndex++] = pixels[oldIndex++];
+ temp[newIndex++] = pixels[oldIndex++];
+ newIndex += alpha01;
}
}
}
return temp;
};
- PDFImage.createMask = function PDFImage_createMask(imgArray, width, height,
- inverseDecode) {
- var buffer = new Uint8Array(width * height * 4);
- var imgArrayPos = 0;
- var i, j, mask, buf;
- // removing making non-masked pixels transparent
- var bufferPos = 3; // alpha component offset
- for (i = 0; i < height; i++) {
- mask = 0;
- for (j = 0; j < width; j++) {
- if (!mask) {
- buf = imgArray[imgArrayPos++];
- mask = 128;
- }
- if (!(buf & mask) !== inverseDecode) {
- buffer[bufferPos] = 255;
- }
- bufferPos += 4;
- mask >>= 1;
+ PDFImage.createMask =
+ function PDFImage_createMask(imgArray, width, height,
+ imageIsFromDecodeStream, inverseDecode) {
+
+ // |imgArray| might not contain full data for every pixel of the mask, so
+ // we need to distinguish between |computedLength| and |actualLength|.
+ // In particular, if inverseDecode is true, then the array we return must
+ // have a length of |computedLength|.
+
+ var computedLength = ((width + 7) >> 3) * height;
+ var actualLength = imgArray.byteLength;
+ var haveFullData = computedLength === actualLength;
+ var data, i;
+
+ if (imageIsFromDecodeStream && (!inverseDecode || haveFullData)) {
+ // imgArray came from a DecodeStream and its data is in an appropriate
+ // form, so we can just transfer it.
+ data = imgArray;
+ } else if (!inverseDecode) {
+ data = new Uint8Array(actualLength);
+ data.set(imgArray);
+ } else {
+ data = new Uint8Array(computedLength);
+ data.set(imgArray);
+ for (i = actualLength; i < computedLength; i++) {
+ data[i] = 0xff;
}
}
- return {data: buffer, width: width, height: height};
+
+ // If necessary, invert the original mask data (but not any extra we might
+ // have added above). It's safe to modify the array -- whether it's the
+ // original or a copy, we're about to transfer it anyway, so nothing else
+ // in this thread can be relying on its contents.
+ if (inverseDecode) {
+ for (i = 0; i < actualLength; i++) {
+ data[i] = ~data[i];
+ }
+ }
+
+ return {data: data, width: width, height: height};
};
PDFImage.prototype = {
get drawWidth() {
- if (!this.smask)
- return this.width;
- return Math.max(this.width, this.smask.width);
+ return Math.max(this.width,
+ this.smask && this.smask.width || 0,
+ this.mask && this.mask.width || 0);
},
+
get drawHeight() {
- if (!this.smask)
- return this.height;
- return Math.max(this.height, this.smask.height);
+ return Math.max(this.height,
+ this.smask && this.smask.height || 0,
+ this.mask && this.mask.height || 0);
},
+
decodeBuffer: function PDFImage_decodeBuffer(buffer) {
var bpc = this.bpc;
- var decodeMap = this.decode;
var numComps = this.numComps;
- var decodeAddends, decodeCoefficients;
var decodeAddends = this.decodeAddends;
var decodeCoefficients = this.decodeCoefficients;
var max = (1 << bpc) - 1;
+ var i, ii;
if (bpc === 1) {
// If the buffer needed decode that means it just needs to be inverted.
- for (var i = 0, ii = buffer.length; i < ii; i++) {
+ for (i = 0, ii = buffer.length; i < ii; i++) {
buffer[i] = +!(buffer[i]);
}
return;
}
var index = 0;
- for (var i = 0, ii = this.width * this.height; i < ii; i++) {
+ for (i = 0, ii = this.width * this.height; i < ii; i++) {
for (var j = 0; j < numComps; j++) {
buffer[index] = decodeAndClamp(buffer[index], decodeAddends[j],
- decodeCoefficients[j], max);
+ decodeCoefficients[j], max);
index++;
}
}
},
+
getComponents: function PDFImage_getComponents(buffer) {
var bpc = this.bpc;
// This image doesn't require any extra work.
- if (bpc === 8)
+ if (bpc === 8) {
return buffer;
+ }
- var bufferLength = buffer.length;
var width = this.width;
var height = this.height;
var numComps = this.numComps;
var length = width * height * numComps;
var bufferPos = 0;
- var output = bpc <= 8 ? new Uint8Array(length) :
- bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length);
+ var output = (bpc <= 8 ? new Uint8Array(length) :
+ (bpc <= 16 ? new Uint16Array(length) : new Uint32Array(length)));
var rowComps = width * numComps;
var max = (1 << bpc) - 1;
+ var i = 0, ii, buf;
if (bpc === 1) {
// Optimization for reading 1 bpc images.
- var mask = 0;
- var buf = 0;
+ var mask, loop1End, loop2End;
+ for (var j = 0; j < height; j++) {
+ loop1End = i + (rowComps & ~7);
+ loop2End = i + rowComps;
- for (var i = 0, ii = length; i < ii; ++i) {
- if (i % rowComps === 0) {
- mask = 0;
- buf = 0;
- } else {
- mask >>= 1;
+ // unroll loop for all full bytes
+ while (i < loop1End) {
+ buf = buffer[bufferPos++];
+ output[i] = (buf >> 7) & 1;
+ output[i + 1] = (buf >> 6) & 1;
+ output[i + 2] = (buf >> 5) & 1;
+ output[i + 3] = (buf >> 4) & 1;
+ output[i + 4] = (buf >> 3) & 1;
+ output[i + 5] = (buf >> 2) & 1;
+ output[i + 6] = (buf >> 1) & 1;
+ output[i + 7] = buf & 1;
+ i += 8;
}
- if (mask <= 0) {
+ // handle remaing bits
+ if (i < loop2End) {
buf = buffer[bufferPos++];
mask = 128;
+ while (i < loop2End) {
+ output[i++] = +!!(buf & mask);
+ mask >>= 1;
+ }
}
-
- output[i] = +!!(buf & mask);
}
} else {
// The general case that handles all other bpc values.
- var bits = 0, buf = 0;
- for (var i = 0, ii = length; i < ii; ++i) {
+ var bits = 0;
+ buf = 0;
+ for (i = 0, ii = length; i < ii; ++i) {
if (i % rowComps === 0) {
buf = 0;
bits = 0;
@@ -28545,50 +26729,55 @@ var PDFImage = (function PDFImageClosure() {
var remainingBits = bits - bpc;
var value = buf >> remainingBits;
- output[i] = value < 0 ? 0 : value > max ? max : value;
+ output[i] = (value < 0 ? 0 : (value > max ? max : value));
buf = buf & ((1 << remainingBits) - 1);
bits = remainingBits;
}
}
return output;
},
- getOpacity: function PDFImage_getOpacity(width, height, image) {
+
+ fillOpacity: function PDFImage_fillOpacity(rgbaBuf, width, height,
+ actualHeight, image) {
var smask = this.smask;
var mask = this.mask;
- var originalWidth = this.width;
- var originalHeight = this.height;
- var buf;
+ var alphaBuf, sw, sh, i, ii, j;
if (smask) {
- var sw = smask.width;
- var sh = smask.height;
- buf = new Uint8Array(sw * sh);
- smask.fillGrayBuffer(buf);
- if (sw != width || sh != height)
- buf = PDFImage.resize(buf, smask.bpc, 1, sw, sh, width, height);
+ sw = smask.width;
+ sh = smask.height;
+ alphaBuf = new Uint8Array(sw * sh);
+ smask.fillGrayBuffer(alphaBuf);
+ if (sw !== width || sh !== height) {
+ alphaBuf = PDFImage.resize(alphaBuf, smask.bpc, 1, sw, sh, width,
+ height);
+ }
} else if (mask) {
if (mask instanceof PDFImage) {
- var sw = mask.width;
- var sh = mask.height;
- buf = new Uint8Array(sw * sh);
+ sw = mask.width;
+ sh = mask.height;
+ alphaBuf = new Uint8Array(sw * sh);
mask.numComps = 1;
- mask.fillGrayBuffer(buf);
+ mask.fillGrayBuffer(alphaBuf);
- // Need to invert values in buffer
- for (var i = 0, ii = sw * sh; i < ii; ++i)
- buf[i] = 255 - buf[i];
+ // Need to invert values in rgbaBuf
+ for (i = 0, ii = sw * sh; i < ii; ++i) {
+ alphaBuf[i] = 255 - alphaBuf[i];
+ }
- if (sw != width || sh != height)
- buf = PDFImage.resize(buf, mask.bpc, 1, sw, sh, width, height);
+ if (sw !== width || sh !== height) {
+ alphaBuf = PDFImage.resize(alphaBuf, mask.bpc, 1, sw, sh, width,
+ height);
+ }
} else if (isArray(mask)) {
// Color key mask: if any of the compontents are outside the range
// then they should be painted.
- buf = new Uint8Array(width * height);
+ alphaBuf = new Uint8Array(width * height);
var numComps = this.numComps;
- for (var i = 0, ii = width * height; i < ii; ++i) {
+ for (i = 0, ii = width * height; i < ii; ++i) {
var opacity = 0;
var imageOffset = i * numComps;
- for (var j = 0; j < numComps; ++j) {
+ for (j = 0; j < numComps; ++j) {
var color = image[imageOffset + j];
var maskOffset = j * 2;
if (color < mask[maskOffset] || color > mask[maskOffset + 1]) {
@@ -28596,122 +26785,214 @@ var PDFImage = (function PDFImageClosure() {
break;
}
}
- buf[i] = opacity;
+ alphaBuf[i] = opacity;
}
} else {
error('Unknown mask format.');
}
- } else {
- buf = new Uint8Array(width * height);
- for (var i = 0, ii = width * height; i < ii; ++i)
- buf[i] = 255;
}
- return buf;
+
+ if (alphaBuf) {
+ for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
+ rgbaBuf[j] = alphaBuf[i];
+ }
+ } else {
+ // No mask.
+ for (i = 0, j = 3, ii = width * actualHeight; i < ii; ++i, j += 4) {
+ rgbaBuf[j] = 255;
+ }
+ }
},
+
undoPreblend: function PDFImage_undoPreblend(buffer, width, height) {
var matte = this.smask && this.smask.matte;
if (!matte) {
return;
}
-
- function clamp(value) {
- return (value < 0 ? 0 : value > 255 ? 255 : value) | 0;
- }
-
var matteRgb = this.colorSpace.getRgb(matte, 0);
+ var matteR = matteRgb[0];
+ var matteG = matteRgb[1];
+ var matteB = matteRgb[2];
var length = width * height * 4;
+ var r, g, b;
for (var i = 0; i < length; i += 4) {
var alpha = buffer[i + 3];
if (alpha === 0) {
// according formula we have to get Infinity in all components
- // making it as white (tipical paper color) should be okay
+ // making it white (typical paper color) should be okay
buffer[i] = 255;
buffer[i + 1] = 255;
buffer[i + 2] = 255;
continue;
}
var k = 255 / alpha;
- buffer[i] = clamp((buffer[i] - matteRgb[0]) * k + matteRgb[0]);
- buffer[i + 1] = clamp((buffer[i + 1] - matteRgb[1]) * k + matteRgb[1]);
- buffer[i + 2] = clamp((buffer[i + 2] - matteRgb[2]) * k + matteRgb[2]);
+ r = (buffer[i] - matteR) * k + matteR;
+ g = (buffer[i + 1] - matteG) * k + matteG;
+ b = (buffer[i + 2] - matteB) * k + matteB;
+ buffer[i] = r <= 0 ? 0 : r >= 255 ? 255 : r | 0;
+ buffer[i + 1] = g <= 0 ? 0 : g >= 255 ? 255 : g | 0;
+ buffer[i + 2] = b <= 0 ? 0 : b >= 255 ? 255 : b | 0;
}
},
- fillRgbaBuffer: function PDFImage_fillRgbaBuffer(buffer, width, height) {
+
+ createImageData: function PDFImage_createImageData(forceRGBA) {
+ var drawWidth = this.drawWidth;
+ var drawHeight = this.drawHeight;
+ var imgData = { // other fields are filled in below
+ width: drawWidth,
+ height: drawHeight
+ };
+
var numComps = this.numComps;
var originalWidth = this.width;
var originalHeight = this.height;
var bpc = this.bpc;
- // rows start at byte boundary;
+ // Rows start at byte boundary.
var rowBytes = (originalWidth * numComps * bpc + 7) >> 3;
- var imgArray = this.getImageBytes(originalHeight * rowBytes);
+ var imgArray;
- // imgArray can be incomplete (e.g. after CCITT fax encoding)
+ if (!forceRGBA) {
+ // If it is a 1-bit-per-pixel grayscale (i.e. black-and-white) image
+ // without any complications, we pass a same-sized copy to the main
+ // thread rather than expanding by 32x to RGBA form. This saves *lots*
+ // of memory for many scanned documents. It's also much faster.
+ //
+ // Similarly, if it is a 24-bit-per pixel RGB image without any
+ // complications, we avoid expanding by 1.333x to RGBA form.
+ var kind;
+ if (this.colorSpace.name === 'DeviceGray' && bpc === 1) {
+ kind = ImageKind.GRAYSCALE_1BPP;
+ } else if (this.colorSpace.name === 'DeviceRGB' && bpc === 8 &&
+ !this.needsDecode) {
+ kind = ImageKind.RGB_24BPP;
+ }
+ if (kind && !this.smask && !this.mask &&
+ drawWidth === originalWidth && drawHeight === originalHeight) {
+ imgData.kind = kind;
+
+ imgArray = this.getImageBytes(originalHeight * rowBytes);
+ // If imgArray came from a DecodeStream, we're safe to transfer it
+ // (and thus neuter it) because it will constitute the entire
+ // DecodeStream's data. But if it came from a Stream, we need to
+ // copy it because it'll only be a portion of the Stream's data, and
+ // the rest will be read later on.
+ if (this.image instanceof DecodeStream) {
+ imgData.data = imgArray;
+ } else {
+ var newArray = new Uint8Array(imgArray.length);
+ newArray.set(imgArray);
+ imgData.data = newArray;
+ }
+ if (this.needsDecode) {
+ // Invert the buffer (which must be grayscale if we reached here).
+ assert(kind === ImageKind.GRAYSCALE_1BPP);
+ var buffer = imgData.data;
+ for (var i = 0, ii = buffer.length; i < ii; i++) {
+ buffer[i] ^= 0xff;
+ }
+ }
+ return imgData;
+ }
+ if (this.image instanceof JpegStream && !this.smask && !this.mask) {
+ imgData.kind = ImageKind.RGB_24BPP;
+ imgData.data = this.getImageBytes(originalHeight * rowBytes,
+ drawWidth, drawHeight, true);
+ return imgData;
+ }
+ }
+
+ imgArray = this.getImageBytes(originalHeight * rowBytes);
+ // imgArray can be incomplete (e.g. after CCITT fax encoding).
var actualHeight = 0 | (imgArray.length / rowBytes *
- height / originalHeight);
+ drawHeight / originalHeight);
+
var comps = this.getComponents(imgArray);
- // Build opacity here since color key masking needs to be perormed on
- // undecoded values.
- var opacity = this.getOpacity(width, height, comps);
+
+ // If opacity data is present, use RGBA_32BPP form. Otherwise, use the
+ // more compact RGB_24BPP form if allowable.
+ var alpha01, maybeUndoPreblend;
+ if (!forceRGBA && !this.smask && !this.mask) {
+ imgData.kind = ImageKind.RGB_24BPP;
+ imgData.data = new Uint8Array(drawWidth * drawHeight * 3);
+ alpha01 = 0;
+ maybeUndoPreblend = false;
+ } else {
+ imgData.kind = ImageKind.RGBA_32BPP;
+ imgData.data = new Uint8Array(drawWidth * drawHeight * 4);
+ alpha01 = 1;
+ maybeUndoPreblend = true;
+
+ // Color key masking (opacity) must be performed before decoding.
+ this.fillOpacity(imgData.data, drawWidth, drawHeight, actualHeight,
+ comps);
+ }
if (this.needsDecode) {
this.decodeBuffer(comps);
}
- var rgbBuf = this.colorSpace.createRgbBuffer(comps, 0,
- originalWidth * originalHeight, bpc);
- if (originalWidth != width || originalHeight != height)
- rgbBuf = PDFImage.resize(rgbBuf, this.bpc, 3, originalWidth,
- originalHeight, width, height);
- var compsPos = 0;
- var opacityPos = 0;
- var length = width * actualHeight * 4;
-
- for (var i = 0; i < length; i += 4) {
- buffer[i] = rgbBuf[compsPos++];
- buffer[i + 1] = rgbBuf[compsPos++];
- buffer[i + 2] = rgbBuf[compsPos++];
- buffer[i + 3] = opacity[opacityPos++];
+ this.colorSpace.fillRgb(imgData.data, originalWidth, originalHeight,
+ drawWidth, drawHeight, actualHeight, bpc, comps,
+ alpha01);
+ if (maybeUndoPreblend) {
+ this.undoPreblend(imgData.data, drawWidth, actualHeight);
}
- this.undoPreblend(buffer, width, actualHeight);
+ return imgData;
},
+
fillGrayBuffer: function PDFImage_fillGrayBuffer(buffer) {
var numComps = this.numComps;
- if (numComps != 1)
+ if (numComps !== 1) {
error('Reading gray scale from a color image: ' + numComps);
+ }
var width = this.width;
var height = this.height;
var bpc = this.bpc;
- // rows start at byte boundary;
+ // rows start at byte boundary
var rowBytes = (width * numComps * bpc + 7) >> 3;
var imgArray = this.getImageBytes(height * rowBytes);
var comps = this.getComponents(imgArray);
+ var i, length;
+
+ if (bpc === 1) {
+ // inline decoding (= inversion) for 1 bpc images
+ length = width * height;
+ if (this.needsDecode) {
+ // invert and scale to {0, 255}
+ for (i = 0; i < length; ++i) {
+ buffer[i] = (comps[i] - 1) & 255;
+ }
+ } else {
+ // scale to {0, 255}
+ for (i = 0; i < length; ++i) {
+ buffer[i] = (-comps[i]) & 255;
+ }
+ }
+ return;
+ }
+
if (this.needsDecode) {
this.decodeBuffer(comps);
}
- var length = width * height;
+ length = width * height;
// we aren't using a colorspace so we need to scale the value
var scale = 255 / ((1 << bpc) - 1);
- for (var i = 0; i < length; ++i)
+ for (i = 0; i < length; ++i) {
buffer[i] = (scale * comps[i]) | 0;
+ }
},
- getImageData: function PDFImage_getImageData() {
- var drawWidth = this.drawWidth;
- var drawHeight = this.drawHeight;
- var imgData = {
- width: drawWidth,
- height: drawHeight,
- data: new Uint8Array(drawWidth * drawHeight * 4)
- };
- var pixels = imgData.data;
- this.fillRgbaBuffer(pixels, drawWidth, drawHeight);
- return imgData;
- },
- getImageBytes: function PDFImage_getImageBytes(length) {
+
+ getImageBytes: function PDFImage_getImageBytes(length,
+ drawWidth, drawHeight,
+ forceRGB) {
this.image.reset();
+ this.image.drawWidth = drawWidth || this.width;
+ this.image.drawHeight = drawHeight || this.height;
+ this.image.forceRGB = !!forceRGB;
return this.image.getBytes(length);
}
};
@@ -31666,7 +29947,7 @@ var Metrics = {
var EOF = {};
function isEOF(v) {
- return v == EOF;
+ return (v === EOF);
}
var Parser = (function ParserClosure() {
@@ -31674,25 +29955,15 @@ var Parser = (function ParserClosure() {
this.lexer = lexer;
this.allowStreams = allowStreams;
this.xref = xref;
+ this.imageCache = {
+ length: 0,
+ adler32: 0,
+ stream: null
+ };
this.refill();
}
Parser.prototype = {
- saveState: function Parser_saveState() {
- this.state = {
- buf1: this.buf1,
- buf2: this.buf2,
- streamPos: this.lexer.stream.pos
- };
- },
-
- restoreState: function Parser_restoreState() {
- var state = this.state;
- this.buf1 = state.buf1;
- this.buf2 = state.buf2;
- this.lexer.stream.pos = state.streamPos;
- },
-
refill: function Parser_refill() {
this.buf1 = this.lexer.getObj();
this.buf2 = this.lexer.getObj();
@@ -31707,51 +29978,58 @@ var Parser = (function ParserClosure() {
}
},
getObj: function Parser_getObj(cipherTransform) {
- if (isCmd(this.buf1, 'BI')) { // inline image
- this.shift();
- return this.makeInlineImage(cipherTransform);
- }
- if (isCmd(this.buf1, '[')) { // array
- this.shift();
- var array = [];
- while (!isCmd(this.buf1, ']') && !isEOF(this.buf1))
- array.push(this.getObj(cipherTransform));
- if (isEOF(this.buf1))
- error('End of file inside array');
- this.shift();
- return array;
- }
- if (isCmd(this.buf1, '<<')) { // dictionary or stream
- this.shift();
- var dict = new Dict(this.xref);
- while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
- if (!isName(this.buf1)) {
- info('Malformed dictionary, key must be a name object');
+ var buf1 = this.buf1;
+ this.shift();
+
+ if (buf1 instanceof Cmd) {
+ switch (buf1.cmd) {
+ case 'BI': // inline image
+ return this.makeInlineImage(cipherTransform);
+ case '[': // array
+ var array = [];
+ while (!isCmd(this.buf1, ']') && !isEOF(this.buf1)) {
+ array.push(this.getObj(cipherTransform));
+ }
+ if (isEOF(this.buf1)) {
+ error('End of file inside array');
+ }
this.shift();
- continue;
- }
+ return array;
+ case '<<': // dictionary or stream
+ var dict = new Dict(this.xref);
+ while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
+ if (!isName(this.buf1)) {
+ info('Malformed dictionary: key must be a name object');
+ this.shift();
+ continue;
+ }
- var key = this.buf1.name;
- this.shift();
- if (isEOF(this.buf1))
- break;
- dict.set(key, this.getObj(cipherTransform));
- }
- if (isEOF(this.buf1))
- error('End of file inside dictionary');
+ var key = this.buf1.name;
+ this.shift();
+ if (isEOF(this.buf1)) {
+ break;
+ }
+ dict.set(key, this.getObj(cipherTransform));
+ }
+ if (isEOF(this.buf1)) {
+ error('End of file inside dictionary');
+ }
- // stream objects are not allowed inside content streams or
- // object streams
- if (isCmd(this.buf2, 'stream')) {
- return this.allowStreams ?
- this.makeStream(dict, cipherTransform) : dict;
+ // Stream objects are not allowed inside content streams or
+ // object streams.
+ if (isCmd(this.buf2, 'stream')) {
+ return (this.allowStreams ?
+ this.makeStream(dict, cipherTransform) : dict);
+ }
+ this.shift();
+ return dict;
+ default: // simple object
+ return buf1;
}
- this.shift();
- return dict;
}
- if (isInt(this.buf1)) { // indirect reference or integer
- var num = this.buf1;
- this.shift();
+
+ if (isInt(buf1)) { // indirect reference or integer
+ var num = buf1;
if (isInt(this.buf1) && isCmd(this.buf2, 'R')) {
var ref = new Ref(num, this.buf1);
this.shift();
@@ -31760,33 +30038,34 @@ var Parser = (function ParserClosure() {
}
return num;
}
- if (isString(this.buf1)) { // string
- var str = this.buf1;
- this.shift();
- if (cipherTransform)
+
+ if (isString(buf1)) { // string
+ var str = buf1;
+ if (cipherTransform) {
str = cipherTransform.decryptString(str);
+ }
return str;
}
// simple object
- var obj = this.buf1;
- this.shift();
- return obj;
+ return buf1;
},
makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
var lexer = this.lexer;
var stream = lexer.stream;
// parse dictionary
- var dict = new Dict();
+ var dict = new Dict(null);
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
- if (!isName(this.buf1))
+ if (!isName(this.buf1)) {
error('Dictionary key must be a name object');
+ }
var key = this.buf1.name;
this.shift();
- if (isEOF(this.buf1))
+ if (isEOF(this.buf1)) {
break;
+ }
dict.set(key, this.getObj(cipherTransform));
}
@@ -31795,41 +30074,80 @@ var Parser = (function ParserClosure() {
// searching for the /EI\s/
var state = 0, ch, i, ii;
- while (state != 4 && (ch = stream.getByte()) !== -1) {
- switch (ch | 0) {
- case 0x20:
- case 0x0D:
- case 0x0A:
- // let's check next five bytes to be ASCII... just be sure
- var followingBytes = stream.peekBytes(5);
- for (i = 0, ii = followingBytes.length; i < ii; i++) {
+ var E = 0x45, I = 0x49, SPACE = 0x20, NL = 0xA, CR = 0xD;
+ while ((ch = stream.getByte()) !== -1) {
+ if (state === 0) {
+ state = (ch === E) ? 1 : 0;
+ } else if (state === 1) {
+ state = (ch === I) ? 2 : 0;
+ } else {
+ assert(state === 2);
+ if (ch === SPACE || ch === NL || ch === CR) {
+ // Let's check the next five bytes are ASCII... just be sure.
+ var n = 5;
+ var followingBytes = stream.peekBytes(n);
+ for (i = 0; i < n; i++) {
ch = followingBytes[i];
- if (ch !== 0x0A && ch !== 0x0D && (ch < 0x20 || ch > 0x7F)) {
- // not a LF, CR, SPACE or any visible ASCII character
+ if (ch !== NL && ch !== CR && (ch < SPACE || ch > 0x7F)) {
+ // Not a LF, CR, SPACE or any visible ASCII character, i.e.
+ // it's binary stuff. Resetting the state.
state = 0;
- break; // some binary stuff found, resetting the state
+ break;
}
}
- state = state === 3 ? 4 : 0;
- break;
- case 0x45:
- state = 2;
- break;
- case 0x49:
- state = state === 2 ? 3 : 0;
- break;
- default:
+ if (state === 2) {
+ break; // finished!
+ }
+ } else {
state = 0;
- break;
+ }
}
}
var length = (stream.pos - 4) - startPos;
var imageStream = stream.makeSubStream(startPos, length, dict);
- if (cipherTransform)
- imageStream = cipherTransform.createStream(imageStream);
+
+ // trying to cache repeat images, first we are trying to "warm up" caching
+ // using length, then comparing adler32
+ var MAX_LENGTH_TO_CACHE = 1000;
+ var cacheImage = false, adler32;
+ if (length < MAX_LENGTH_TO_CACHE && this.imageCache.length === length) {
+ var imageBytes = imageStream.getBytes();
+ imageStream.reset();
+
+ var a = 1;
+ var b = 0;
+ for (i = 0, ii = imageBytes.length; i < ii; ++i) {
+ a = (a + (imageBytes[i] & 0xff)) % 65521;
+ b = (b + a) % 65521;
+ }
+ adler32 = (b << 16) | a;
+
+ if (this.imageCache.stream && this.imageCache.adler32 === adler32) {
+ this.buf2 = Cmd.get('EI');
+ this.shift();
+
+ this.imageCache.stream.reset();
+ return this.imageCache.stream;
+ }
+ cacheImage = true;
+ }
+ if (!cacheImage && !this.imageCache.stream) {
+ this.imageCache.length = length;
+ this.imageCache.stream = null;
+ }
+
+ if (cipherTransform) {
+ imageStream = cipherTransform.createStream(imageStream, length);
+ }
+
imageStream = this.filter(imageStream, dict, length);
imageStream.dict = dict;
+ if (cacheImage) {
+ imageStream.cacheKey = 'inline_' + length + '_' + adler32;
+ this.imageCache.adler32 = adler32;
+ this.imageCache.stream = imageStream;
+ }
this.buf2 = Cmd.get('EI');
this.shift();
@@ -31838,7 +30156,7 @@ var Parser = (function ParserClosure() {
},
fetchIfRef: function Parser_fetchIfRef(obj) {
// not relying on the xref.fetchIfRef -- xref might not be set
- return isRef(obj) ? this.xref.fetch(obj) : obj;
+ return (isRef(obj) ? this.xref.fetch(obj) : obj);
},
makeStream: function Parser_makeStream(dict, cipherTransform) {
var lexer = this.lexer;
@@ -31868,11 +30186,14 @@ var Parser = (function ParserClosure() {
var ENDSTREAM_SIGNATURE_LENGTH = 9;
var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65,
0x61, 0x6D];
- var skipped = 0, found = false;
+ var skipped = 0, found = false, i, j;
while (stream.pos < stream.end) {
var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
- var found = false, i, ii, j;
+ if (scanLength <= 0) {
+ break;
+ }
+ found = false;
for (i = 0, j = 0; i < scanLength; i++) {
var b = scanBytes[i];
if (b !== ENDSTREAM_SIGNATURE[j]) {
@@ -31881,6 +30202,7 @@ var Parser = (function ParserClosure() {
} else {
j++;
if (j >= ENDSTREAM_SIGNATURE_LENGTH) {
+ i++;
found = true;
break;
}
@@ -31906,8 +30228,9 @@ var Parser = (function ParserClosure() {
this.shift(); // 'endstream'
stream = stream.makeSubStream(pos, length, dict);
- if (cipherTransform)
- stream = cipherTransform.createStream(stream);
+ if (cipherTransform) {
+ stream = cipherTransform.createStream(stream, length);
+ }
stream = this.filter(stream, dict, length);
stream.dict = dict;
return stream;
@@ -31915,72 +30238,114 @@ var Parser = (function ParserClosure() {
filter: function Parser_filter(stream, dict, length) {
var filter = this.fetchIfRef(dict.get('Filter', 'F'));
var params = this.fetchIfRef(dict.get('DecodeParms', 'DP'));
- if (isName(filter))
+ if (isName(filter)) {
return this.makeFilter(stream, filter.name, length, params);
+ }
+
+ var maybeLength = length;
if (isArray(filter)) {
var filterArray = filter;
var paramsArray = params;
for (var i = 0, ii = filterArray.length; i < ii; ++i) {
filter = filterArray[i];
- if (!isName(filter))
+ if (!isName(filter)) {
error('Bad filter name: ' + filter);
+ }
params = null;
- if (isArray(paramsArray) && (i in paramsArray))
+ if (isArray(paramsArray) && (i in paramsArray)) {
params = paramsArray[i];
- stream = this.makeFilter(stream, filter.name, length, params);
+ }
+ stream = this.makeFilter(stream, filter.name, maybeLength, params);
// after the first stream the length variable is invalid
- length = null;
+ maybeLength = null;
}
}
return stream;
},
- makeFilter: function Parser_makeFilter(stream, name, length, params) {
+ makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) {
if (stream.dict.get('Length') === 0) {
return new NullStream(stream);
}
- if (name == 'FlateDecode' || name == 'Fl') {
+ try {
if (params) {
- return new PredictorStream(new FlateStream(stream), params);
+ params = this.fetchIfRef(params);
}
- return new FlateStream(stream);
- }
- if (name == 'LZWDecode' || name == 'LZW') {
- var earlyChange = 1;
- if (params) {
- if (params.has('EarlyChange'))
- earlyChange = params.get('EarlyChange');
- return new PredictorStream(
- new LZWStream(stream, earlyChange), params);
+ var xrefStreamStats = this.xref.stats.streamTypes;
+ if (name === 'FlateDecode' || name === 'Fl') {
+ xrefStreamStats[StreamType.FLATE] = true;
+ if (params) {
+ return new PredictorStream(new FlateStream(stream, maybeLength),
+ maybeLength, params);
+ }
+ return new FlateStream(stream, maybeLength);
}
- return new LZWStream(stream, earlyChange);
+ if (name === 'LZWDecode' || name === 'LZW') {
+ xrefStreamStats[StreamType.LZW] = true;
+ var earlyChange = 1;
+ if (params) {
+ if (params.has('EarlyChange')) {
+ earlyChange = params.get('EarlyChange');
+ }
+ return new PredictorStream(
+ new LZWStream(stream, maybeLength, earlyChange),
+ maybeLength, params);
+ }
+ return new LZWStream(stream, maybeLength, earlyChange);
+ }
+ if (name === 'DCTDecode' || name === 'DCT') {
+ // According to the specification: for inline images, the ID operator
+ // shall be followed by a single whitespace character (unless it uses
+ // ASCII85Decode or ASCIIHexDecode filters).
+ // In practice this only seems to be followed for inline JPEG images,
+ // and generally ignoring the first byte of the stream if it is a
+ // whitespace char can even *cause* issues (e.g. in the CCITTFaxDecode
+ // filters used in issue2984.pdf).
+ // Hence when the first byte of the stream of an inline JPEG image is
+ // a whitespace character, we thus simply skip over it.
+ if (isCmd(this.buf1, 'ID')) {
+ var firstByte = stream.peekByte();
+ if (firstByte === 0x0A /* LF */ || firstByte === 0x0D /* CR */ ||
+ firstByte === 0x20 /* SPACE */) {
+ stream.skip();
+ }
+ }
+ xrefStreamStats[StreamType.DCT] = true;
+ return new JpegStream(stream, maybeLength, stream.dict, this.xref);
+ }
+ if (name === 'JPXDecode' || name === 'JPX') {
+ xrefStreamStats[StreamType.JPX] = true;
+ return new JpxStream(stream, maybeLength, stream.dict);
+ }
+ if (name === 'ASCII85Decode' || name === 'A85') {
+ xrefStreamStats[StreamType.A85] = true;
+ return new Ascii85Stream(stream, maybeLength);
+ }
+ if (name === 'ASCIIHexDecode' || name === 'AHx') {
+ xrefStreamStats[StreamType.AHX] = true;
+ return new AsciiHexStream(stream, maybeLength);
+ }
+ if (name === 'CCITTFaxDecode' || name === 'CCF') {
+ xrefStreamStats[StreamType.CCF] = true;
+ return new CCITTFaxStream(stream, maybeLength, params);
+ }
+ if (name === 'RunLengthDecode' || name === 'RL') {
+ xrefStreamStats[StreamType.RL] = true;
+ return new RunLengthStream(stream, maybeLength);
+ }
+ if (name === 'JBIG2Decode') {
+ xrefStreamStats[StreamType.JBIG] = true;
+ return new Jbig2Stream(stream, maybeLength, stream.dict);
+ }
+ warn('filter "' + name + '" not supported yet');
+ return stream;
+ } catch (ex) {
+ if (ex instanceof MissingDataException) {
+ throw ex;
+ }
+ warn('Invalid stream: \"' + ex + '\"');
+ return new NullStream(stream);
}
- if (name == 'DCTDecode' || name == 'DCT') {
- var bytes = stream.getBytes(length);
- return new JpegStream(bytes, stream.dict, this.xref);
- }
- if (name == 'JPXDecode' || name == 'JPX') {
- var bytes = stream.getBytes(length);
- return new JpxStream(bytes, stream.dict);
- }
- if (name == 'ASCII85Decode' || name == 'A85') {
- return new Ascii85Stream(stream);
- }
- if (name == 'ASCIIHexDecode' || name == 'AHx') {
- return new AsciiHexStream(stream);
- }
- if (name == 'CCITTFaxDecode' || name == 'CCF') {
- return new CCITTFaxStream(stream, params);
- }
- if (name == 'RunLengthDecode' || name == 'RL') {
- return new RunLengthStream(stream);
- }
- if (name == 'JBIG2Decode') {
- var bytes = stream.getBytes(length);
- return new Jbig2Stream(bytes, stream.dict);
- }
- warn('filter "' + name + '" not supported yet');
- return stream;
}
};
@@ -31992,6 +30357,13 @@ var Lexer = (function LexerClosure() {
this.stream = stream;
this.nextChar();
+ // While lexing, we build up many strings one char at a time. Using += for
+ // this can result in lots of garbage strings. It's better to build an
+ // array of single-char strings and then join() them together at the end.
+ // And reusing a single array (i.e. |this.strBuf|) over and over for this
+ // purpose uses less memory than using a new array for each string.
+ this.strBuf = [];
+
// The PDFs might have "glued" commands with other commands, operands or
// literals, e.g. "q1". The knownCommands is a dictionary of the valid
// commands and their prefixes. The prefixes are built the following way:
@@ -32003,29 +30375,29 @@ var Lexer = (function LexerClosure() {
}
Lexer.isSpace = function Lexer_isSpace(ch) {
- // space is one of the following characters: SPACE, TAB, CR, or LF
- return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A;
+ // Space is one of the following characters: SPACE, TAB, CR or LF.
+ return (ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A);
};
- // A '1' in this array means the character is white space. A '1' or
+ // A '1' in this array means the character is white space. A '1' or
// '2' means the character ends a name or command.
var specialChars = [
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
- 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
];
function toHexDigit(ch) {
@@ -32043,36 +30415,87 @@ var Lexer = (function LexerClosure() {
nextChar: function Lexer_nextChar() {
return (this.currentChar = this.stream.getByte());
},
+ peekChar: function Lexer_peekChar() {
+ return this.stream.peekByte();
+ },
getNumber: function Lexer_getNumber() {
- var floating = false;
var ch = this.currentChar;
- var str = String.fromCharCode(ch);
+ var eNotation = false;
+ var divideBy = 0; // different from 0 if it's a floating point value
+ var sign = 1;
+
+ if (ch === 0x2D) { // '-'
+ sign = -1;
+ ch = this.nextChar();
+ } else if (ch === 0x2B) { // '+'
+ ch = this.nextChar();
+ }
+ if (ch === 0x2E) { // '.'
+ divideBy = 10;
+ ch = this.nextChar();
+ }
+ if (ch < 0x30 || ch > 0x39) { // '0' - '9'
+ error('Invalid number: ' + String.fromCharCode(ch));
+ return 0;
+ }
+
+ var baseValue = ch - 0x30; // '0'
+ var powerValue = 0;
+ var powerValueSign = 1;
+
while ((ch = this.nextChar()) >= 0) {
- if (ch === 0x2E && !floating) { // '.'
- str += '.';
- floating = true;
+ if (0x30 <= ch && ch <= 0x39) { // '0' - '9'
+ var currentDigit = ch - 0x30; // '0'
+ if (eNotation) { // We are after an 'e' or 'E'
+ powerValue = powerValue * 10 + currentDigit;
+ } else {
+ if (divideBy !== 0) { // We are after a point
+ divideBy *= 10;
+ }
+ baseValue = baseValue * 10 + currentDigit;
+ }
+ } else if (ch === 0x2E) { // '.'
+ if (divideBy === 0) {
+ divideBy = 1;
+ } else {
+ // A number can have only one '.'
+ break;
+ }
} else if (ch === 0x2D) { // '-'
// ignore minus signs in the middle of numbers to match
// Adobe's behavior
warn('Badly formated number');
- } else if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
- str += String.fromCharCode(ch);
} else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
- floating = true;
+ // 'E' can be either a scientific notation or the beginning of a new
+ // operator
+ ch = this.peekChar();
+ if (ch === 0x2B || ch === 0x2D) { // '+', '-'
+ powerValueSign = (ch === 0x2D) ? -1 : 1;
+ this.nextChar(); // Consume the sign character
+ } else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
+ // The 'E' must be the beginning of a new operator
+ break;
+ }
+ eNotation = true;
} else {
// the last character doesn't belong to us
break;
}
}
- var value = parseFloat(str);
- if (isNaN(value))
- error('Invalid floating point number: ' + value);
- return value;
+
+ if (divideBy !== 0) {
+ baseValue /= divideBy;
+ }
+ if (eNotation) {
+ baseValue *= Math.pow(10, powerValueSign * powerValue);
+ }
+ return sign * baseValue;
},
getString: function Lexer_getString() {
var numParen = 1;
var done = false;
- var str = '';
+ var strBuf = this.strBuf;
+ strBuf.length = 0;
var ch = this.nextChar();
while (true) {
@@ -32084,14 +30507,14 @@ var Lexer = (function LexerClosure() {
break;
case 0x28: // '('
++numParen;
- str += '(';
+ strBuf.push('(');
break;
case 0x29: // ')'
if (--numParen === 0) {
this.nextChar(); // consume strings ')'
done = true;
} else {
- str += ')';
+ strBuf.push(')');
}
break;
case 0x5C: // '\\'
@@ -32102,24 +30525,24 @@ var Lexer = (function LexerClosure() {
done = true;
break;
case 0x6E: // 'n'
- str += '\n';
+ strBuf.push('\n');
break;
case 0x72: // 'r'
- str += '\r';
+ strBuf.push('\r');
break;
case 0x74: // 't'
- str += '\t';
+ strBuf.push('\t');
break;
case 0x62: // 'b'
- str += '\b';
+ strBuf.push('\b');
break;
case 0x66: // 'f'
- str += '\f';
+ strBuf.push('\f');
break;
case 0x5C: // '\'
case 0x28: // '('
case 0x29: // ')'
- str += String.fromCharCode(ch);
+ strBuf.push(String.fromCharCode(ch));
break;
case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3'
case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7'
@@ -32134,18 +30557,22 @@ var Lexer = (function LexerClosure() {
x = (x << 3) + (ch & 0x0F);
}
}
-
- str += String.fromCharCode(x);
+ strBuf.push(String.fromCharCode(x));
break;
- case 0x0A: case 0x0D: // LF, CR
+ case 0x0D: // CR
+ if (this.peekChar() === 0x0A) { // LF
+ this.nextChar();
+ }
+ break;
+ case 0x0A: // LF
break;
default:
- str += String.fromCharCode(ch);
+ strBuf.push(String.fromCharCode(ch));
break;
}
break;
default:
- str += String.fromCharCode(ch);
+ strBuf.push(String.fromCharCode(ch));
break;
}
if (done) {
@@ -32155,35 +30582,38 @@ var Lexer = (function LexerClosure() {
ch = this.nextChar();
}
}
- return str;
+ return strBuf.join('');
},
getName: function Lexer_getName() {
- var str = '', ch;
+ var ch;
+ var strBuf = this.strBuf;
+ strBuf.length = 0;
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
if (ch === 0x23) { // '#'
ch = this.nextChar();
var x = toHexDigit(ch);
- if (x != -1) {
+ if (x !== -1) {
var x2 = toHexDigit(this.nextChar());
- if (x2 == -1)
+ if (x2 === -1) {
error('Illegal digit in hex char in name: ' + x2);
- str += String.fromCharCode((x << 4) | x2);
+ }
+ strBuf.push(String.fromCharCode((x << 4) | x2));
} else {
- str += '#';
- str += String.fromCharCode(ch);
+ strBuf.push('#', String.fromCharCode(ch));
}
} else {
- str += String.fromCharCode(ch);
+ strBuf.push(String.fromCharCode(ch));
}
}
- if (str.length > 128) {
+ if (strBuf.length > 128) {
error('Warning: name token is longer than allowed by the spec: ' +
- str.length);
+ strBuf.length);
}
- return new Name(str);
+ return Name.get(strBuf.join(''));
},
getHexString: function Lexer_getHexString() {
- var str = '';
+ var strBuf = this.strBuf;
+ strBuf.length = 0;
var ch = this.currentChar;
var isFirstHex = true;
var firstDigit;
@@ -32213,13 +30643,13 @@ var Lexer = (function LexerClosure() {
ch = this.nextChar();
continue;
}
- str += String.fromCharCode((firstDigit << 4) | secondDigit);
+ strBuf.push(String.fromCharCode((firstDigit << 4) | secondDigit));
}
isFirstHex = !isFirstHex;
ch = this.nextChar();
}
}
- return str;
+ return strBuf.join('');
},
getObj: function Lexer_getObj() {
// skip whitespace and comments
@@ -32230,8 +30660,9 @@ var Lexer = (function LexerClosure() {
return EOF;
}
if (comment) {
- if (ch === 0x0A || ch == 0x0D) // LF, CR
+ if (ch === 0x0A || ch === 0x0D) { // LF, CR
comment = false;
+ }
} else if (ch === 0x25) { // '%'
comment = true;
} else if (specialChars[ch] !== 1) {
@@ -32288,29 +30719,32 @@ var Lexer = (function LexerClosure() {
// command
var str = String.fromCharCode(ch);
var knownCommands = this.knownCommands;
- var knownCommandFound = knownCommands && (str in knownCommands);
+ var knownCommandFound = knownCommands && knownCommands[str] !== undefined;
while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
// stop if known command is found and next character does not make
// the str a command
var possibleCommand = str + String.fromCharCode(ch);
- if (knownCommandFound && !(possibleCommand in knownCommands)) {
+ if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
break;
}
- if (str.length == 128)
+ if (str.length === 128) {
error('Command token too long: ' + str.length);
+ }
str = possibleCommand;
- knownCommandFound = knownCommands && (str in knownCommands);
+ knownCommandFound = knownCommands && knownCommands[str] !== undefined;
}
- if (str == 'true')
+ if (str === 'true') {
return true;
- if (str == 'false')
+ }
+ if (str === 'false') {
return false;
- if (str == 'null')
+ }
+ if (str === 'null') {
return null;
+ }
return Cmd.get(str);
},
skipToNextLine: function Lexer_skipToNextLine() {
- var stream = this.stream;
var ch = this.currentChar;
while (ch >= 0) {
if (ch === 0x0D) { // CR
@@ -32331,87 +30765,264 @@ var Lexer = (function LexerClosure() {
return Lexer;
})();
-var Linearization = (function LinearizationClosure() {
- function Linearization(stream) {
- this.parser = new Parser(new Lexer(stream), false, null);
- var obj1 = this.parser.getObj();
- var obj2 = this.parser.getObj();
- var obj3 = this.parser.getObj();
- this.linDict = this.parser.getObj();
- if (isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') &&
- isDict(this.linDict)) {
- var obj = this.linDict.get('Linearized');
- if (!(isNum(obj) && obj > 0))
- this.linDict = null;
- }
- }
-
- Linearization.prototype = {
- getInt: function Linearization_getInt(name) {
- var linDict = this.linDict;
- var obj;
- if (isDict(linDict) &&
- isInt(obj = linDict.get(name)) &&
- obj > 0) {
+var Linearization = {
+ create: function LinearizationCreate(stream) {
+ function getInt(name, allowZeroValue) {
+ var obj = linDict.get(name);
+ if (isInt(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
return obj;
}
- error('"' + name + '" field in linearization table is invalid');
- },
- getHint: function Linearization_getHint(index) {
- var linDict = this.linDict;
- var obj1, obj2;
- if (isDict(linDict) &&
- isArray(obj1 = linDict.get('H')) &&
- obj1.length >= 2 &&
- isInt(obj2 = obj1[index]) &&
- obj2 > 0) {
- return obj2;
+ throw new Error('The "' + name + '" parameter in the linearization ' +
+ 'dictionary is invalid.');
+ }
+ function getHints() {
+ var hints = linDict.get('H'), hintsLength, item;
+ if (isArray(hints) &&
+ ((hintsLength = hints.length) === 2 || hintsLength === 4)) {
+ for (var index = 0; index < hintsLength; index++) {
+ if (!(isInt(item = hints[index]) && item > 0)) {
+ throw new Error('Hint (' + index +
+ ') in the linearization dictionary is invalid.');
+ }
+ }
+ return hints;
}
- error('Hints table in linearization table is invalid: ' + index);
+ throw new Error('Hint array in the linearization dictionary is invalid.');
+ }
+ var parser = new Parser(new Lexer(stream), false, null);
+ var obj1 = parser.getObj();
+ var obj2 = parser.getObj();
+ var obj3 = parser.getObj();
+ var linDict = parser.getObj();
+ var obj, length;
+ if (!(isInt(obj1) && isInt(obj2) && isCmd(obj3, 'obj') && isDict(linDict) &&
+ isNum(obj = linDict.get('Linearized')) && obj > 0)) {
+ return null; // No valid linearization dictionary found.
+ } else if ((length = getInt('L')) !== stream.length) {
+ throw new Error('The "L" parameter in the linearization dictionary ' +
+ 'does not equal the stream length.');
+ }
+ return {
+ length: length,
+ hints: getHints(),
+ objectNumberFirst: getInt('O'),
+ endFirst: getInt('E'),
+ numPages: getInt('N'),
+ mainXRefEntriesOffset: getInt('T'),
+ pageFirst: (linDict.has('P') ? getInt('P', true) : 0)
+ };
+ }
+};
+
+
+var PostScriptParser = (function PostScriptParserClosure() {
+ function PostScriptParser(lexer) {
+ this.lexer = lexer;
+ this.operators = [];
+ this.token = null;
+ this.prev = null;
+ }
+ PostScriptParser.prototype = {
+ nextToken: function PostScriptParser_nextToken() {
+ this.prev = this.token;
+ this.token = this.lexer.getToken();
},
- get length() {
- if (!isDict(this.linDict))
- return 0;
- return this.getInt('L');
+ accept: function PostScriptParser_accept(type) {
+ if (this.token.type === type) {
+ this.nextToken();
+ return true;
+ }
+ return false;
},
- get hintsOffset() {
- return this.getHint(0);
+ expect: function PostScriptParser_expect(type) {
+ if (this.accept(type)) {
+ return true;
+ }
+ error('Unexpected symbol: found ' + this.token.type + ' expected ' +
+ type + '.');
},
- get hintsLength() {
- return this.getHint(1);
+ parse: function PostScriptParser_parse() {
+ this.nextToken();
+ this.expect(PostScriptTokenTypes.LBRACE);
+ this.parseBlock();
+ this.expect(PostScriptTokenTypes.RBRACE);
+ return this.operators;
},
- get hintsOffset2() {
- return this.getHint(2);
+ parseBlock: function PostScriptParser_parseBlock() {
+ while (true) {
+ if (this.accept(PostScriptTokenTypes.NUMBER)) {
+ this.operators.push(this.prev.value);
+ } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
+ this.operators.push(this.prev.value);
+ } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
+ this.parseCondition();
+ } else {
+ return;
+ }
+ }
},
- get hintsLenth2() {
- return this.getHint(3);
- },
- get objectNumberFirst() {
- return this.getInt('O');
- },
- get endFirst() {
- return this.getInt('E');
- },
- get numPages() {
- return this.getInt('N');
- },
- get mainXRefEntriesOffset() {
- return this.getInt('T');
- },
- get pageFirst() {
- return this.getInt('P');
+ parseCondition: function PostScriptParser_parseCondition() {
+ // Add two place holders that will be updated later
+ var conditionLocation = this.operators.length;
+ this.operators.push(null, null);
+
+ this.parseBlock();
+ this.expect(PostScriptTokenTypes.RBRACE);
+ if (this.accept(PostScriptTokenTypes.IF)) {
+ // The true block is right after the 'if' so it just falls through on
+ // true else it jumps and skips the true block.
+ this.operators[conditionLocation] = this.operators.length;
+ this.operators[conditionLocation + 1] = 'jz';
+ } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
+ var jumpLocation = this.operators.length;
+ this.operators.push(null, null);
+ var endOfTrue = this.operators.length;
+ this.parseBlock();
+ this.expect(PostScriptTokenTypes.RBRACE);
+ this.expect(PostScriptTokenTypes.IFELSE);
+ // The jump is added at the end of the true block to skip the false
+ // block.
+ this.operators[jumpLocation] = this.operators.length;
+ this.operators[jumpLocation + 1] = 'j';
+
+ this.operators[conditionLocation] = endOfTrue;
+ this.operators[conditionLocation + 1] = 'jz';
+ } else {
+ error('PS Function: error parsing conditional.');
+ }
}
};
-
- return Linearization;
+ return PostScriptParser;
})();
+var PostScriptTokenTypes = {
+ LBRACE: 0,
+ RBRACE: 1,
+ NUMBER: 2,
+ OPERATOR: 3,
+ IF: 4,
+ IFELSE: 5
+};
+
+var PostScriptToken = (function PostScriptTokenClosure() {
+ function PostScriptToken(type, value) {
+ this.type = type;
+ this.value = value;
+ }
+
+ var opCache = {};
+
+ PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
+ var opValue = opCache[op];
+ if (opValue) {
+ return opValue;
+ }
+ return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
+ };
+
+ PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
+ '{');
+ PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
+ '}');
+ PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
+ PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
+ 'IFELSE');
+ return PostScriptToken;
+})();
+
+var PostScriptLexer = (function PostScriptLexerClosure() {
+ function PostScriptLexer(stream) {
+ this.stream = stream;
+ this.nextChar();
+
+ this.strBuf = [];
+ }
+ PostScriptLexer.prototype = {
+ nextChar: function PostScriptLexer_nextChar() {
+ return (this.currentChar = this.stream.getByte());
+ },
+ getToken: function PostScriptLexer_getToken() {
+ var comment = false;
+ var ch = this.currentChar;
+
+ // skip comments
+ while (true) {
+ if (ch < 0) {
+ return EOF;
+ }
+
+ if (comment) {
+ if (ch === 0x0A || ch === 0x0D) {
+ comment = false;
+ }
+ } else if (ch === 0x25) { // '%'
+ comment = true;
+ } else if (!Lexer.isSpace(ch)) {
+ break;
+ }
+ ch = this.nextChar();
+ }
+ switch (ch | 0) {
+ case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
+ case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
+ case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
+ return new PostScriptToken(PostScriptTokenTypes.NUMBER,
+ this.getNumber());
+ case 0x7B: // '{'
+ this.nextChar();
+ return PostScriptToken.LBRACE;
+ case 0x7D: // '}'
+ this.nextChar();
+ return PostScriptToken.RBRACE;
+ }
+ // operator
+ var strBuf = this.strBuf;
+ strBuf.length = 0;
+ strBuf[0] = String.fromCharCode(ch);
+
+ while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
+ ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
+ strBuf.push(String.fromCharCode(ch));
+ }
+ var str = strBuf.join('');
+ switch (str.toLowerCase()) {
+ case 'if':
+ return PostScriptToken.IF;
+ case 'ifelse':
+ return PostScriptToken.IFELSE;
+ default:
+ return PostScriptToken.getOperator(str);
+ }
+ },
+ getNumber: function PostScriptLexer_getNumber() {
+ var ch = this.currentChar;
+ var strBuf = this.strBuf;
+ strBuf.length = 0;
+ strBuf[0] = String.fromCharCode(ch);
+
+ while ((ch = this.nextChar()) >= 0) {
+ if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
+ ch === 0x2D || ch === 0x2E) { // '-', '.'
+ strBuf.push(String.fromCharCode(ch));
+ } else {
+ break;
+ }
+ }
+ var value = parseFloat(strBuf.join(''));
+ if (isNaN(value)) {
+ error('Invalid floating point number: ' + value);
+ }
+ return value;
+ }
+ };
+ return PostScriptLexer;
+})();
var Stream = (function StreamClosure() {
function Stream(arrayBuffer, start, length, dict) {
- this.bytes = arrayBuffer instanceof Uint8Array ? arrayBuffer :
- new Uint8Array(arrayBuffer);
+ this.bytes = (arrayBuffer instanceof Uint8Array ?
+ arrayBuffer : new Uint8Array(arrayBuffer));
this.start = start || 0;
this.pos = this.start;
this.end = (start + length) || this.bytes.length;
@@ -32424,11 +31035,27 @@ var Stream = (function StreamClosure() {
get length() {
return this.end - this.start;
},
+ get isEmpty() {
+ return this.length === 0;
+ },
getByte: function Stream_getByte() {
- if (this.pos >= this.end)
+ if (this.pos >= this.end) {
return -1;
+ }
return this.bytes[this.pos++];
},
+ getUint16: function Stream_getUint16() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ return (b0 << 8) + b1;
+ },
+ getInt32: function Stream_getInt32() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ var b2 = this.getByte();
+ var b3 = this.getByte();
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
+ },
// returns subarray of original buffer
// should only be read
getBytes: function Stream_getBytes(length) {
@@ -32436,24 +31063,30 @@ var Stream = (function StreamClosure() {
var pos = this.pos;
var strEnd = this.end;
- if (!length)
+ if (!length) {
return bytes.subarray(pos, strEnd);
-
+ }
var end = pos + length;
- if (end > strEnd)
+ if (end > strEnd) {
end = strEnd;
-
+ }
this.pos = end;
return bytes.subarray(pos, end);
},
+ peekByte: function Stream_peekByte() {
+ var peekedByte = this.getByte();
+ this.pos--;
+ return peekedByte;
+ },
peekBytes: function Stream_peekBytes(length) {
var bytes = this.getBytes(length);
this.pos -= bytes.length;
return bytes;
},
skip: function Stream_skip(n) {
- if (!n)
+ if (!n) {
n = 1;
+ }
this.pos += n;
},
reset: function Stream_reset() {
@@ -32475,8 +31108,9 @@ var StringStream = (function StringStreamClosure() {
function StringStream(str) {
var length = str.length;
var bytes = new Uint8Array(length);
- for (var n = 0; n < length; ++n)
+ for (var n = 0; n < length; ++n) {
bytes[n] = str.charCodeAt(n);
+ }
Stream.call(this, bytes);
}
@@ -32487,36 +31121,68 @@ var StringStream = (function StringStreamClosure() {
// super class for the decoding streams
var DecodeStream = (function DecodeStreamClosure() {
- function DecodeStream() {
+ // Lots of DecodeStreams are created whose buffers are never used. For these
+ // we share a single empty buffer. This is (a) space-efficient and (b) avoids
+ // having special cases that would be required if we used |null| for an empty
+ // buffer.
+ var emptyBuffer = new Uint8Array(0);
+
+ function DecodeStream(maybeMinBufferLength) {
this.pos = 0;
this.bufferLength = 0;
this.eof = false;
- this.buffer = null;
+ this.buffer = emptyBuffer;
+ this.minBufferLength = 512;
+ if (maybeMinBufferLength) {
+ // Compute the first power of two that is as big as maybeMinBufferLength.
+ while (this.minBufferLength < maybeMinBufferLength) {
+ this.minBufferLength *= 2;
+ }
+ }
}
DecodeStream.prototype = {
+ get isEmpty() {
+ while (!this.eof && this.bufferLength === 0) {
+ this.readBlock();
+ }
+ return this.bufferLength === 0;
+ },
ensureBuffer: function DecodeStream_ensureBuffer(requested) {
var buffer = this.buffer;
- var current = buffer ? buffer.byteLength : 0;
- if (requested < current)
+ if (requested <= buffer.byteLength) {
return buffer;
- var size = 512;
- while (size < requested)
- size <<= 1;
+ }
+ var size = this.minBufferLength;
+ while (size < requested) {
+ size *= 2;
+ }
var buffer2 = new Uint8Array(size);
- for (var i = 0; i < current; ++i)
- buffer2[i] = buffer[i];
+ buffer2.set(buffer);
return (this.buffer = buffer2);
},
getByte: function DecodeStream_getByte() {
var pos = this.pos;
while (this.bufferLength <= pos) {
- if (this.eof)
+ if (this.eof) {
return -1;
+ }
this.readBlock();
}
return this.buffer[this.pos++];
},
+ getUint16: function DecodeStream_getUint16() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ return (b0 << 8) + b1;
+ },
+ getInt32: function DecodeStream_getInt32() {
+ var b0 = this.getByte();
+ var b1 = this.getByte();
+ var b2 = this.getByte();
+ var b3 = this.getByte();
+ return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
+ },
getBytes: function DecodeStream_getBytes(length) {
var end, pos = this.pos;
@@ -32524,27 +31190,28 @@ var DecodeStream = (function DecodeStreamClosure() {
this.ensureBuffer(pos + length);
end = pos + length;
- while (!this.eof && this.bufferLength < end)
+ while (!this.eof && this.bufferLength < end) {
this.readBlock();
-
+ }
var bufEnd = this.bufferLength;
- if (end > bufEnd)
+ if (end > bufEnd) {
end = bufEnd;
+ }
} else {
- while (!this.eof)
+ while (!this.eof) {
this.readBlock();
-
+ }
end = this.bufferLength;
-
- // checking if bufferLength is still 0 then
- // the buffer has to be initialized
- if (!end)
- this.buffer = new Uint8Array(0);
}
this.pos = end;
return this.buffer.subarray(pos, end);
},
+ peekByte: function DecodeStream_peekByte() {
+ var peekedByte = this.getByte();
+ this.pos--;
+ return peekedByte;
+ },
peekBytes: function DecodeStream_peekBytes(length) {
var bytes = this.getBytes(length);
this.pos -= bytes.length;
@@ -32552,13 +31219,15 @@ var DecodeStream = (function DecodeStreamClosure() {
},
makeSubStream: function DecodeStream_makeSubStream(start, length, dict) {
var end = start + length;
- while (this.bufferLength <= end && !this.eof)
+ while (this.bufferLength <= end && !this.eof) {
this.readBlock();
+ }
return new Stream(this.buffer, start, length, dict);
},
- skip: function Stream_skip(n) {
- if (!n)
+ skip: function DecodeStream_skip(n) {
+ if (!n) {
n = 1;
+ }
this.pos += n;
},
reset: function DecodeStream_reset() {
@@ -32575,55 +31244,16 @@ var DecodeStream = (function DecodeStreamClosure() {
return DecodeStream;
})();
-var FakeStream = (function FakeStreamClosure() {
- function FakeStream(stream) {
- this.dict = stream.dict;
- DecodeStream.call(this);
- }
-
- FakeStream.prototype = Object.create(DecodeStream.prototype);
- FakeStream.prototype.readBlock = function FakeStream_readBlock() {
- var bufferLength = this.bufferLength;
- bufferLength += 1024;
- var buffer = this.ensureBuffer(bufferLength);
- this.bufferLength = bufferLength;
- };
-
- FakeStream.prototype.getBytes = function FakeStream_getBytes(length) {
- var end, pos = this.pos;
-
- if (length) {
- this.ensureBuffer(pos + length);
- end = pos + length;
-
- while (!this.eof && this.bufferLength < end)
- this.readBlock();
-
- var bufEnd = this.bufferLength;
- if (end > bufEnd)
- end = bufEnd;
- } else {
- this.eof = true;
- end = this.bufferLength;
- }
-
- this.pos = end;
- return this.buffer.subarray(pos, end);
- };
-
- return FakeStream;
-})();
-
var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
function StreamsSequenceStream(streams) {
this.streams = streams;
- DecodeStream.call(this);
+ DecodeStream.call(this, /* maybeLength = */ null);
}
StreamsSequenceStream.prototype = Object.create(DecodeStream.prototype);
StreamsSequenceStream.prototype.readBlock =
- function streamSequenceStreamReadBlock() {
+ function streamSequenceStreamReadBlock() {
var streams = this.streams;
if (streams.length === 0) {
@@ -32646,7 +31276,7 @@ var StreamsSequenceStream = (function StreamsSequenceStreamClosure() {
for (var i = 0, ii = this.streams.length; i < ii; i++) {
var stream = this.streams[i];
if (stream.getBaseStreams) {
- Util.concatenateToArray(baseStreams, stream.getBaseStreams());
+ Util.appendToArray(baseStreams, stream.getBaseStreams());
}
}
return baseStreams;
@@ -32748,88 +31378,92 @@ var FlateStream = (function FlateStreamClosure() {
0x50003, 0x50013, 0x5000b, 0x5001b, 0x50007, 0x50017, 0x5000f, 0x00000
]), 5];
- function FlateStream(stream) {
- var bytes = stream.getBytes();
- var bytesPos = 0;
+ function FlateStream(str, maybeLength) {
+ this.str = str;
+ this.dict = str.dict;
- this.dict = stream.dict;
- var cmf = bytes[bytesPos++];
- var flg = bytes[bytesPos++];
- if (cmf == -1 || flg == -1)
+ var cmf = str.getByte();
+ var flg = str.getByte();
+ if (cmf === -1 || flg === -1) {
error('Invalid header in flate stream: ' + cmf + ', ' + flg);
- if ((cmf & 0x0f) != 0x08)
+ }
+ if ((cmf & 0x0f) !== 0x08) {
error('Unknown compression method in flate stream: ' + cmf + ', ' + flg);
- if ((((cmf << 8) + flg) % 31) !== 0)
+ }
+ if ((((cmf << 8) + flg) % 31) !== 0) {
error('Bad FCHECK in flate stream: ' + cmf + ', ' + flg);
- if (flg & 0x20)
+ }
+ if (flg & 0x20) {
error('FDICT bit set in flate stream: ' + cmf + ', ' + flg);
-
- this.bytes = bytes;
- this.bytesPos = bytesPos;
+ }
this.codeSize = 0;
this.codeBuf = 0;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
FlateStream.prototype = Object.create(DecodeStream.prototype);
FlateStream.prototype.getBits = function FlateStream_getBits(bits) {
+ var str = this.str;
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
- var bytes = this.bytes;
- var bytesPos = this.bytesPos;
var b;
while (codeSize < bits) {
- if (typeof (b = bytes[bytesPos++]) == 'undefined')
+ if ((b = str.getByte()) === -1) {
error('Bad encoding in flate stream');
+ }
codeBuf |= b << codeSize;
codeSize += 8;
}
b = codeBuf & ((1 << bits) - 1);
this.codeBuf = codeBuf >> bits;
this.codeSize = codeSize -= bits;
- this.bytesPos = bytesPos;
+
return b;
};
FlateStream.prototype.getCode = function FlateStream_getCode(table) {
+ var str = this.str;
var codes = table[0];
var maxLen = table[1];
var codeSize = this.codeSize;
var codeBuf = this.codeBuf;
- var bytes = this.bytes;
- var bytesPos = this.bytesPos;
+ var b;
while (codeSize < maxLen) {
- var b;
- if (typeof (b = bytes[bytesPos++]) == 'undefined')
- error('Bad encoding in flate stream');
+ if ((b = str.getByte()) === -1) {
+ // premature end of stream. code might however still be valid.
+ // codeSize < codeLen check below guards against incomplete codeVal.
+ break;
+ }
codeBuf |= (b << codeSize);
codeSize += 8;
}
var code = codes[codeBuf & ((1 << maxLen) - 1)];
var codeLen = code >> 16;
var codeVal = code & 0xffff;
- if (codeSize === 0 || codeSize < codeLen || codeLen === 0)
+ if (codeLen < 1 || codeSize < codeLen) {
error('Bad encoding in flate stream');
+ }
this.codeBuf = (codeBuf >> codeLen);
this.codeSize = (codeSize - codeLen);
- this.bytesPos = bytesPos;
return codeVal;
};
FlateStream.prototype.generateHuffmanTable =
- function flateStreamGenerateHuffmanTable(lengths) {
+ function flateStreamGenerateHuffmanTable(lengths) {
var n = lengths.length;
// find max code length
var maxLen = 0;
- for (var i = 0; i < n; ++i) {
- if (lengths[i] > maxLen)
+ var i;
+ for (i = 0; i < n; ++i) {
+ if (lengths[i] > maxLen) {
maxLen = lengths[i];
+ }
}
// build the table
@@ -32839,19 +31473,19 @@ var FlateStream = (function FlateStreamClosure() {
len <= maxLen;
++len, code <<= 1, skip <<= 1) {
for (var val = 0; val < n; ++val) {
- if (lengths[val] == len) {
+ if (lengths[val] === len) {
// bit-reverse the code
var code2 = 0;
var t = code;
- for (var i = 0; i < len; ++i) {
+ for (i = 0; i < len; ++i) {
code2 = (code2 << 1) | (t & 1);
t >>= 1;
}
// fill the table entries
- for (var i = code2; i < size; i += skip)
+ for (i = code2; i < size; i += skip) {
codes[i] = (len << 16) | val;
-
+ }
++code;
}
}
@@ -32861,30 +31495,35 @@ var FlateStream = (function FlateStreamClosure() {
};
FlateStream.prototype.readBlock = function FlateStream_readBlock() {
+ var buffer, len;
+ var str = this.str;
// read block header
var hdr = this.getBits(3);
- if (hdr & 1)
+ if (hdr & 1) {
this.eof = true;
+ }
hdr >>= 1;
if (hdr === 0) { // uncompressed block
- var bytes = this.bytes;
- var bytesPos = this.bytesPos;
var b;
- if (typeof (b = bytes[bytesPos++]) == 'undefined')
+ if ((b = str.getByte()) === -1) {
error('Bad block header in flate stream');
+ }
var blockLen = b;
- if (typeof (b = bytes[bytesPos++]) == 'undefined')
+ if ((b = str.getByte()) === -1) {
error('Bad block header in flate stream');
+ }
blockLen |= (b << 8);
- if (typeof (b = bytes[bytesPos++]) == 'undefined')
+ if ((b = str.getByte()) === -1) {
error('Bad block header in flate stream');
+ }
var check = b;
- if (typeof (b = bytes[bytesPos++]) == 'undefined')
+ if ((b = str.getByte()) === -1) {
error('Bad block header in flate stream');
+ }
check |= (b << 8);
- if (check != (~blockLen & 0xffff) &&
+ if (check !== (~blockLen & 0xffff) &&
(blockLen !== 0 || check !== 0)) {
// Ignoring error for bad "empty" block (see issue 1277)
error('Bad uncompressed block length in flate stream');
@@ -32894,32 +31533,31 @@ var FlateStream = (function FlateStreamClosure() {
this.codeSize = 0;
var bufferLength = this.bufferLength;
- var buffer = this.ensureBuffer(bufferLength + blockLen);
+ buffer = this.ensureBuffer(bufferLength + blockLen);
var end = bufferLength + blockLen;
this.bufferLength = end;
if (blockLen === 0) {
- if (typeof bytes[bytesPos] == 'undefined') {
+ if (str.peekByte() === -1) {
this.eof = true;
}
} else {
for (var n = bufferLength; n < end; ++n) {
- if (typeof (b = bytes[bytesPos++]) == 'undefined') {
+ if ((b = str.getByte()) === -1) {
this.eof = true;
break;
}
buffer[n] = b;
}
}
- this.bytesPos = bytesPos;
return;
}
var litCodeTable;
var distCodeTable;
- if (hdr == 1) { // compressed block, fixed codes
+ if (hdr === 1) { // compressed block, fixed codes
litCodeTable = fixedLitCodeTab;
distCodeTable = fixedDistCodeTab;
- } else if (hdr == 2) { // compressed block, dynamic codes
+ } else if (hdr === 2) { // compressed block, dynamic codes
var numLitCodes = this.getBits(5) + 257;
var numDistCodes = this.getBits(5) + 1;
var numCodeLenCodes = this.getBits(4) + 4;
@@ -32927,31 +31565,35 @@ var FlateStream = (function FlateStreamClosure() {
// build the code lengths code table
var codeLenCodeLengths = new Uint8Array(codeLenCodeMap.length);
- for (var i = 0; i < numCodeLenCodes; ++i)
+ var i;
+ for (i = 0; i < numCodeLenCodes; ++i) {
codeLenCodeLengths[codeLenCodeMap[i]] = this.getBits(3);
+ }
var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths);
// build the literal and distance code tables
- var len = 0;
- var i = 0;
+ len = 0;
+ i = 0;
var codes = numLitCodes + numDistCodes;
var codeLengths = new Uint8Array(codes);
+ var bitsLength, bitsOffset, what;
while (i < codes) {
var code = this.getCode(codeLenCodeTab);
- if (code == 16) {
- var bitsLength = 2, bitsOffset = 3, what = len;
- } else if (code == 17) {
- var bitsLength = 3, bitsOffset = 3, what = (len = 0);
- } else if (code == 18) {
- var bitsLength = 7, bitsOffset = 11, what = (len = 0);
+ if (code === 16) {
+ bitsLength = 2; bitsOffset = 3; what = len;
+ } else if (code === 17) {
+ bitsLength = 3; bitsOffset = 3; what = (len = 0);
+ } else if (code === 18) {
+ bitsLength = 7; bitsOffset = 11; what = (len = 0);
} else {
codeLengths[i++] = len = code;
continue;
}
var repeatLength = this.getBits(bitsLength) + bitsOffset;
- while (repeatLength-- > 0)
+ while (repeatLength-- > 0) {
codeLengths[i++] = what;
+ }
}
litCodeTable =
@@ -32962,7 +31604,7 @@ var FlateStream = (function FlateStreamClosure() {
error('Unknown block type in flate stream');
}
- var buffer = this.buffer;
+ buffer = this.buffer;
var limit = buffer ? buffer.length : 0;
var pos = this.bufferLength;
while (true) {
@@ -32975,28 +31617,31 @@ var FlateStream = (function FlateStreamClosure() {
buffer[pos++] = code1;
continue;
}
- if (code1 == 256) {
+ if (code1 === 256) {
this.bufferLength = pos;
return;
}
code1 -= 257;
code1 = lengthDecode[code1];
var code2 = code1 >> 16;
- if (code2 > 0)
+ if (code2 > 0) {
code2 = this.getBits(code2);
- var len = (code1 & 0xffff) + code2;
+ }
+ len = (code1 & 0xffff) + code2;
code1 = this.getCode(distCodeTable);
code1 = distDecode[code1];
code2 = code1 >> 16;
- if (code2 > 0)
+ if (code2 > 0) {
code2 = this.getBits(code2);
+ }
var dist = (code1 & 0xffff) + code2;
if (pos + len >= limit) {
buffer = this.ensureBuffer(pos + len);
limit = buffer.length;
}
- for (var k = 0; k < len; ++k, ++pos)
+ for (var k = 0; k < len; ++k, ++pos) {
buffer[pos] = buffer[pos - dist];
+ }
}
};
@@ -33004,18 +31649,21 @@ var FlateStream = (function FlateStreamClosure() {
})();
var PredictorStream = (function PredictorStreamClosure() {
- function PredictorStream(str, params) {
+ function PredictorStream(str, maybeLength, params) {
var predictor = this.predictor = params.get('Predictor') || 1;
- if (predictor <= 1)
+ if (predictor <= 1) {
return str; // no prediction
- if (predictor !== 2 && (predictor < 10 || predictor > 15))
+ }
+ if (predictor !== 2 && (predictor < 10 || predictor > 15)) {
error('Unsupported predictor: ' + predictor);
+ }
- if (predictor === 2)
+ if (predictor === 2) {
this.readBlock = this.readBlockTiff;
- else
+ } else {
this.readBlock = this.readBlockPng;
+ }
this.str = str;
this.dict = str.dict;
@@ -33027,14 +31675,14 @@ var PredictorStream = (function PredictorStreamClosure() {
this.pixBytes = (colors * bits + 7) >> 3;
this.rowBytes = (columns * colors * bits + 7) >> 3;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
return this;
}
PredictorStream.prototype = Object.create(DecodeStream.prototype);
PredictorStream.prototype.readBlockTiff =
- function predictorStreamReadBlockTiff() {
+ function predictorStreamReadBlockTiff() {
var rowBytes = this.rowBytes;
var bufferLength = this.bufferLength;
@@ -33052,9 +31700,10 @@ var PredictorStream = (function PredictorStreamClosure() {
var inbuf = 0, outbuf = 0;
var inbits = 0, outbits = 0;
var pos = bufferLength;
+ var i;
if (bits === 1) {
- for (var i = 0; i < rowBytes; ++i) {
+ for (i = 0; i < rowBytes; ++i) {
var c = rawBytes[i];
inbuf = (inbuf << 8) | c;
// bitwise addition is exclusive or
@@ -33064,8 +31713,9 @@ var PredictorStream = (function PredictorStreamClosure() {
inbuf &= 0xFFFF;
}
} else if (bits === 8) {
- for (var i = 0; i < colors; ++i)
+ for (i = 0; i < colors; ++i) {
buffer[pos++] = rawBytes[i];
+ }
for (; i < rowBytes; ++i) {
buffer[pos] = buffer[pos - colors] + rawBytes[i];
pos++;
@@ -33075,7 +31725,7 @@ var PredictorStream = (function PredictorStreamClosure() {
var bitMask = (1 << bits) - 1;
var j = 0, k = bufferLength;
var columns = this.columns;
- for (var i = 0; i < columns; ++i) {
+ for (i = 0; i < columns; ++i) {
for (var kk = 0; kk < colors; ++kk) {
if (inbits < bits) {
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF);
@@ -33094,14 +31744,14 @@ var PredictorStream = (function PredictorStreamClosure() {
}
if (outbits > 0) {
buffer[k++] = (outbuf << (8 - outbits)) +
- (inbuf & ((1 << (8 - outbits)) - 1));
+ (inbuf & ((1 << (8 - outbits)) - 1));
}
}
this.bufferLength += rowBytes;
};
PredictorStream.prototype.readBlockPng =
- function predictorStreamReadBlockPng() {
+ function predictorStreamReadBlockPng() {
var rowBytes = this.rowBytes;
var pixBytes = this.pixBytes;
@@ -33117,30 +31767,35 @@ var PredictorStream = (function PredictorStreamClosure() {
var buffer = this.ensureBuffer(bufferLength + rowBytes);
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength);
- if (prevRow.length === 0)
+ if (prevRow.length === 0) {
prevRow = new Uint8Array(rowBytes);
+ }
- var j = bufferLength;
+ var i, j = bufferLength, up, c;
switch (predictor) {
case 0:
- for (var i = 0; i < rowBytes; ++i)
+ for (i = 0; i < rowBytes; ++i) {
buffer[j++] = rawBytes[i];
+ }
break;
case 1:
- for (var i = 0; i < pixBytes; ++i)
+ for (i = 0; i < pixBytes; ++i) {
buffer[j++] = rawBytes[i];
+ }
for (; i < rowBytes; ++i) {
buffer[j] = (buffer[j - pixBytes] + rawBytes[i]) & 0xFF;
j++;
}
break;
case 2:
- for (var i = 0; i < rowBytes; ++i)
+ for (i = 0; i < rowBytes; ++i) {
buffer[j++] = (prevRow[i] + rawBytes[i]) & 0xFF;
+ }
break;
case 3:
- for (var i = 0; i < pixBytes; ++i)
+ for (i = 0; i < pixBytes; ++i) {
buffer[j++] = (prevRow[i] >> 1) + rawBytes[i];
+ }
for (; i < rowBytes; ++i) {
buffer[j] = (((prevRow[i] + buffer[j - pixBytes]) >> 1) +
rawBytes[i]) & 0xFF;
@@ -33150,34 +31805,38 @@ var PredictorStream = (function PredictorStreamClosure() {
case 4:
// we need to save the up left pixels values. the simplest way
// is to create a new buffer
- for (var i = 0; i < pixBytes; ++i) {
- var up = prevRow[i];
- var c = rawBytes[i];
+ for (i = 0; i < pixBytes; ++i) {
+ up = prevRow[i];
+ c = rawBytes[i];
buffer[j++] = up + c;
}
for (; i < rowBytes; ++i) {
- var up = prevRow[i];
+ up = prevRow[i];
var upLeft = prevRow[i - pixBytes];
var left = buffer[j - pixBytes];
var p = left + up - upLeft;
var pa = p - left;
- if (pa < 0)
+ if (pa < 0) {
pa = -pa;
+ }
var pb = p - up;
- if (pb < 0)
+ if (pb < 0) {
pb = -pb;
+ }
var pc = p - upLeft;
- if (pc < 0)
+ if (pc < 0) {
pc = -pc;
+ }
- var c = rawBytes[i];
- if (pa <= pb && pa <= pc)
+ c = rawBytes[i];
+ if (pa <= pb && pa <= pc) {
buffer[j++] = left + c;
- else if (pb <= pc)
+ } else if (pb <= pc) {
buffer[j++] = up + c;
- else
+ } else {
buffer[j++] = upLeft + c;
+ }
}
break;
default:
@@ -33197,28 +31856,56 @@ var PredictorStream = (function PredictorStreamClosure() {
* DecodeStreams.
*/
var JpegStream = (function JpegStreamClosure() {
- function JpegStream(bytes, dict, xref) {
+ function JpegStream(stream, maybeLength, dict, xref) {
// TODO: per poppler, some images may have 'junk' before that
// need to be removed
+ this.stream = stream;
+ this.maybeLength = maybeLength;
this.dict = dict;
- this.bytes = bytes;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
JpegStream.prototype = Object.create(DecodeStream.prototype);
+ Object.defineProperty(JpegStream.prototype, 'bytes', {
+ get: function JpegStream_bytes() {
+ // If this.maybeLength is null, we'll get the entire stream.
+ return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
+ },
+ configurable: true
+ });
+
JpegStream.prototype.ensureBuffer = function JpegStream_ensureBuffer(req) {
- if (this.bufferLength)
+ if (this.bufferLength) {
return;
+ }
try {
var jpegImage = new JpegImage();
- if (this.colorTransform != -1)
- jpegImage.colorTransform = this.colorTransform;
+
+ // checking if values needs to be transformed before conversion
+ if (this.forceRGB && this.dict && isArray(this.dict.get('Decode'))) {
+ var decodeArr = this.dict.get('Decode');
+ var bitsPerComponent = this.dict.get('BitsPerComponent') || 8;
+ var decodeArrLength = decodeArr.length;
+ var transform = new Int32Array(decodeArrLength);
+ var transformNeeded = false;
+ var maxValue = (1 << bitsPerComponent) - 1;
+ for (var i = 0; i < decodeArrLength; i += 2) {
+ transform[i] = ((decodeArr[i + 1] - decodeArr[i]) * 256) | 0;
+ transform[i + 1] = (decodeArr[i] * maxValue) | 0;
+ if (transform[i] !== 256 || transform[i + 1] !== 0) {
+ transformNeeded = true;
+ }
+ }
+ if (transformNeeded) {
+ jpegImage.decodeTransform = transform;
+ }
+ }
+
jpegImage.parse(this.bytes);
- var width = jpegImage.width;
- var height = jpegImage.height;
- var data = jpegImage.getData(width, height);
+ var data = jpegImage.getData(this.drawWidth, this.drawHeight,
+ this.forceRGB);
this.buffer = data;
this.bufferLength = data.length;
this.eof = true;
@@ -33226,6 +31913,12 @@ var JpegStream = (function JpegStreamClosure() {
error('JPEG error: ' + e);
}
};
+
+ JpegStream.prototype.getBytes = function JpegStream_getBytes(length) {
+ this.ensureBuffer();
+ return this.buffer;
+ };
+
JpegStream.prototype.getIR = function JpegStream_getIR() {
return PDFJS.createObjectURL(this.bytes, 'image/jpeg');
};
@@ -33234,7 +31927,7 @@ var JpegStream = (function JpegStreamClosure() {
* further processing such as color space conversions.
*/
JpegStream.prototype.isNativelySupported =
- function JpegStream_isNativelySupported(xref, res) {
+ function JpegStream_isNativelySupported(xref, res) {
var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
return cs.name === 'DeviceGray' || cs.name === 'DeviceRGB';
};
@@ -33242,10 +31935,10 @@ var JpegStream = (function JpegStreamClosure() {
* Checks if the image can be decoded by the browser.
*/
JpegStream.prototype.isNativelyDecodable =
- function JpegStream_isNativelyDecodable(xref, res) {
+ function JpegStream_isNativelyDecodable(xref, res) {
var cs = ColorSpace.parse(this.dict.get('ColorSpace', 'CS'), xref, res);
var numComps = cs.numComps;
- return numComps == 1 || numComps == 3;
+ return numComps === 1 || numComps === 3;
};
return JpegStream;
@@ -33256,18 +31949,28 @@ var JpegStream = (function JpegStreamClosure() {
* the stream behaves like all the other DecodeStreams.
*/
var JpxStream = (function JpxStreamClosure() {
- function JpxStream(bytes, dict) {
+ function JpxStream(stream, maybeLength, dict) {
+ this.stream = stream;
+ this.maybeLength = maybeLength;
this.dict = dict;
- this.bytes = bytes;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
JpxStream.prototype = Object.create(DecodeStream.prototype);
+ Object.defineProperty(JpxStream.prototype, 'bytes', {
+ get: function JpxStream_bytes() {
+ // If this.maybeLength is null, we'll get the entire stream.
+ return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
+ },
+ configurable: true
+ });
+
JpxStream.prototype.ensureBuffer = function JpxStream_ensureBuffer(req) {
- if (this.bufferLength)
+ if (this.bufferLength) {
return;
+ }
var jpxImage = new JpxImage();
jpxImage.parse(this.bytes);
@@ -33275,75 +31978,35 @@ var JpxStream = (function JpxStreamClosure() {
var width = jpxImage.width;
var height = jpxImage.height;
var componentsCount = jpxImage.componentsCount;
- if (componentsCount != 1 && componentsCount != 3 && componentsCount != 4)
- error('JPX with ' + componentsCount + ' components is not supported');
+ var tileCount = jpxImage.tiles.length;
+ if (tileCount === 1) {
+ this.buffer = jpxImage.tiles[0].items;
+ } else {
+ var data = new Uint8Array(width * height * componentsCount);
- var data = new Uint8Array(width * height * componentsCount);
+ for (var k = 0; k < tileCount; k++) {
+ var tileComponents = jpxImage.tiles[k];
+ var tileWidth = tileComponents.width;
+ var tileHeight = tileComponents.height;
+ var tileLeft = tileComponents.left;
+ var tileTop = tileComponents.top;
- for (var k = 0, kk = jpxImage.tiles.length; k < kk; k++) {
- var tileCompoments = jpxImage.tiles[k];
- var tileWidth = tileCompoments[0].width;
- var tileHeight = tileCompoments[0].height;
- var tileLeft = tileCompoments[0].left;
- var tileTop = tileCompoments[0].top;
+ var src = tileComponents.items;
+ var srcPosition = 0;
+ var dataPosition = (width * tileTop + tileLeft) * componentsCount;
+ var imgRowSize = width * componentsCount;
+ var tileRowSize = tileWidth * componentsCount;
- var dataPosition, sourcePosition, data0, data1, data2, data3, rowFeed;
- switch (componentsCount) {
- case 1:
- data0 = tileCompoments[0].items;
-
- dataPosition = width * tileTop + tileLeft;
- rowFeed = width - tileWidth;
- sourcePosition = 0;
- for (var j = 0; j < tileHeight; j++) {
- for (var i = 0; i < tileWidth; i++)
- data[dataPosition++] = data0[sourcePosition++];
- dataPosition += rowFeed;
- }
- break;
- case 3:
- data0 = tileCompoments[0].items;
- data1 = tileCompoments[1].items;
- data2 = tileCompoments[2].items;
-
- dataPosition = (width * tileTop + tileLeft) * 3;
- rowFeed = (width - tileWidth) * 3;
- sourcePosition = 0;
- for (var j = 0; j < tileHeight; j++) {
- for (var i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition];
- data[dataPosition++] = data1[sourcePosition];
- data[dataPosition++] = data2[sourcePosition];
- sourcePosition++;
- }
- dataPosition += rowFeed;
- }
- break;
- case 4:
- data0 = tileCompoments[0].items;
- data1 = tileCompoments[1].items;
- data2 = tileCompoments[2].items;
- data3 = tileCompoments[3].items;
-
- dataPosition = (width * tileTop + tileLeft) * 4;
- rowFeed = (width - tileWidth) * 4;
- sourcePosition = 0;
- for (var j = 0; j < tileHeight; j++) {
- for (var i = 0; i < tileWidth; i++) {
- data[dataPosition++] = data0[sourcePosition];
- data[dataPosition++] = data1[sourcePosition];
- data[dataPosition++] = data2[sourcePosition];
- data[dataPosition++] = data3[sourcePosition];
- sourcePosition++;
- }
- dataPosition += rowFeed;
- }
- break;
+ for (var j = 0; j < tileHeight; j++) {
+ var rowBytes = src.subarray(srcPosition, srcPosition + tileRowSize);
+ data.set(rowBytes, dataPosition);
+ srcPosition += tileRowSize;
+ dataPosition += imgRowSize;
+ }
}
+ this.buffer = data;
}
-
- this.buffer = data;
- this.bufferLength = data.length;
+ this.bufferLength = this.buffer.length;
this.eof = true;
};
@@ -33355,22 +32018,33 @@ var JpxStream = (function JpxStreamClosure() {
* the stream behaves like all the other DecodeStreams.
*/
var Jbig2Stream = (function Jbig2StreamClosure() {
- function Jbig2Stream(bytes, dict) {
+ function Jbig2Stream(stream, maybeLength, dict) {
+ this.stream = stream;
+ this.maybeLength = maybeLength;
this.dict = dict;
- this.bytes = bytes;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
Jbig2Stream.prototype = Object.create(DecodeStream.prototype);
+ Object.defineProperty(Jbig2Stream.prototype, 'bytes', {
+ get: function Jbig2Stream_bytes() {
+ // If this.maybeLength is null, we'll get the entire stream.
+ return shadow(this, 'bytes', this.stream.getBytes(this.maybeLength));
+ },
+ configurable: true
+ });
+
Jbig2Stream.prototype.ensureBuffer = function Jbig2Stream_ensureBuffer(req) {
- if (this.bufferLength)
+ if (this.bufferLength) {
return;
+ }
var jbig2Image = new Jbig2Image();
- var chunks = [], decodeParams = this.dict.get('DecodeParms');
+ var chunks = [], xref = this.dict.xref;
+ var decodeParams = xref.fetchIfRef(this.dict.get('DecodeParms'));
// According to the PDF specification, DecodeParms can be either
// a dictionary, or an array whose elements are dictionaries.
@@ -33379,7 +32053,7 @@ var Jbig2Stream = (function Jbig2StreamClosure() {
warn('JBIG2 - \'DecodeParms\' array with multiple elements ' +
'not supported.');
}
- decodeParams = decodeParams[0];
+ decodeParams = xref.fetchIfRef(decodeParams[0]);
}
if (decodeParams && decodeParams.has('JBIG2Globals')) {
var globalsStream = decodeParams.get('JBIG2Globals');
@@ -33391,8 +32065,9 @@ var Jbig2Stream = (function Jbig2StreamClosure() {
var dataLength = data.length;
// JBIG2 had black as 1 and white as 0, inverting the colors
- for (var i = 0; i < dataLength; i++)
+ for (var i = 0; i < dataLength; i++) {
data[i] ^= 0xFF;
+ }
this.buffer = data;
this.bufferLength = dataLength;
@@ -33403,14 +32078,14 @@ var Jbig2Stream = (function Jbig2StreamClosure() {
})();
var DecryptStream = (function DecryptStreamClosure() {
- function DecryptStream(str, decrypt) {
+ function DecryptStream(str, maybeLength, decrypt) {
this.str = str;
this.dict = str.dict;
this.decrypt = decrypt;
this.nextChunk = null;
this.initialized = false;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
var chunkSize = 512;
@@ -33438,8 +32113,9 @@ var DecryptStream = (function DecryptStreamClosure() {
var bufferLength = this.bufferLength;
var i, n = chunk.length;
var buffer = this.ensureBuffer(bufferLength + n);
- for (i = 0; i < n; i++)
+ for (i = 0; i < n; i++) {
buffer[bufferLength++] = chunk[i];
+ }
this.bufferLength = bufferLength;
};
@@ -33447,12 +32123,17 @@ var DecryptStream = (function DecryptStreamClosure() {
})();
var Ascii85Stream = (function Ascii85StreamClosure() {
- function Ascii85Stream(str) {
+ function Ascii85Stream(str, maybeLength) {
this.str = str;
this.dict = str.dict;
this.input = new Uint8Array(5);
- DecodeStream.call(this);
+ // Most streams increase in size when decoded, but Ascii85 streams
+ // typically shrink by ~20%.
+ if (maybeLength) {
+ maybeLength = 0.8 * maybeLength;
+ }
+ DecodeStream.call(this, maybeLength);
}
Ascii85Stream.prototype = Object.create(DecodeStream.prototype);
@@ -33475,17 +32156,19 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
}
var bufferLength = this.bufferLength, buffer;
+ var i;
// special code for z
- if (c == Z_LOWER_CHAR) {
+ if (c === Z_LOWER_CHAR) {
buffer = this.ensureBuffer(bufferLength + 4);
- for (var i = 0; i < 4; ++i)
+ for (i = 0; i < 4; ++i) {
buffer[bufferLength + i] = 0;
+ }
this.bufferLength += 4;
} else {
var input = this.input;
input[0] = c;
- for (var i = 1; i < 5; ++i) {
+ for (i = 1; i < 5; ++i) {
c = str.getByte();
while (Lexer.isSpace(c)) {
c = str.getByte();
@@ -33493,23 +32176,26 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
input[i] = c;
- if (c === EOF || c == TILDA_CHAR)
+ if (c === EOF || c === TILDA_CHAR) {
break;
+ }
}
buffer = this.ensureBuffer(bufferLength + i - 1);
this.bufferLength += i - 1;
// partial ending;
if (i < 5) {
- for (; i < 5; ++i)
+ for (; i < 5; ++i) {
input[i] = 0x21 + 84;
+ }
this.eof = true;
}
var t = 0;
- for (var i = 0; i < 5; ++i)
+ for (i = 0; i < 5; ++i) {
t = t * 85 + (input[i] - 0x21);
+ }
- for (var i = 3; i >= 0; --i) {
+ for (i = 3; i >= 0; --i) {
buffer[bufferLength + i] = t & 0xFF;
t >>= 8;
}
@@ -33520,13 +32206,18 @@ var Ascii85Stream = (function Ascii85StreamClosure() {
})();
var AsciiHexStream = (function AsciiHexStreamClosure() {
- function AsciiHexStream(str) {
+ function AsciiHexStream(str, maybeLength) {
this.str = str;
this.dict = str.dict;
this.firstDigit = -1;
- DecodeStream.call(this);
+ // Most streams increase in size when decoded, but AsciiHex streams shrink
+ // by 50%.
+ if (maybeLength) {
+ maybeLength = 0.5 * maybeLength;
+ }
+ DecodeStream.call(this, maybeLength);
}
AsciiHexStream.prototype = Object.create(DecodeStream.prototype);
@@ -33577,11 +32268,11 @@ var AsciiHexStream = (function AsciiHexStreamClosure() {
})();
var RunLengthStream = (function RunLengthStreamClosure() {
- function RunLengthStream(str) {
+ function RunLengthStream(str, maybeLength) {
this.str = str;
this.dict = str.dict;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
RunLengthStream.prototype = Object.create(DecodeStream.prototype);
@@ -33592,16 +32283,17 @@ var RunLengthStream = (function RunLengthStreamClosure() {
// (in addition to the second byte from the header), n = 129 through 255 -
// duplicate the second byte from the header (257 - n) times, n = 128 - end.
var repeatHeader = this.str.getBytes(2);
- if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] == 128) {
+ if (!repeatHeader || repeatHeader.length < 2 || repeatHeader[0] === 128) {
this.eof = true;
return;
}
+ var buffer;
var bufferLength = this.bufferLength;
var n = repeatHeader[0];
if (n < 128) {
// copy n bytes
- var buffer = this.ensureBuffer(bufferLength + n + 1);
+ buffer = this.ensureBuffer(bufferLength + n + 1);
buffer[bufferLength++] = repeatHeader[1];
if (n > 0) {
var source = this.str.getBytes(n);
@@ -33611,9 +32303,10 @@ var RunLengthStream = (function RunLengthStreamClosure() {
} else {
n = 257 - n;
var b = repeatHeader[1];
- var buffer = this.ensureBuffer(bufferLength + n + 1);
- for (var i = 0; i < n; i++)
+ buffer = this.ensureBuffer(bufferLength + n + 1);
+ for (var i = 0; i < n; i++) {
buffer[bufferLength++] = b;
+ }
}
this.bufferLength = bufferLength;
};
@@ -34049,11 +32742,11 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
[2, 2], [2, 2], [2, 2], [2, 2]
];
- function CCITTFaxStream(str, params) {
+ function CCITTFaxStream(str, maybeLength, params) {
this.str = str;
this.dict = str.dict;
- params = params || new Dict();
+ params = params || Dict.empty;
this.encoding = params.get('K') || 0;
this.eoline = params.get('EndOfLine') || false;
@@ -34061,8 +32754,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.columns = params.get('Columns') || 1728;
this.rows = params.get('Rows') || 0;
var eoblock = params.get('EndOfBlock');
- if (eoblock === null || eoblock === undefined)
+ if (eoblock === null || eoblock === undefined) {
eoblock = true;
+ }
this.eoblock = eoblock;
this.black = params.get('BlackIs1') || false;
@@ -34077,13 +32771,12 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.inputBits = 0;
this.inputBuf = 0;
this.outputBits = 0;
- this.buf = EOF;
var code1;
while ((code1 = this.lookBits(12)) === 0) {
this.eatBits(1);
}
- if (code1 == 1) {
+ if (code1 === 1) {
this.eatBits(12);
}
if (this.encoding > 0) {
@@ -34091,7 +32784,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.eatBits(1);
}
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
CCITTFaxStream.prototype = Object.create(DecodeStream.prototype);
@@ -34099,14 +32792,13 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
CCITTFaxStream.prototype.readBlock = function CCITTFaxStream_readBlock() {
while (!this.eof) {
var c = this.lookChar();
- this.buf = EOF;
this.ensureBuffer(this.bufferLength + 1);
this.buffer[this.bufferLength++] = c;
}
};
CCITTFaxStream.prototype.addPixels =
- function ccittFaxStreamAddPixels(a1, blackPixels) {
+ function ccittFaxStreamAddPixels(a1, blackPixels) {
var codingLine = this.codingLine;
var codingPos = this.codingPos;
@@ -34126,7 +32818,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.addPixelsNeg =
- function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
+ function ccittFaxStreamAddPixelsNeg(a1, blackPixels) {
var codingLine = this.codingLine;
var codingPos = this.codingPos;
@@ -34136,8 +32828,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.err = true;
a1 = this.columns;
}
- if ((codingPos & 1) ^ blackPixels)
+ if ((codingPos & 1) ^ blackPixels) {
++codingPos;
+ }
codingLine[codingPos] = a1;
} else if (a1 < codingLine[codingPos]) {
@@ -34146,8 +32839,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.err = true;
a1 = 0;
}
- while (codingPos > 0 && a1 < codingLine[codingPos - 1])
+ while (codingPos > 0 && a1 < codingLine[codingPos - 1]) {
--codingPos;
+ }
codingLine[codingPos] = a1;
}
@@ -34155,26 +32849,23 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.lookChar = function CCITTFaxStream_lookChar() {
- if (this.buf != EOF)
- return this.buf;
-
var refLine = this.refLine;
var codingLine = this.codingLine;
var columns = this.columns;
- var refPos, blackPixels, bits;
+ var refPos, blackPixels, bits, i;
if (this.outputBits === 0) {
- if (this.eof)
+ if (this.eof) {
return null;
-
+ }
this.err = false;
var code1, code2, code3;
if (this.nextLine2D) {
- for (var i = 0; codingLine[i] < columns; ++i)
+ for (i = 0; codingLine[i] < columns; ++i) {
refLine[i] = codingLine[i];
-
+ }
refLine[i++] = columns;
refLine[i] = columns;
codingLine[0] = 0;
@@ -34187,8 +32878,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
switch (code1) {
case twoDimPass:
this.addPixels(refLine[refPos + 1], blackPixels);
- if (refLine[refPos + 1] < columns)
+ if (refLine[refPos + 1] < columns) {
refPos += 2;
+ }
break;
case twoDimHoriz:
code1 = code2 = 0;
@@ -34224,8 +32916,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (codingLine[this.codingPos] < columns) {
++refPos;
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertR2:
@@ -34245,8 +32938,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (codingLine[this.codingPos] < columns) {
++refPos;
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVert0:
@@ -34255,48 +32949,54 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
if (codingLine[this.codingPos] < columns) {
++refPos;
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertL3:
this.addPixelsNeg(refLine[refPos] - 3, blackPixels);
blackPixels ^= 1;
if (codingLine[this.codingPos] < columns) {
- if (refPos > 0)
+ if (refPos > 0) {
--refPos;
- else
+ } else {
++refPos;
+ }
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertL2:
this.addPixelsNeg(refLine[refPos] - 2, blackPixels);
blackPixels ^= 1;
if (codingLine[this.codingPos] < columns) {
- if (refPos > 0)
+ if (refPos > 0) {
--refPos;
- else
+ } else {
++refPos;
+ }
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case twoDimVertL1:
this.addPixelsNeg(refLine[refPos] - 1, blackPixels);
blackPixels ^= 1;
if (codingLine[this.codingPos] < columns) {
- if (refPos > 0)
+ if (refPos > 0) {
--refPos;
- else
+ } else {
++refPos;
-
+ }
while (refLine[refPos] <= codingLine[this.codingPos] &&
- refLine[refPos] < columns)
+ refLine[refPos] < columns) {
refPos += 2;
+ }
}
break;
case EOF:
@@ -34329,45 +33029,54 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
}
- if (this.byteAlign)
- this.inputBits &= ~7;
-
var gotEOL = false;
- if (!this.eoblock && this.row == this.rows - 1) {
+ if (!this.eoblock && this.row === this.rows - 1) {
this.eof = true;
- } else {
+ } else if (this.eoline || !this.byteAlign) {
code1 = this.lookBits(12);
- while (code1 === 0) {
- this.eatBits(1);
- code1 = this.lookBits(12);
+ if (this.eoline) {
+ while (code1 !== EOF && code1 !== 1) {
+ this.eatBits(1);
+ code1 = this.lookBits(12);
+ }
+ } else {
+ while (code1 === 0) {
+ this.eatBits(1);
+ code1 = this.lookBits(12);
+ }
}
- if (code1 == 1) {
+ if (code1 === 1) {
this.eatBits(12);
gotEOL = true;
- } else if (code1 == EOF) {
+ } else if (code1 === EOF) {
this.eof = true;
}
}
+ if (this.byteAlign && !gotEOL) {
+ this.inputBits &= ~7;
+ }
+
if (!this.eof && this.encoding > 0) {
this.nextLine2D = !this.lookBits(1);
this.eatBits(1);
}
- if (this.eoblock && gotEOL) {
+ if (this.eoblock && gotEOL && this.byteAlign) {
code1 = this.lookBits(12);
- if (code1 == 1) {
+ if (code1 === 1) {
this.eatBits(12);
if (this.encoding > 0) {
this.lookBits(1);
this.eatBits(1);
}
if (this.encoding >= 0) {
- for (var i = 0; i < 4; ++i) {
+ for (i = 0; i < 4; ++i) {
code1 = this.lookBits(12);
- if (code1 != 1)
+ if (code1 !== 1) {
info('bad rtc code: ' + code1);
+ }
this.eatBits(12);
if (this.encoding > 0) {
this.lookBits(1);
@@ -34380,11 +33089,11 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
} else if (this.err && this.eoline) {
while (true) {
code1 = this.lookBits(13);
- if (code1 == EOF) {
+ if (code1 === EOF) {
this.eof = true;
return null;
}
- if ((code1 >> 1) == 1) {
+ if ((code1 >> 1) === 1) {
break;
}
this.eatBits(1);
@@ -34396,15 +33105,17 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
}
- if (codingLine[0] > 0)
+ if (codingLine[0] > 0) {
this.outputBits = codingLine[this.codingPos = 0];
- else
+ } else {
this.outputBits = codingLine[this.codingPos = 1];
+ }
this.row++;
}
+ var c;
if (this.outputBits >= 8) {
- this.buf = (this.codingPos & 1) ? 0 : 0xFF;
+ c = (this.codingPos & 1) ? 0 : 0xFF;
this.outputBits -= 8;
if (this.outputBits === 0 && codingLine[this.codingPos] < columns) {
this.codingPos++;
@@ -34412,20 +33123,20 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
codingLine[this.codingPos - 1]);
}
} else {
- var bits = 8;
- this.buf = 0;
+ bits = 8;
+ c = 0;
do {
if (this.outputBits > bits) {
- this.buf <<= bits;
+ c <<= bits;
if (!(this.codingPos & 1)) {
- this.buf |= 0xFF >> (8 - bits);
+ c |= 0xFF >> (8 - bits);
}
this.outputBits -= bits;
bits = 0;
} else {
- this.buf <<= this.outputBits;
+ c <<= this.outputBits;
if (!(this.codingPos & 1)) {
- this.buf |= 0xFF >> (8 - this.outputBits);
+ c |= 0xFF >> (8 - this.outputBits);
}
bits -= this.outputBits;
this.outputBits = 0;
@@ -34434,16 +33145,16 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
this.outputBits = (codingLine[this.codingPos] -
codingLine[this.codingPos - 1]);
} else if (bits > 0) {
- this.buf <<= bits;
+ c <<= bits;
bits = 0;
}
}
} while (bits);
}
if (this.black) {
- this.buf ^= 0xFF;
+ c ^= 0xFF;
}
- return this.buf;
+ return c;
};
// This functions returns the code found from the table.
@@ -34453,18 +33164,20 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
// returned. The second array element is the actual code. The third array
// element indicates whether EOF was reached.
CCITTFaxStream.prototype.findTableCode =
- function ccittFaxStreamFindTableCode(start, end, table, limit) {
+ function ccittFaxStreamFindTableCode(start, end, table, limit) {
var limitValue = limit || 0;
for (var i = start; i <= end; ++i) {
var code = this.lookBits(i);
- if (code == EOF)
+ if (code === EOF) {
return [true, 1, false];
- if (i < end)
+ }
+ if (i < end) {
code <<= end - i;
+ }
if (!limitValue || code >= limitValue) {
var p = table[code - limitValue];
- if (p[0] == i) {
+ if (p[0] === i) {
this.eatBits(i);
return [true, p[1], true];
}
@@ -34474,7 +33187,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.getTwoDimCode =
- function ccittFaxStreamGetTwoDimCode() {
+ function ccittFaxStreamGetTwoDimCode() {
var code = 0;
var p;
@@ -34487,28 +33200,30 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
} else {
var result = this.findTableCode(1, 7, twoDimTable);
- if (result[0] && result[2])
+ if (result[0] && result[2]) {
return result[1];
+ }
}
info('Bad two dim code');
return EOF;
};
CCITTFaxStream.prototype.getWhiteCode =
- function ccittFaxStreamGetWhiteCode() {
+ function ccittFaxStreamGetWhiteCode() {
var code = 0;
var p;
- var n;
if (this.eoblock) {
code = this.lookBits(12);
- if (code == EOF)
+ if (code === EOF) {
return 1;
+ }
- if ((code >> 5) === 0)
+ if ((code >> 5) === 0) {
p = whiteTable1[code];
- else
+ } else {
p = whiteTable2[code >> 3];
+ }
if (p[0] > 0) {
this.eatBits(p[0]);
@@ -34516,12 +33231,14 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
} else {
var result = this.findTableCode(1, 9, whiteTable2);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
result = this.findTableCode(11, 12, whiteTable1);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
}
info('bad white code');
this.eatBits(1);
@@ -34529,19 +33246,21 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.getBlackCode =
- function ccittFaxStreamGetBlackCode() {
+ function ccittFaxStreamGetBlackCode() {
var code, p;
if (this.eoblock) {
code = this.lookBits(13);
- if (code == EOF)
+ if (code === EOF) {
return 1;
- if ((code >> 7) === 0)
+ }
+ if ((code >> 7) === 0) {
p = blackTable1[code];
- else if ((code >> 9) === 0 && (code >> 7) !== 0)
+ } else if ((code >> 9) === 0 && (code >> 7) !== 0) {
p = blackTable2[(code >> 1) - 64];
- else
+ } else {
p = blackTable3[code >> 7];
+ }
if (p[0] > 0) {
this.eatBits(p[0]);
@@ -34549,16 +33268,19 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
}
} else {
var result = this.findTableCode(2, 6, blackTable3);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
result = this.findTableCode(7, 12, blackTable2, 64);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
result = this.findTableCode(10, 13, blackTable1);
- if (result[0])
+ if (result[0]) {
return result[1];
+ }
}
info('bad black code');
this.eatBits(1);
@@ -34569,8 +33291,9 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
var c;
while (this.inputBits < n) {
if ((c = this.str.getByte()) === -1) {
- if (this.inputBits === 0)
+ if (this.inputBits === 0) {
return EOF;
+ }
return ((this.inputBuf << (n - this.inputBits)) &
(0xFFFF >> (16 - n)));
}
@@ -34581,15 +33304,16 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
};
CCITTFaxStream.prototype.eatBits = function CCITTFaxStream_eatBits(n) {
- if ((this.inputBits -= n) < 0)
+ if ((this.inputBits -= n) < 0) {
this.inputBits = 0;
+ }
};
return CCITTFaxStream;
})();
var LZWStream = (function LZWStreamClosure() {
- function LZWStream(str, earlyChange) {
+ function LZWStream(str, maybeLength, earlyChange) {
this.str = str;
this.dict = str.dict;
this.cachedData = 0;
@@ -34612,7 +33336,7 @@ var LZWStream = (function LZWStreamClosure() {
}
this.lzwState = lzwState;
- DecodeStream.call(this);
+ DecodeStream.call(this, maybeLength);
}
LZWStream.prototype = Object.create(DecodeStream.prototype);
@@ -34641,8 +33365,9 @@ var LZWStream = (function LZWStreamClosure() {
var i, j, q;
var lzwState = this.lzwState;
- if (!lzwState)
+ if (!lzwState) {
return; // eof was found
+ }
var earlyChange = lzwState.earlyChange;
var nextCode = lzwState.nextCode;
@@ -34674,7 +33399,7 @@ var LZWStream = (function LZWStreamClosure() {
} else {
currentSequence[currentSequenceLength++] = currentSequence[0];
}
- } else if (code == 256) {
+ } else if (code === 256) {
codeLength = 9;
nextCode = 258;
currentSequenceLength = 0;
@@ -34703,8 +33428,9 @@ var LZWStream = (function LZWStreamClosure() {
} while (estimatedDecodedSize < decodedLength);
buffer = this.ensureBuffer(this.bufferLength + estimatedDecodedSize);
}
- for (j = 0; j < currentSequenceLength; j++)
+ for (j = 0; j < currentSequenceLength; j++) {
buffer[currentBufferLength++] = currentSequence[j];
+ }
}
lzwState.nextCode = nextCode;
lzwState.codeLength = codeLength;
@@ -34733,75 +33459,66 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var pdfManager;
function loadDocument(recoveryMode) {
- var loadDocumentPromise = new LegacyPromise();
+ var loadDocumentCapability = createPromiseCapability();
var parseSuccess = function parseSuccess() {
- var numPagesPromise = pdfManager.ensureModel('numPages');
- var fingerprintPromise = pdfManager.ensureModel('fingerprint');
- var outlinePromise = pdfManager.ensureCatalog('documentOutline');
- var infoPromise = pdfManager.ensureModel('documentInfo');
- var metadataPromise = pdfManager.ensureCatalog('metadata');
+ var numPagesPromise = pdfManager.ensureDoc('numPages');
+ var fingerprintPromise = pdfManager.ensureDoc('fingerprint');
var encryptedPromise = pdfManager.ensureXRef('encrypt');
- var javaScriptPromise = pdfManager.ensureCatalog('javaScript');
- Promise.all([numPagesPromise, fingerprintPromise, outlinePromise,
- infoPromise, metadataPromise, encryptedPromise,
- javaScriptPromise]).then(
- function onDocReady(results) {
-
+ Promise.all([numPagesPromise, fingerprintPromise,
+ encryptedPromise]).then(function onDocReady(results) {
var doc = {
numPages: results[0],
fingerprint: results[1],
- outline: results[2],
- info: results[3],
- metadata: results[4],
- encrypted: !!results[5],
- javaScript: results[6]
+ encrypted: !!results[2],
};
- loadDocumentPromise.resolve(doc);
+ loadDocumentCapability.resolve(doc);
},
parseFailure);
};
var parseFailure = function parseFailure(e) {
- loadDocumentPromise.reject(e);
+ loadDocumentCapability.reject(e);
};
- pdfManager.ensureModel('checkHeader', []).then(function() {
- pdfManager.ensureModel('parseStartXRef', []).then(function() {
- pdfManager.ensureModel('parse', [recoveryMode]).then(
- parseSuccess, parseFailure);
+ pdfManager.ensureDoc('checkHeader', []).then(function() {
+ pdfManager.ensureDoc('parseStartXRef', []).then(function() {
+ pdfManager.ensureDoc('parse', [recoveryMode]).then(
+ parseSuccess, parseFailure);
}, parseFailure);
}, parseFailure);
- return loadDocumentPromise;
+ return loadDocumentCapability.promise;
}
function getPdfManager(data) {
- var pdfManagerPromise = new LegacyPromise();
+ var pdfManagerCapability = createPromiseCapability();
var source = data.source;
var disableRange = data.disableRange;
if (source.data) {
try {
pdfManager = new LocalPdfManager(source.data, source.password);
- pdfManagerPromise.resolve();
+ pdfManagerCapability.resolve();
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
- return pdfManagerPromise;
+ return pdfManagerCapability.promise;
} else if (source.chunkedViewerLoading) {
try {
pdfManager = new NetworkPdfManager(source, handler);
- pdfManagerPromise.resolve();
+ pdfManagerCapability.resolve();
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
- return pdfManagerPromise;
+ return pdfManagerCapability.promise;
}
var networkManager = new NetworkManager(source.url, {
- httpHeaders: source.httpHeaders
+ httpHeaders: source.httpHeaders,
+ withCredentials: source.withCredentials
});
+ var cachedChunks = [];
var fullRequestXhrId = networkManager.requestFull({
onHeadersReceived: function onHeadersReceived() {
if (disableRange) {
@@ -34824,53 +33541,102 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
if (!isInt(length)) {
return;
}
-
- // NOTE: by cancelling the full request, and then issuing range
- // requests, there will be an issue for sites where you can only
- // request the pdf once. However, if this is the case, then the
- // server should not be returning that it can support range requests.
- networkManager.abortRequest(fullRequestXhrId);
-
source.length = length;
+ if (length <= 2 * RANGE_CHUNK_SIZE) {
+ // The file size is smaller than the size of two chunks, so it does
+ // not make any sense to abort the request and retry with a range
+ // request.
+ return;
+ }
+
+ if (networkManager.isStreamingRequest(fullRequestXhrId)) {
+ // We can continue fetching when progressive loading is enabled,
+ // and we don't need the autoFetch feature.
+ source.disableAutoFetch = true;
+ } else {
+ // NOTE: by cancelling the full request, and then issuing range
+ // requests, there will be an issue for sites where you can only
+ // request the pdf once. However, if this is the case, then the
+ // server should not be returning that it can support range
+ // requests.
+ networkManager.abortRequest(fullRequestXhrId);
+ }
+
try {
pdfManager = new NetworkPdfManager(source, handler);
- pdfManagerPromise.resolve(pdfManager);
+ pdfManagerCapability.resolve(pdfManager);
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
},
+ onProgressiveData: source.disableStream ? null :
+ function onProgressiveData(chunk) {
+ if (!pdfManager) {
+ cachedChunks.push(chunk);
+ return;
+ }
+ pdfManager.sendProgressiveData(chunk);
+ },
+
onDone: function onDone(args) {
+ if (pdfManager) {
+ return; // already processed
+ }
+
+ var pdfFile;
+ if (args === null) {
+ // TODO add some streaming manager, e.g. for unknown length files.
+ // The data was returned in the onProgressiveData, combining...
+ var pdfFileLength = 0, pos = 0;
+ cachedChunks.forEach(function (chunk) {
+ pdfFileLength += chunk.byteLength;
+ });
+ if (source.length && pdfFileLength !== source.length) {
+ warn('reported HTTP length is different from actual');
+ }
+ var pdfFileArray = new Uint8Array(pdfFileLength);
+ cachedChunks.forEach(function (chunk) {
+ pdfFileArray.set(new Uint8Array(chunk), pos);
+ pos += chunk.byteLength;
+ });
+ pdfFile = pdfFileArray.buffer;
+ } else {
+ pdfFile = args.chunk;
+ }
+
// the data is array, instantiating directly from it
try {
- pdfManager = new LocalPdfManager(args.chunk, source.password);
- pdfManagerPromise.resolve();
+ pdfManager = new LocalPdfManager(pdfFile, source.password);
+ pdfManagerCapability.resolve();
} catch (ex) {
- pdfManagerPromise.reject(ex);
+ pdfManagerCapability.reject(ex);
}
},
onError: function onError(status) {
- if (status == 404) {
- var exception = new MissingPDFException( 'Missing PDF "' +
- source.url + '".');
- handler.send('MissingPDF', { exception: exception });
+ var exception;
+ if (status === 404) {
+ exception = new MissingPDFException('Missing PDF "' +
+ source.url + '".');
+ handler.send('MissingPDF', exception);
} else {
- handler.send('DocError', 'Unexpected server response (' +
- status + ') while retrieving PDF "' +
- source.url + '".');
+ exception = new UnexpectedResponseException(
+ 'Unexpected server response (' + status +
+ ') while retrieving PDF "' + source.url + '".', status);
+ handler.send('UnexpectedResponse', exception);
}
},
onProgress: function onProgress(evt) {
handler.send('DocProgress', {
loaded: evt.loaded,
- total: evt.lengthComputable ? evt.total : void(0)
+ total: evt.lengthComputable ? evt.total : source.length
});
}
});
- return pdfManagerPromise;
+ return pdfManagerCapability.promise;
}
handler.on('test', function wphSetupTest(data) {
@@ -34910,44 +33676,44 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var onFailure = function(e) {
if (e instanceof PasswordException) {
if (e.code === PasswordResponses.NEED_PASSWORD) {
- handler.send('NeedPassword', {
- exception: e
- });
+ handler.send('NeedPassword', e);
} else if (e.code === PasswordResponses.INCORRECT_PASSWORD) {
- handler.send('IncorrectPassword', {
- exception: e
- });
+ handler.send('IncorrectPassword', e);
}
} else if (e instanceof InvalidPDFException) {
- handler.send('InvalidPDF', {
- exception: e
- });
+ handler.send('InvalidPDF', e);
} else if (e instanceof MissingPDFException) {
- handler.send('MissingPDF', {
- exception: e
- });
+ handler.send('MissingPDF', e);
+ } else if (e instanceof UnexpectedResponseException) {
+ handler.send('UnexpectedResponse', e);
} else {
- handler.send('UnknownError', {
- exception: new UnknownErrorException(e.message, e.toString())
- });
+ handler.send('UnknownError',
+ new UnknownErrorException(e.message, e.toString()));
}
};
PDFJS.maxImageSize = data.maxImageSize === undefined ?
-1 : data.maxImageSize;
PDFJS.disableFontFace = data.disableFontFace;
+ PDFJS.disableCreateObjectURL = data.disableCreateObjectURL;
PDFJS.verbosity = data.verbosity;
+ PDFJS.cMapUrl = data.cMapUrl === undefined ?
+ null : data.cMapUrl;
+ PDFJS.cMapPacked = data.cMapPacked === true;
- getPdfManager(data).then(function pdfManagerReady() {
+ getPdfManager(data).then(function () {
+ handler.send('PDFManagerReady', null);
+ pdfManager.onLoadedStream().then(function(stream) {
+ handler.send('DataLoaded', { length: stream.bytes.byteLength });
+ });
+ }).then(function pdfManagerReady() {
loadDocument(false).then(onSuccess, function loadFailure(ex) {
// Try again with recoveryMode == true
if (!(ex instanceof XRefParseException)) {
if (ex instanceof PasswordException) {
// after password exception prepare to receive a new password
// to repeat loading
- pdfManager.passwordChangedPromise =
- new LegacyPromise();
- pdfManager.passwordChangedPromise.then(pdfManagerReady);
+ pdfManager.passwordChanged().then(pdfManagerReady);
}
onFailure(ex);
@@ -34962,69 +33728,86 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
}, onFailure);
});
- handler.on('GetPageRequest', function wphSetupGetPage(data) {
- var pageIndex = data.pageIndex;
- pdfManager.getPage(pageIndex).then(function(page) {
+ handler.on('GetPage', function wphSetupGetPage(data) {
+ return pdfManager.getPage(data.pageIndex).then(function(page) {
var rotatePromise = pdfManager.ensure(page, 'rotate');
var refPromise = pdfManager.ensure(page, 'ref');
var viewPromise = pdfManager.ensure(page, 'view');
- Promise.all([rotatePromise, refPromise, viewPromise]).then(
+ return Promise.all([rotatePromise, refPromise, viewPromise]).then(
function(results) {
- var page = {
- pageIndex: data.pageIndex,
+ return {
rotate: results[0],
ref: results[1],
view: results[2]
};
-
- handler.send('GetPage', { pageInfo: page });
});
});
});
- handler.on('GetPageIndex', function wphSetupGetPageIndex(data, deferred) {
+ handler.on('GetPageIndex', function wphSetupGetPageIndex(data) {
var ref = new Ref(data.ref.num, data.ref.gen);
- pdfManager.pdfModel.catalog.getPageIndex(ref).then(function (pageIndex) {
- deferred.resolve(pageIndex);
- }, deferred.reject);
+ var catalog = pdfManager.pdfDocument.catalog;
+ return catalog.getPageIndex(ref);
});
handler.on('GetDestinations',
- function wphSetupGetDestinations(data, deferred) {
- pdfManager.ensureCatalog('destinations').then(function(destinations) {
- deferred.resolve(destinations);
- });
+ function wphSetupGetDestinations(data) {
+ return pdfManager.ensureCatalog('destinations');
}
);
- handler.on('GetData', function wphSetupGetData(data, deferred) {
+ handler.on('GetDestination',
+ function wphSetupGetDestination(data) {
+ return pdfManager.ensureCatalog('getDestination', [ data.id ]);
+ }
+ );
+
+ handler.on('GetAttachments',
+ function wphSetupGetAttachments(data) {
+ return pdfManager.ensureCatalog('attachments');
+ }
+ );
+
+ handler.on('GetJavaScript',
+ function wphSetupGetJavaScript(data) {
+ return pdfManager.ensureCatalog('javaScript');
+ }
+ );
+
+ handler.on('GetOutline',
+ function wphSetupGetOutline(data) {
+ return pdfManager.ensureCatalog('documentOutline');
+ }
+ );
+
+ handler.on('GetMetadata',
+ function wphSetupGetMetadata(data) {
+ return Promise.all([pdfManager.ensureDoc('documentInfo'),
+ pdfManager.ensureCatalog('metadata')]);
+ }
+ );
+
+ handler.on('GetData', function wphSetupGetData(data) {
pdfManager.requestLoadedStream();
- pdfManager.onLoadedStream().then(function(stream) {
- deferred.resolve(stream.bytes);
+ return pdfManager.onLoadedStream().then(function(stream) {
+ return stream.bytes;
});
});
- handler.on('DataLoaded', function wphSetupDataLoaded(data, deferred) {
- pdfManager.onLoadedStream().then(function(stream) {
- deferred.resolve({ length: stream.bytes.byteLength });
- });
- });
+ handler.on('GetStats',
+ function wphSetupGetStats(data) {
+ return pdfManager.pdfDocument.xref.stats;
+ }
+ );
handler.on('UpdatePassword', function wphSetupUpdatePassword(data) {
pdfManager.updatePassword(data);
});
- handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
- pdfManager.getPage(data.pageIndex).then(function(page) {
- pdfManager.ensure(page, 'getAnnotationsData', []).then(
- function(annotationsData) {
- handler.send('GetAnnotations', {
- pageIndex: data.pageIndex,
- annotations: annotationsData
- });
- }
- );
+ handler.on('GetAnnotations', function wphSetupGetAnnotations(data) {
+ return pdfManager.getPage(data.pageIndex).then(function(page) {
+ return pdfManager.ensure(page, 'getAnnotationsData', []);
});
});
@@ -35034,15 +33817,15 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
var pageNum = data.pageIndex + 1;
var start = Date.now();
// Pre compile the pdf page and fetch the fonts/images.
- page.getOperatorList(handler).then(function(operatorList) {
+ page.getOperatorList(handler, data.intent).then(function(operatorList) {
- log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
- Date.now() - start, operatorList.fnArray.length);
+ info('page=' + pageNum + ' - getOperatorList: time=' +
+ (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
}, function(e) {
var minimumStackMessage =
- 'worker.js: while trying to getPage() and getOperatorList()';
+ 'worker.js: while trying to getPage() and getOperatorList()';
var wrappedException;
@@ -35066,35 +33849,31 @@ var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
handler.send('PageError', {
pageNum: pageNum,
- error: wrappedException
+ error: wrappedException,
+ intent: data.intent
});
});
});
}, this);
- handler.on('GetTextContent', function wphExtractText(data, deferred) {
- pdfManager.getPage(data.pageIndex).then(function(page) {
+ handler.on('GetTextContent', function wphExtractText(data) {
+ return pdfManager.getPage(data.pageIndex).then(function(page) {
var pageNum = data.pageIndex + 1;
var start = Date.now();
- page.extractTextContent().then(function(textContent) {
- deferred.resolve(textContent);
- log('text indexing: page=%d - time=%dms', pageNum,
- Date.now() - start);
- }, function (e) {
- // Skip errored pages
- deferred.reject(e);
+ return page.extractTextContent().then(function(textContent) {
+ info('text indexing: page=' + pageNum + ' - time=' +
+ (Date.now() - start) + 'ms');
+ return textContent;
});
});
});
- handler.on('Cleanup', function wphCleanup(data, deferred) {
- pdfManager.cleanup();
- deferred.resolve(true);
+ handler.on('Cleanup', function wphCleanup(data) {
+ return pdfManager.cleanup();
});
- handler.on('Terminate', function wphTerminate(data, deferred) {
+ handler.on('Terminate', function wphTerminate(data) {
pdfManager.terminate();
- deferred.resolve();
});
}
};
@@ -35126,15 +33905,18 @@ var workerConsole = {
timeEnd: function timeEnd(name) {
var time = consoleTimer[name];
if (!time) {
- error('Unkown timer name ' + name);
+ error('Unknown timer name ' + name);
}
this.log('Timer:', name, Date.now() - time);
}
};
+
// Worker thread?
if (typeof window === 'undefined') {
- globalScope.console = workerConsole;
+ if (!('console' in globalScope)) {
+ globalScope.console = workerConsole;
+ }
// Listen for unsupported features so we can pass them on to the main thread.
PDFJS.UnsupportedManager.listen(function (msg) {
@@ -35149,6 +33931,1188 @@ if (typeof window === 'undefined') {
}
+/* This class implements the QM Coder decoding as defined in
+ * JPEG 2000 Part I Final Committee Draft Version 1.0
+ * Annex C.3 Arithmetic decoding procedure
+ * available at http://www.jpeg.org/public/fcd15444-1.pdf
+ *
+ * The arithmetic decoder is used in conjunction with context models to decode
+ * JPEG2000 and JBIG2 streams.
+ */
+var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
+ // Table C-2
+ var QeTable = [
+ {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
+ {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
+ {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
+ {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
+ {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
+ {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
+ {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
+ {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
+ {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
+ {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
+ {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
+ {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
+ {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
+ {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
+ {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
+ {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
+ {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
+ {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
+ {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
+ {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
+ {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
+ {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
+ {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
+ {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
+ {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
+ {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
+ {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
+ {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
+ {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
+ {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
+ {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
+ {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
+ {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
+ {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
+ {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
+ {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
+ {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
+ {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
+ {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
+ {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
+ {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
+ {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
+ {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
+ {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
+ {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
+ {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
+ {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
+ ];
+
+ // C.3.5 Initialisation of the decoder (INITDEC)
+ function ArithmeticDecoder(data, start, end) {
+ this.data = data;
+ this.bp = start;
+ this.dataEnd = end;
+
+ this.chigh = data[start];
+ this.clow = 0;
+
+ this.byteIn();
+
+ this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
+ this.clow = (this.clow << 7) & 0xFFFF;
+ this.ct -= 7;
+ this.a = 0x8000;
+ }
+
+ ArithmeticDecoder.prototype = {
+ // C.3.4 Compressed data input (BYTEIN)
+ byteIn: function ArithmeticDecoder_byteIn() {
+ var data = this.data;
+ var bp = this.bp;
+ if (data[bp] === 0xFF) {
+ var b1 = data[bp + 1];
+ if (b1 > 0x8F) {
+ this.clow += 0xFF00;
+ this.ct = 8;
+ } else {
+ bp++;
+ this.clow += (data[bp] << 9);
+ this.ct = 7;
+ this.bp = bp;
+ }
+ } else {
+ bp++;
+ this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
+ this.ct = 8;
+ this.bp = bp;
+ }
+ if (this.clow > 0xFFFF) {
+ this.chigh += (this.clow >> 16);
+ this.clow &= 0xFFFF;
+ }
+ },
+ // C.3.2 Decoding a decision (DECODE)
+ readBit: function ArithmeticDecoder_readBit(contexts, pos) {
+ // contexts are packed into 1 byte:
+ // highest 7 bits carry cx.index, lowest bit carries cx.mps
+ var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
+ var qeTableIcx = QeTable[cx_index];
+ var qeIcx = qeTableIcx.qe;
+ var d;
+ var a = this.a - qeIcx;
+
+ if (this.chigh < qeIcx) {
+ // exchangeLps
+ if (a < qeIcx) {
+ a = qeIcx;
+ d = cx_mps;
+ cx_index = qeTableIcx.nmps;
+ } else {
+ a = qeIcx;
+ d = 1 ^ cx_mps;
+ if (qeTableIcx.switchFlag === 1) {
+ cx_mps = d;
+ }
+ cx_index = qeTableIcx.nlps;
+ }
+ } else {
+ this.chigh -= qeIcx;
+ if ((a & 0x8000) !== 0) {
+ this.a = a;
+ return cx_mps;
+ }
+ // exchangeMps
+ if (a < qeIcx) {
+ d = 1 ^ cx_mps;
+ if (qeTableIcx.switchFlag === 1) {
+ cx_mps = d;
+ }
+ cx_index = qeTableIcx.nlps;
+ } else {
+ d = cx_mps;
+ cx_index = qeTableIcx.nmps;
+ }
+ }
+ // C.3.3 renormD;
+ do {
+ if (this.ct === 0) {
+ this.byteIn();
+ }
+
+ a <<= 1;
+ this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
+ this.clow = (this.clow << 1) & 0xFFFF;
+ this.ct--;
+ } while ((a & 0x8000) === 0);
+ this.a = a;
+
+ contexts[pos] = cx_index << 1 | cx_mps;
+ return d;
+ }
+ };
+
+ return ArithmeticDecoder;
+})();
+
+
+var JpegImage = (function jpegImage() {
+ var dctZigZag = new Uint8Array([
+ 0,
+ 1, 8,
+ 16, 9, 2,
+ 3, 10, 17, 24,
+ 32, 25, 18, 11, 4,
+ 5, 12, 19, 26, 33, 40,
+ 48, 41, 34, 27, 20, 13, 6,
+ 7, 14, 21, 28, 35, 42, 49, 56,
+ 57, 50, 43, 36, 29, 22, 15,
+ 23, 30, 37, 44, 51, 58,
+ 59, 52, 45, 38, 31,
+ 39, 46, 53, 60,
+ 61, 54, 47,
+ 55, 62,
+ 63
+ ]);
+
+ var dctCos1 = 4017; // cos(pi/16)
+ var dctSin1 = 799; // sin(pi/16)
+ var dctCos3 = 3406; // cos(3*pi/16)
+ var dctSin3 = 2276; // sin(3*pi/16)
+ var dctCos6 = 1567; // cos(6*pi/16)
+ var dctSin6 = 3784; // sin(6*pi/16)
+ var dctSqrt2 = 5793; // sqrt(2)
+ var dctSqrt1d2 = 2896; // sqrt(2) / 2
+
+ function constructor() {
+ }
+
+ function buildHuffmanTable(codeLengths, values) {
+ var k = 0, code = [], i, j, length = 16;
+ while (length > 0 && !codeLengths[length - 1]) {
+ length--;
+ }
+ code.push({children: [], index: 0});
+ var p = code[0], q;
+ for (i = 0; i < length; i++) {
+ for (j = 0; j < codeLengths[i]; j++) {
+ p = code.pop();
+ p.children[p.index] = values[k];
+ while (p.index > 0) {
+ p = code.pop();
+ }
+ p.index++;
+ code.push(p);
+ while (code.length <= i) {
+ code.push(q = {children: [], index: 0});
+ p.children[p.index] = q.children;
+ p = q;
+ }
+ k++;
+ }
+ if (i + 1 < length) {
+ // p here points to last code
+ code.push(q = {children: [], index: 0});
+ p.children[p.index] = q.children;
+ p = q;
+ }
+ }
+ return code[0].children;
+ }
+
+ function getBlockBufferOffset(component, row, col) {
+ return 64 * ((component.blocksPerLine + 1) * row + col);
+ }
+
+ function decodeScan(data, offset, frame, components, resetInterval,
+ spectralStart, spectralEnd, successivePrev, successive) {
+ var precision = frame.precision;
+ var samplesPerLine = frame.samplesPerLine;
+ var scanLines = frame.scanLines;
+ var mcusPerLine = frame.mcusPerLine;
+ var progressive = frame.progressive;
+ var maxH = frame.maxH, maxV = frame.maxV;
+
+ var startOffset = offset, bitsData = 0, bitsCount = 0;
+
+ function readBit() {
+ if (bitsCount > 0) {
+ bitsCount--;
+ return (bitsData >> bitsCount) & 1;
+ }
+ bitsData = data[offset++];
+ if (bitsData === 0xFF) {
+ var nextByte = data[offset++];
+ if (nextByte) {
+ throw 'unexpected marker: ' +
+ ((bitsData << 8) | nextByte).toString(16);
+ }
+ // unstuff 0
+ }
+ bitsCount = 7;
+ return bitsData >>> 7;
+ }
+
+ function decodeHuffman(tree) {
+ var node = tree;
+ var bit;
+ while ((bit = readBit()) !== null) {
+ node = node[bit];
+ if (typeof node === 'number') {
+ return node;
+ }
+ if (typeof node !== 'object') {
+ throw 'invalid huffman sequence';
+ }
+ }
+ return null;
+ }
+
+ function receive(length) {
+ var n = 0;
+ while (length > 0) {
+ var bit = readBit();
+ if (bit === null) {
+ return;
+ }
+ n = (n << 1) | bit;
+ length--;
+ }
+ return n;
+ }
+
+ function receiveAndExtend(length) {
+ if (length === 1) {
+ return readBit() === 1 ? 1 : -1;
+ }
+ var n = receive(length);
+ if (n >= 1 << (length - 1)) {
+ return n;
+ }
+ return n + (-1 << length) + 1;
+ }
+
+ function decodeBaseline(component, offset) {
+ var t = decodeHuffman(component.huffmanTableDC);
+ var diff = t === 0 ? 0 : receiveAndExtend(t);
+ component.blockData[offset] = (component.pred += diff);
+ var k = 1;
+ while (k < 64) {
+ var rs = decodeHuffman(component.huffmanTableAC);
+ var s = rs & 15, r = rs >> 4;
+ if (s === 0) {
+ if (r < 15) {
+ break;
+ }
+ k += 16;
+ continue;
+ }
+ k += r;
+ var z = dctZigZag[k];
+ component.blockData[offset + z] = receiveAndExtend(s);
+ k++;
+ }
+ }
+
+ function decodeDCFirst(component, offset) {
+ var t = decodeHuffman(component.huffmanTableDC);
+ var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
+ component.blockData[offset] = (component.pred += diff);
+ }
+
+ function decodeDCSuccessive(component, offset) {
+ component.blockData[offset] |= readBit() << successive;
+ }
+
+ var eobrun = 0;
+ function decodeACFirst(component, offset) {
+ if (eobrun > 0) {
+ eobrun--;
+ return;
+ }
+ var k = spectralStart, e = spectralEnd;
+ while (k <= e) {
+ var rs = decodeHuffman(component.huffmanTableAC);
+ var s = rs & 15, r = rs >> 4;
+ if (s === 0) {
+ if (r < 15) {
+ eobrun = receive(r) + (1 << r) - 1;
+ break;
+ }
+ k += 16;
+ continue;
+ }
+ k += r;
+ var z = dctZigZag[k];
+ component.blockData[offset + z] =
+ receiveAndExtend(s) * (1 << successive);
+ k++;
+ }
+ }
+
+ var successiveACState = 0, successiveACNextValue;
+ function decodeACSuccessive(component, offset) {
+ var k = spectralStart;
+ var e = spectralEnd;
+ var r = 0;
+ var s;
+ var rs;
+ while (k <= e) {
+ var z = dctZigZag[k];
+ switch (successiveACState) {
+ case 0: // initial state
+ rs = decodeHuffman(component.huffmanTableAC);
+ s = rs & 15;
+ r = rs >> 4;
+ if (s === 0) {
+ if (r < 15) {
+ eobrun = receive(r) + (1 << r);
+ successiveACState = 4;
+ } else {
+ r = 16;
+ successiveACState = 1;
+ }
+ } else {
+ if (s !== 1) {
+ throw 'invalid ACn encoding';
+ }
+ successiveACNextValue = receiveAndExtend(s);
+ successiveACState = r ? 2 : 3;
+ }
+ continue;
+ case 1: // skipping r zero items
+ case 2:
+ if (component.blockData[offset + z]) {
+ component.blockData[offset + z] += (readBit() << successive);
+ } else {
+ r--;
+ if (r === 0) {
+ successiveACState = successiveACState === 2 ? 3 : 0;
+ }
+ }
+ break;
+ case 3: // set value for a zero item
+ if (component.blockData[offset + z]) {
+ component.blockData[offset + z] += (readBit() << successive);
+ } else {
+ component.blockData[offset + z] =
+ successiveACNextValue << successive;
+ successiveACState = 0;
+ }
+ break;
+ case 4: // eob
+ if (component.blockData[offset + z]) {
+ component.blockData[offset + z] += (readBit() << successive);
+ }
+ break;
+ }
+ k++;
+ }
+ if (successiveACState === 4) {
+ eobrun--;
+ if (eobrun === 0) {
+ successiveACState = 0;
+ }
+ }
+ }
+
+ function decodeMcu(component, decode, mcu, row, col) {
+ var mcuRow = (mcu / mcusPerLine) | 0;
+ var mcuCol = mcu % mcusPerLine;
+ var blockRow = mcuRow * component.v + row;
+ var blockCol = mcuCol * component.h + col;
+ var offset = getBlockBufferOffset(component, blockRow, blockCol);
+ decode(component, offset);
+ }
+
+ function decodeBlock(component, decode, mcu) {
+ var blockRow = (mcu / component.blocksPerLine) | 0;
+ var blockCol = mcu % component.blocksPerLine;
+ var offset = getBlockBufferOffset(component, blockRow, blockCol);
+ decode(component, offset);
+ }
+
+ var componentsLength = components.length;
+ var component, i, j, k, n;
+ var decodeFn;
+ if (progressive) {
+ if (spectralStart === 0) {
+ decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
+ } else {
+ decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
+ }
+ } else {
+ decodeFn = decodeBaseline;
+ }
+
+ var mcu = 0, marker;
+ var mcuExpected;
+ if (componentsLength === 1) {
+ mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
+ } else {
+ mcuExpected = mcusPerLine * frame.mcusPerColumn;
+ }
+ if (!resetInterval) {
+ resetInterval = mcuExpected;
+ }
+
+ var h, v;
+ while (mcu < mcuExpected) {
+ // reset interval stuff
+ for (i = 0; i < componentsLength; i++) {
+ components[i].pred = 0;
+ }
+ eobrun = 0;
+
+ if (componentsLength === 1) {
+ component = components[0];
+ for (n = 0; n < resetInterval; n++) {
+ decodeBlock(component, decodeFn, mcu);
+ mcu++;
+ }
+ } else {
+ for (n = 0; n < resetInterval; n++) {
+ for (i = 0; i < componentsLength; i++) {
+ component = components[i];
+ h = component.h;
+ v = component.v;
+ for (j = 0; j < v; j++) {
+ for (k = 0; k < h; k++) {
+ decodeMcu(component, decodeFn, mcu, j, k);
+ }
+ }
+ }
+ mcu++;
+ }
+ }
+
+ // find marker
+ bitsCount = 0;
+ marker = (data[offset] << 8) | data[offset + 1];
+ if (marker <= 0xFF00) {
+ throw 'marker was not found';
+ }
+
+ if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
+ offset += 2;
+ } else {
+ break;
+ }
+ }
+
+ return offset - startOffset;
+ }
+
+ // A port of poppler's IDCT method which in turn is taken from:
+ // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
+ // 'Practical Fast 1-D DCT Algorithms with 11 Multiplications',
+ // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
+ // 988-991.
+ function quantizeAndInverse(component, blockBufferOffset, p) {
+ var qt = component.quantizationTable, blockData = component.blockData;
+ var v0, v1, v2, v3, v4, v5, v6, v7;
+ var p0, p1, p2, p3, p4, p5, p6, p7;
+ var t;
+
+ // inverse DCT on rows
+ for (var row = 0; row < 64; row += 8) {
+ // gather block data
+ p0 = blockData[blockBufferOffset + row];
+ p1 = blockData[blockBufferOffset + row + 1];
+ p2 = blockData[blockBufferOffset + row + 2];
+ p3 = blockData[blockBufferOffset + row + 3];
+ p4 = blockData[blockBufferOffset + row + 4];
+ p5 = blockData[blockBufferOffset + row + 5];
+ p6 = blockData[blockBufferOffset + row + 6];
+ p7 = blockData[blockBufferOffset + row + 7];
+
+ // dequant p0
+ p0 *= qt[row];
+
+ // check for all-zero AC coefficients
+ if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
+ t = (dctSqrt2 * p0 + 512) >> 10;
+ p[row] = t;
+ p[row + 1] = t;
+ p[row + 2] = t;
+ p[row + 3] = t;
+ p[row + 4] = t;
+ p[row + 5] = t;
+ p[row + 6] = t;
+ p[row + 7] = t;
+ continue;
+ }
+ // dequant p1 ... p7
+ p1 *= qt[row + 1];
+ p2 *= qt[row + 2];
+ p3 *= qt[row + 3];
+ p4 *= qt[row + 4];
+ p5 *= qt[row + 5];
+ p6 *= qt[row + 6];
+ p7 *= qt[row + 7];
+
+ // stage 4
+ v0 = (dctSqrt2 * p0 + 128) >> 8;
+ v1 = (dctSqrt2 * p4 + 128) >> 8;
+ v2 = p2;
+ v3 = p6;
+ v4 = (dctSqrt1d2 * (p1 - p7) + 128) >> 8;
+ v7 = (dctSqrt1d2 * (p1 + p7) + 128) >> 8;
+ v5 = p3 << 4;
+ v6 = p5 << 4;
+
+ // stage 3
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = v0 - v1;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
+ v3 = t;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = v4 - v6;
+ v7 = (v7 + v5 + 1) >> 1;
+ v5 = v7 - v5;
+
+ // stage 2
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = v0 - v3;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = v1 - v2;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[row] = v0 + v7;
+ p[row + 7] = v0 - v7;
+ p[row + 1] = v1 + v6;
+ p[row + 6] = v1 - v6;
+ p[row + 2] = v2 + v5;
+ p[row + 5] = v2 - v5;
+ p[row + 3] = v3 + v4;
+ p[row + 4] = v3 - v4;
+ }
+
+ // inverse DCT on columns
+ for (var col = 0; col < 8; ++col) {
+ p0 = p[col];
+ p1 = p[col + 8];
+ p2 = p[col + 16];
+ p3 = p[col + 24];
+ p4 = p[col + 32];
+ p5 = p[col + 40];
+ p6 = p[col + 48];
+ p7 = p[col + 56];
+
+ // check for all-zero AC coefficients
+ if ((p1 | p2 | p3 | p4 | p5 | p6 | p7) === 0) {
+ t = (dctSqrt2 * p0 + 8192) >> 14;
+ // convert to 8 bit
+ t = (t < -2040) ? 0 : (t >= 2024) ? 255 : (t + 2056) >> 4;
+ blockData[blockBufferOffset + col] = t;
+ blockData[blockBufferOffset + col + 8] = t;
+ blockData[blockBufferOffset + col + 16] = t;
+ blockData[blockBufferOffset + col + 24] = t;
+ blockData[blockBufferOffset + col + 32] = t;
+ blockData[blockBufferOffset + col + 40] = t;
+ blockData[blockBufferOffset + col + 48] = t;
+ blockData[blockBufferOffset + col + 56] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p0 + 2048) >> 12;
+ v1 = (dctSqrt2 * p4 + 2048) >> 12;
+ v2 = p2;
+ v3 = p6;
+ v4 = (dctSqrt1d2 * (p1 - p7) + 2048) >> 12;
+ v7 = (dctSqrt1d2 * (p1 + p7) + 2048) >> 12;
+ v5 = p3;
+ v6 = p5;
+
+ // stage 3
+ // Shift v0 by 128.5 << 5 here, so we don't need to shift p0...p7 when
+ // converting to UInt8 range later.
+ v0 = ((v0 + v1 + 1) >> 1) + 4112;
+ v1 = v0 - v1;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
+ v3 = t;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = v4 - v6;
+ v7 = (v7 + v5 + 1) >> 1;
+ v5 = v7 - v5;
+
+ // stage 2
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = v0 - v3;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = v1 - v2;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p0 = v0 + v7;
+ p7 = v0 - v7;
+ p1 = v1 + v6;
+ p6 = v1 - v6;
+ p2 = v2 + v5;
+ p5 = v2 - v5;
+ p3 = v3 + v4;
+ p4 = v3 - v4;
+
+ // convert to 8-bit integers
+ p0 = (p0 < 16) ? 0 : (p0 >= 4080) ? 255 : p0 >> 4;
+ p1 = (p1 < 16) ? 0 : (p1 >= 4080) ? 255 : p1 >> 4;
+ p2 = (p2 < 16) ? 0 : (p2 >= 4080) ? 255 : p2 >> 4;
+ p3 = (p3 < 16) ? 0 : (p3 >= 4080) ? 255 : p3 >> 4;
+ p4 = (p4 < 16) ? 0 : (p4 >= 4080) ? 255 : p4 >> 4;
+ p5 = (p5 < 16) ? 0 : (p5 >= 4080) ? 255 : p5 >> 4;
+ p6 = (p6 < 16) ? 0 : (p6 >= 4080) ? 255 : p6 >> 4;
+ p7 = (p7 < 16) ? 0 : (p7 >= 4080) ? 255 : p7 >> 4;
+
+ // store block data
+ blockData[blockBufferOffset + col] = p0;
+ blockData[blockBufferOffset + col + 8] = p1;
+ blockData[blockBufferOffset + col + 16] = p2;
+ blockData[blockBufferOffset + col + 24] = p3;
+ blockData[blockBufferOffset + col + 32] = p4;
+ blockData[blockBufferOffset + col + 40] = p5;
+ blockData[blockBufferOffset + col + 48] = p6;
+ blockData[blockBufferOffset + col + 56] = p7;
+ }
+ }
+
+ function buildComponentData(frame, component) {
+ var blocksPerLine = component.blocksPerLine;
+ var blocksPerColumn = component.blocksPerColumn;
+ var computationBuffer = new Int16Array(64);
+
+ for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
+ for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
+ var offset = getBlockBufferOffset(component, blockRow, blockCol);
+ quantizeAndInverse(component, offset, computationBuffer);
+ }
+ }
+ return component.blockData;
+ }
+
+ function clamp0to255(a) {
+ return a <= 0 ? 0 : a >= 255 ? 255 : a;
+ }
+
+ constructor.prototype = {
+ parse: function parse(data) {
+
+ function readUint16() {
+ var value = (data[offset] << 8) | data[offset + 1];
+ offset += 2;
+ return value;
+ }
+
+ function readDataBlock() {
+ var length = readUint16();
+ var array = data.subarray(offset, offset + length - 2);
+ offset += array.length;
+ return array;
+ }
+
+ function prepareComponents(frame) {
+ var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / frame.maxH);
+ var mcusPerColumn = Math.ceil(frame.scanLines / 8 / frame.maxV);
+ for (var i = 0; i < frame.components.length; i++) {
+ component = frame.components[i];
+ var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) *
+ component.h / frame.maxH);
+ var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) *
+ component.v / frame.maxV);
+ var blocksPerLineForMcu = mcusPerLine * component.h;
+ var blocksPerColumnForMcu = mcusPerColumn * component.v;
+
+ var blocksBufferSize = 64 * blocksPerColumnForMcu *
+ (blocksPerLineForMcu + 1);
+ component.blockData = new Int16Array(blocksBufferSize);
+ component.blocksPerLine = blocksPerLine;
+ component.blocksPerColumn = blocksPerColumn;
+ }
+ frame.mcusPerLine = mcusPerLine;
+ frame.mcusPerColumn = mcusPerColumn;
+ }
+
+ var offset = 0, length = data.length;
+ var jfif = null;
+ var adobe = null;
+ var pixels = null;
+ var frame, resetInterval;
+ var quantizationTables = [];
+ var huffmanTablesAC = [], huffmanTablesDC = [];
+ var fileMarker = readUint16();
+ if (fileMarker !== 0xFFD8) { // SOI (Start of Image)
+ throw 'SOI not found';
+ }
+
+ fileMarker = readUint16();
+ while (fileMarker !== 0xFFD9) { // EOI (End of image)
+ var i, j, l;
+ switch(fileMarker) {
+ case 0xFFE0: // APP0 (Application Specific)
+ case 0xFFE1: // APP1
+ case 0xFFE2: // APP2
+ case 0xFFE3: // APP3
+ case 0xFFE4: // APP4
+ case 0xFFE5: // APP5
+ case 0xFFE6: // APP6
+ case 0xFFE7: // APP7
+ case 0xFFE8: // APP8
+ case 0xFFE9: // APP9
+ case 0xFFEA: // APP10
+ case 0xFFEB: // APP11
+ case 0xFFEC: // APP12
+ case 0xFFED: // APP13
+ case 0xFFEE: // APP14
+ case 0xFFEF: // APP15
+ case 0xFFFE: // COM (Comment)
+ var appData = readDataBlock();
+
+ if (fileMarker === 0xFFE0) {
+ if (appData[0] === 0x4A && appData[1] === 0x46 &&
+ appData[2] === 0x49 && appData[3] === 0x46 &&
+ appData[4] === 0) { // 'JFIF\x00'
+ jfif = {
+ version: { major: appData[5], minor: appData[6] },
+ densityUnits: appData[7],
+ xDensity: (appData[8] << 8) | appData[9],
+ yDensity: (appData[10] << 8) | appData[11],
+ thumbWidth: appData[12],
+ thumbHeight: appData[13],
+ thumbData: appData.subarray(14, 14 +
+ 3 * appData[12] * appData[13])
+ };
+ }
+ }
+ // TODO APP1 - Exif
+ if (fileMarker === 0xFFEE) {
+ if (appData[0] === 0x41 && appData[1] === 0x64 &&
+ appData[2] === 0x6F && appData[3] === 0x62 &&
+ appData[4] === 0x65 && appData[5] === 0) { // 'Adobe\x00'
+ adobe = {
+ version: appData[6],
+ flags0: (appData[7] << 8) | appData[8],
+ flags1: (appData[9] << 8) | appData[10],
+ transformCode: appData[11]
+ };
+ }
+ }
+ break;
+
+ case 0xFFDB: // DQT (Define Quantization Tables)
+ var quantizationTablesLength = readUint16();
+ var quantizationTablesEnd = quantizationTablesLength + offset - 2;
+ var z;
+ while (offset < quantizationTablesEnd) {
+ var quantizationTableSpec = data[offset++];
+ var tableData = new Uint16Array(64);
+ if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
+ for (j = 0; j < 64; j++) {
+ z = dctZigZag[j];
+ tableData[z] = data[offset++];
+ }
+ } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
+ for (j = 0; j < 64; j++) {
+ z = dctZigZag[j];
+ tableData[z] = readUint16();
+ }
+ } else {
+ throw 'DQT: invalid table spec';
+ }
+ quantizationTables[quantizationTableSpec & 15] = tableData;
+ }
+ break;
+
+ case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
+ case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
+ case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
+ if (frame) {
+ throw 'Only single frame JPEGs supported';
+ }
+ readUint16(); // skip data length
+ frame = {};
+ frame.extended = (fileMarker === 0xFFC1);
+ frame.progressive = (fileMarker === 0xFFC2);
+ frame.precision = data[offset++];
+ frame.scanLines = readUint16();
+ frame.samplesPerLine = readUint16();
+ frame.components = [];
+ frame.componentIds = {};
+ var componentsCount = data[offset++], componentId;
+ var maxH = 0, maxV = 0;
+ for (i = 0; i < componentsCount; i++) {
+ componentId = data[offset];
+ var h = data[offset + 1] >> 4;
+ var v = data[offset + 1] & 15;
+ if (maxH < h) {
+ maxH = h;
+ }
+ if (maxV < v) {
+ maxV = v;
+ }
+ var qId = data[offset + 2];
+ l = frame.components.push({
+ h: h,
+ v: v,
+ quantizationTable: quantizationTables[qId]
+ });
+ frame.componentIds[componentId] = l - 1;
+ offset += 3;
+ }
+ frame.maxH = maxH;
+ frame.maxV = maxV;
+ prepareComponents(frame);
+ break;
+
+ case 0xFFC4: // DHT (Define Huffman Tables)
+ var huffmanLength = readUint16();
+ for (i = 2; i < huffmanLength;) {
+ var huffmanTableSpec = data[offset++];
+ var codeLengths = new Uint8Array(16);
+ var codeLengthSum = 0;
+ for (j = 0; j < 16; j++, offset++) {
+ codeLengthSum += (codeLengths[j] = data[offset]);
+ }
+ var huffmanValues = new Uint8Array(codeLengthSum);
+ for (j = 0; j < codeLengthSum; j++, offset++) {
+ huffmanValues[j] = data[offset];
+ }
+ i += 17 + codeLengthSum;
+
+ ((huffmanTableSpec >> 4) === 0 ?
+ huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
+ buildHuffmanTable(codeLengths, huffmanValues);
+ }
+ break;
+
+ case 0xFFDD: // DRI (Define Restart Interval)
+ readUint16(); // skip data length
+ resetInterval = readUint16();
+ break;
+
+ case 0xFFDA: // SOS (Start of Scan)
+ var scanLength = readUint16();
+ var selectorsCount = data[offset++];
+ var components = [], component;
+ for (i = 0; i < selectorsCount; i++) {
+ var componentIndex = frame.componentIds[data[offset++]];
+ component = frame.components[componentIndex];
+ var tableSpec = data[offset++];
+ component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
+ component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
+ components.push(component);
+ }
+ var spectralStart = data[offset++];
+ var spectralEnd = data[offset++];
+ var successiveApproximation = data[offset++];
+ var processed = decodeScan(data, offset,
+ frame, components, resetInterval,
+ spectralStart, spectralEnd,
+ successiveApproximation >> 4, successiveApproximation & 15);
+ offset += processed;
+ break;
+ default:
+ if (data[offset - 3] === 0xFF &&
+ data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
+ // could be incorrect encoding -- last 0xFF byte of the previous
+ // block was eaten by the encoder
+ offset -= 3;
+ break;
+ }
+ throw 'unknown JPEG marker ' + fileMarker.toString(16);
+ }
+ fileMarker = readUint16();
+ }
+
+ this.width = frame.samplesPerLine;
+ this.height = frame.scanLines;
+ this.jfif = jfif;
+ this.adobe = adobe;
+ this.components = [];
+ for (i = 0; i < frame.components.length; i++) {
+ component = frame.components[i];
+ this.components.push({
+ output: buildComponentData(frame, component),
+ scaleX: component.h / frame.maxH,
+ scaleY: component.v / frame.maxV,
+ blocksPerLine: component.blocksPerLine,
+ blocksPerColumn: component.blocksPerColumn
+ });
+ }
+ this.numComponents = this.components.length;
+ },
+
+ _getLinearizedBlockData: function getLinearizedBlockData(width, height) {
+ var scaleX = this.width / width, scaleY = this.height / height;
+
+ var component, componentScaleX, componentScaleY, blocksPerScanline;
+ var x, y, i, j, k;
+ var index;
+ var offset = 0;
+ var output;
+ var numComponents = this.components.length;
+ var dataLength = width * height * numComponents;
+ var data = new Uint8Array(dataLength);
+ var xScaleBlockOffset = new Uint32Array(width);
+ var mask3LSB = 0xfffffff8; // used to clear the 3 LSBs
+
+ for (i = 0; i < numComponents; i++) {
+ component = this.components[i];
+ componentScaleX = component.scaleX * scaleX;
+ componentScaleY = component.scaleY * scaleY;
+ offset = i;
+ output = component.output;
+ blocksPerScanline = (component.blocksPerLine + 1) << 3;
+ // precalculate the xScaleBlockOffset
+ for (x = 0; x < width; x++) {
+ j = 0 | (x * componentScaleX);
+ xScaleBlockOffset[x] = ((j & mask3LSB) << 3) | (j & 7);
+ }
+ // linearize the blocks of the component
+ for (y = 0; y < height; y++) {
+ j = 0 | (y * componentScaleY);
+ index = blocksPerScanline * (j & mask3LSB) | ((j & 7) << 3);
+ for (x = 0; x < width; x++) {
+ data[offset] = output[index + xScaleBlockOffset[x]];
+ offset += numComponents;
+ }
+ }
+ }
+
+ // decodeTransform will contains pairs of multiplier (-256..256) and
+ // additive
+ var transform = this.decodeTransform;
+ if (transform) {
+ for (i = 0; i < dataLength;) {
+ for (j = 0, k = 0; j < numComponents; j++, i++, k += 2) {
+ data[i] = ((data[i] * transform[k]) >> 8) + transform[k + 1];
+ }
+ }
+ }
+ return data;
+ },
+
+ _isColorConversionNeeded: function isColorConversionNeeded() {
+ if (this.adobe && this.adobe.transformCode) {
+ // The adobe transform marker overrides any previous setting
+ return true;
+ } else if (this.numComponents === 3) {
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ _convertYccToRgb: function convertYccToRgb(data) {
+ var Y, Cb, Cr;
+ for (var i = 0, length = data.length; i < length; i += 3) {
+ Y = data[i ];
+ Cb = data[i + 1];
+ Cr = data[i + 2];
+ data[i ] = clamp0to255(Y - 179.456 + 1.402 * Cr);
+ data[i + 1] = clamp0to255(Y + 135.459 - 0.344 * Cb - 0.714 * Cr);
+ data[i + 2] = clamp0to255(Y - 226.816 + 1.772 * Cb);
+ }
+ return data;
+ },
+
+ _convertYcckToRgb: function convertYcckToRgb(data) {
+ var Y, Cb, Cr, k, CbCb, CbCr, CbY, Cbk, CrCr, Crk, CrY, YY, Yk, kk;
+ var offset = 0;
+ for (var i = 0, length = data.length; i < length; i += 4) {
+ Y = data[i];
+ Cb = data[i + 1];
+ Cr = data[i + 2];
+ k = data[i + 3];
+
+ CbCb = Cb * Cb;
+ CbCr = Cb * Cr;
+ CbY = Cb * Y;
+ Cbk = Cb * k;
+ CrCr = Cr * Cr;
+ Crk = Cr * k;
+ CrY = Cr * Y;
+ YY = Y * Y;
+ Yk = Y * k;
+ kk = k * k;
+
+ var r = - 122.67195406894 -
+ 6.60635669420364e-5 * CbCb + 0.000437130475926232 * CbCr -
+ 5.4080610064599e-5* CbY + 0.00048449797120281* Cbk -
+ 0.154362151871126 * Cb - 0.000957964378445773 * CrCr +
+ 0.000817076911346625 * CrY - 0.00477271405408747 * Crk +
+ 1.53380253221734 * Cr + 0.000961250184130688 * YY -
+ 0.00266257332283933 * Yk + 0.48357088451265 * Y -
+ 0.000336197177618394 * kk + 0.484791561490776 * k;
+
+ var g = 107.268039397724 +
+ 2.19927104525741e-5 * CbCb - 0.000640992018297945 * CbCr +
+ 0.000659397001245577* CbY + 0.000426105652938837* Cbk -
+ 0.176491792462875 * Cb - 0.000778269941513683 * CrCr +
+ 0.00130872261408275 * CrY + 0.000770482631801132 * Crk -
+ 0.151051492775562 * Cr + 0.00126935368114843 * YY -
+ 0.00265090189010898 * Yk + 0.25802910206845 * Y -
+ 0.000318913117588328 * kk - 0.213742400323665 * k;
+
+ var b = - 20.810012546947 -
+ 0.000570115196973677 * CbCb - 2.63409051004589e-5 * CbCr +
+ 0.0020741088115012* CbY - 0.00288260236853442* Cbk +
+ 0.814272968359295 * Cb - 1.53496057440975e-5 * CrCr -
+ 0.000132689043961446 * CrY + 0.000560833691242812 * Crk -
+ 0.195152027534049 * Cr + 0.00174418132927582 * YY -
+ 0.00255243321439347 * Yk + 0.116935020465145 * Y -
+ 0.000343531996510555 * kk + 0.24165260232407 * k;
+
+ data[offset++] = clamp0to255(r);
+ data[offset++] = clamp0to255(g);
+ data[offset++] = clamp0to255(b);
+ }
+ return data;
+ },
+
+ _convertYcckToCmyk: function convertYcckToCmyk(data) {
+ var Y, Cb, Cr;
+ for (var i = 0, length = data.length; i < length; i += 4) {
+ Y = data[i];
+ Cb = data[i + 1];
+ Cr = data[i + 2];
+ data[i ] = clamp0to255(434.456 - Y - 1.402 * Cr);
+ data[i + 1] = clamp0to255(119.541 - Y + 0.344 * Cb + 0.714 * Cr);
+ data[i + 2] = clamp0to255(481.816 - Y - 1.772 * Cb);
+ // K in data[i + 3] is unchanged
+ }
+ return data;
+ },
+
+ _convertCmykToRgb: function convertCmykToRgb(data) {
+ var c, m, y, k;
+ var offset = 0;
+ var min = -255 * 255 * 255;
+ var scale = 1 / 255 / 255;
+ for (var i = 0, length = data.length; i < length; i += 4) {
+ c = data[i];
+ m = data[i + 1];
+ y = data[i + 2];
+ k = data[i + 3];
+
+ var r =
+ c * (-4.387332384609988 * c + 54.48615194189176 * m +
+ 18.82290502165302 * y + 212.25662451639585 * k -
+ 72734.4411664936) +
+ m * (1.7149763477362134 * m - 5.6096736904047315 * y -
+ 17.873870861415444 * k - 1401.7366389350734) +
+ y * (-2.5217340131683033 * y - 21.248923337353073 * k +
+ 4465.541406466231) -
+ k * (21.86122147463605 * k + 48317.86113160301);
+ var g =
+ c * (8.841041422036149 * c + 60.118027045597366 * m +
+ 6.871425592049007 * y + 31.159100130055922 * k -
+ 20220.756542821975) +
+ m * (-15.310361306967817 * m + 17.575251261109482 * y +
+ 131.35250912493976 * k - 48691.05921601825) +
+ y * (4.444339102852739 * y + 9.8632861493405 * k -
+ 6341.191035517494) -
+ k * (20.737325471181034 * k + 47890.15695978492);
+ var b =
+ c * (0.8842522430003296 * c + 8.078677503112928 * m +
+ 30.89978309703729 * y - 0.23883238689178934 * k -
+ 3616.812083916688) +
+ m * (10.49593273432072 * m + 63.02378494754052 * y +
+ 50.606957656360734 * k - 28620.90484698408) +
+ y * (0.03296041114873217 * y + 115.60384449646641 * k -
+ 49363.43385999684) -
+ k * (22.33816807309886 * k + 45932.16563550634);
+
+ data[offset++] = r >= 0 ? 255 : r <= min ? 0 : 255 + r * scale | 0;
+ data[offset++] = g >= 0 ? 255 : g <= min ? 0 : 255 + g * scale | 0;
+ data[offset++] = b >= 0 ? 255 : b <= min ? 0 : 255 + b * scale | 0;
+ }
+ return data;
+ },
+
+ getData: function getData(width, height, forceRGBoutput) {
+ if (this.numComponents > 4) {
+ throw 'Unsupported color mode';
+ }
+ // type of data: Uint8Array(width * height * numComponents)
+ var data = this._getLinearizedBlockData(width, height);
+
+ if (this.numComponents === 3) {
+ return this._convertYccToRgb(data);
+ } else if (this.numComponents === 4) {
+ if (this._isColorConversionNeeded()) {
+ if (forceRGBoutput) {
+ return this._convertYcckToRgb(data);
+ } else {
+ return this._convertYcckToCmyk(data);
+ }
+ } else if (forceRGBoutput) {
+ return this._convertCmykToRgb(data);
+ }
+ }
+ return data;
+ }
+ };
+
+ return constructor;
+})();
+
+
var JpxImage = (function JpxImageClosure() {
// Table E.1
var SubbandsGainLog2 = {
@@ -35161,41 +35125,35 @@ var JpxImage = (function JpxImageClosure() {
this.failOnCorruptedImage = false;
}
JpxImage.prototype = {
- load: function JpxImage_load(url) {
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.onload = (function() {
- // TODO catch parse error
- var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
- this.parse(data);
- if (this.onload)
- this.onload();
- }).bind(this);
- xhr.send(null);
- },
parse: function JpxImage_parse(data) {
- function readUint(data, offset, bytes) {
- var n = 0;
- for (var i = 0; i < bytes; i++)
- n = n * 256 + (data[offset + i] & 0xFF);
- return n;
+
+ var head = readUint16(data, 0);
+ // No box header, immediate start of codestream (SOC)
+ if (head === 0xFF4F) {
+ this.parseCodestream(data, 0, data.length);
+ return;
}
+
var position = 0, length = data.length;
while (position < length) {
var headerSize = 8;
- var lbox = readUint(data, position, 4);
- var tbox = readUint(data, position + 4, 4);
+ var lbox = readUint32(data, position);
+ var tbox = readUint32(data, position + 4);
position += headerSize;
- if (lbox == 1) {
- lbox = readUint(data, position, 8);
+ if (lbox === 1) {
+ // XLBox: read UInt64 according to spec.
+ // JavaScript's int precision of 53 bit should be sufficient here.
+ lbox = readUint32(data, position) * 4294967296 +
+ readUint32(data, position + 4);
position += 8;
headerSize += 8;
}
- if (lbox === 0)
+ if (lbox === 0) {
lbox = length - position + headerSize;
- if (lbox < headerSize)
- error('JPX error: Invalid box field size');
+ }
+ if (lbox < headerSize) {
+ throw new Error('JPX Error: Invalid box field size');
+ }
var dataLength = lbox - headerSize;
var jumpDataLength = true;
switch (tbox) {
@@ -35212,19 +35170,46 @@ var JpxImage = (function JpxImageClosure() {
this.parseCodestream(data, position, position + dataLength);
break;
}
- if (jumpDataLength)
+ if (jumpDataLength) {
position += dataLength;
+ }
}
},
+ parseImageProperties: function JpxImage_parseImageProperties(stream) {
+ var newByte = stream.getByte();
+ while (newByte >= 0) {
+ var oldByte = newByte;
+ newByte = stream.getByte();
+ var code = (oldByte << 8) | newByte;
+ // Image and tile size (SIZ)
+ if (code === 0xFF51) {
+ stream.skip(4);
+ var Xsiz = stream.getInt32() >>> 0; // Byte 4
+ var Ysiz = stream.getInt32() >>> 0; // Byte 8
+ var XOsiz = stream.getInt32() >>> 0; // Byte 12
+ var YOsiz = stream.getInt32() >>> 0; // Byte 16
+ stream.skip(16);
+ var Csiz = stream.getUint16(); // Byte 36
+ this.width = Xsiz - XOsiz;
+ this.height = Ysiz - YOsiz;
+ this.componentsCount = Csiz;
+ // Results are always returned as Uint8Arrays
+ this.bitsPerComponent = 8;
+ return;
+ }
+ }
+ throw new Error('JPX Error: No size marker found in JPX stream');
+ },
parseCodestream: function JpxImage_parseCodestream(data, start, end) {
var context = {};
try {
+ var doNotRecover = false;
var position = start;
- while (position < end) {
+ while (position + 1 < end) {
var code = readUint16(data, position);
position += 2;
- var length = 0, j;
+ var length = 0, j, sqcd, spqcds, spqcdSize, scalarExpounded, tile;
switch (code) {
case 0xFF4F: // Start of codestream (SOC)
context.mainHeader = true;
@@ -35262,12 +35247,16 @@ var JpxImage = (function JpxImageClosure() {
context.QCC = [];
context.COC = [];
break;
+ case 0xFF55: // Tile-part lengths, main header (TLM)
+ var Ltlm = readUint16(data, position); // Marker segment length
+ // Skip tile length markers
+ position += Ltlm;
+ break;
case 0xFF5C: // Quantization default (QCD)
length = readUint16(data, position);
var qcd = {};
j = position + 2;
- var sqcd = data[j++];
- var spqcdSize, scalarExpounded;
+ sqcd = data[j++];
switch (sqcd & 0x1F) {
case 0:
spqcdSize = 8;
@@ -35282,15 +35271,15 @@ var JpxImage = (function JpxImageClosure() {
scalarExpounded = true;
break;
default:
- throw 'Invalid SQcd value ' + sqcd;
+ throw new Error('JPX Error: Invalid SQcd value ' + sqcd);
}
- qcd.noQuantization = spqcdSize == 8;
+ qcd.noQuantization = (spqcdSize === 8);
qcd.scalarExpounded = scalarExpounded;
qcd.guardBits = sqcd >> 5;
- var spqcds = [];
+ spqcds = [];
while (j < length + position) {
var spqcd = {};
- if (spqcdSize == 8) {
+ if (spqcdSize === 8) {
spqcd.epsilon = data[j++] >> 3;
spqcd.mu = 0;
} else {
@@ -35301,9 +35290,9 @@ var JpxImage = (function JpxImageClosure() {
spqcds.push(spqcd);
}
qcd.SPqcds = spqcds;
- if (context.mainHeader)
+ if (context.mainHeader) {
context.QCD = qcd;
- else {
+ } else {
context.currentTile.QCD = qcd;
context.currentTile.QCC = [];
}
@@ -35313,14 +35302,13 @@ var JpxImage = (function JpxImageClosure() {
var qcc = {};
j = position + 2;
var cqcc;
- if (context.SIZ.Csiz < 257)
+ if (context.SIZ.Csiz < 257) {
cqcc = data[j++];
- else {
+ } else {
cqcc = readUint16(data, j);
j += 2;
}
- var sqcd = data[j++];
- var spqcdSize, scalarExpounded;
+ sqcd = data[j++];
switch (sqcd & 0x1F) {
case 0:
spqcdSize = 8;
@@ -35335,15 +35323,15 @@ var JpxImage = (function JpxImageClosure() {
scalarExpounded = true;
break;
default:
- throw 'Invalid SQcd value ' + sqcd;
+ throw new Error('JPX Error: Invalid SQcd value ' + sqcd);
}
- qcc.noQuantization = spqcdSize == 8;
+ qcc.noQuantization = (spqcdSize === 8);
qcc.scalarExpounded = scalarExpounded;
qcc.guardBits = sqcd >> 5;
- var spqcds = [];
- while (j < length + position) {
- var spqcd = {};
- if (spqcdSize == 8) {
+ spqcds = [];
+ while (j < (length + position)) {
+ spqcd = {};
+ if (spqcdSize === 8) {
spqcd.epsilon = data[j++] >> 3;
spqcd.mu = 0;
} else {
@@ -35354,10 +35342,11 @@ var JpxImage = (function JpxImageClosure() {
spqcds.push(spqcd);
}
qcc.SPqcds = spqcds;
- if (context.mainHeader)
+ if (context.mainHeader) {
context.QCC[cqcc] = qcc;
- else
+ } else {
context.currentTile.QCC[cqcc] = qcc;
+ }
break;
case 0xFF52: // Coding style default (COD)
length = readUint16(data, position);
@@ -35367,7 +35356,6 @@ var JpxImage = (function JpxImageClosure() {
cod.entropyCoderWithCustomPrecincts = !!(scod & 1);
cod.sopMarkerUsed = !!(scod & 2);
cod.ephMarkerUsed = !!(scod & 4);
- var codingStyle = {};
cod.progressionOrder = data[j++];
cod.layersCount = readUint16(data, j);
j += 2;
@@ -35383,11 +35371,11 @@ var JpxImage = (function JpxImageClosure() {
cod.verticalyStripe = !!(blockStyle & 8);
cod.predictableTermination = !!(blockStyle & 16);
cod.segmentationSymbolUsed = !!(blockStyle & 32);
- cod.transformation = data[j++];
+ cod.reversibleTransformation = data[j++];
if (cod.entropyCoderWithCustomPrecincts) {
- var precinctsSizes = {};
+ var precinctsSizes = [];
while (j < length + position) {
- var precinctsSize = data[j];
+ var precinctsSize = data[j++];
precinctsSizes.push({
PPx: precinctsSize & 0xF,
PPy: precinctsSize >> 4
@@ -35395,25 +35383,43 @@ var JpxImage = (function JpxImageClosure() {
}
cod.precinctsSizes = precinctsSizes;
}
-
- if (cod.sopMarkerUsed || cod.ephMarkerUsed ||
- cod.selectiveArithmeticCodingBypass ||
- cod.resetContextProbabilities ||
- cod.terminationOnEachCodingPass ||
- cod.verticalyStripe || cod.predictableTermination)
- throw 'Unsupported COD options: ' +
- globalScope.JSON.stringify(cod);
-
- if (context.mainHeader)
+ var unsupported = [];
+ if (cod.sopMarkerUsed) {
+ unsupported.push('sopMarkerUsed');
+ }
+ if (cod.ephMarkerUsed) {
+ unsupported.push('ephMarkerUsed');
+ }
+ if (cod.selectiveArithmeticCodingBypass) {
+ unsupported.push('selectiveArithmeticCodingBypass');
+ }
+ if (cod.resetContextProbabilities) {
+ unsupported.push('resetContextProbabilities');
+ }
+ if (cod.terminationOnEachCodingPass) {
+ unsupported.push('terminationOnEachCodingPass');
+ }
+ if (cod.verticalyStripe) {
+ unsupported.push('verticalyStripe');
+ }
+ if (cod.predictableTermination) {
+ unsupported.push('predictableTermination');
+ }
+ if (unsupported.length > 0) {
+ doNotRecover = true;
+ throw new Error('JPX Error: Unsupported COD options (' +
+ unsupported.join(', ') + ')');
+ }
+ if (context.mainHeader) {
context.COD = cod;
- else {
+ } else {
context.currentTile.COD = cod;
context.currentTile.COC = [];
}
break;
case 0xFF90: // Start of tile-part (SOT)
length = readUint16(data, position);
- var tile = {};
+ tile = {};
tile.index = readUint16(data, position + 2);
tile.length = readUint32(data, position + 4);
tile.dataEnd = tile.length + position - 2;
@@ -35431,7 +35437,7 @@ var JpxImage = (function JpxImageClosure() {
context.currentTile = tile;
break;
case 0xFF93: // Start of data (SOD)
- var tile = context.currentTile;
+ tile = context.currentTile;
if (tile.partIndex === 0) {
initializeTile(context, tile.index);
buildPackets(context);
@@ -35439,23 +35445,27 @@ var JpxImage = (function JpxImageClosure() {
// moving to the end of the data
length = tile.dataEnd - position;
-
parseTilePackets(context, data, position, length);
break;
case 0xFF64: // Comment (COM)
length = readUint16(data, position);
// skipping content
break;
+ case 0xFF53: // Coding style component (COC)
+ throw new Error('JPX Error: Codestream code 0xFF53 (COC) is ' +
+ 'not implemented');
default:
- throw 'Unknown codestream code: ' + code.toString(16);
+ throw new Error('JPX Error: Unknown codestream code: ' +
+ code.toString(16));
}
position += length;
}
} catch (e) {
- if (this.failOnCorruptedImage)
- error('JPX error: ' + e);
- else
- warn('JPX error: ' + e + '. Trying to recover');
+ if (doNotRecover || this.failOnCorruptedImage) {
+ throw e;
+ } else {
+ warn('Trying to recover from ' + e.message);
+ }
}
this.tiles = transformComponents(context);
this.width = context.SIZ.Xsiz - context.SIZ.XOsiz;
@@ -35463,21 +35473,6 @@ var JpxImage = (function JpxImageClosure() {
this.componentsCount = context.SIZ.Csiz;
}
};
- function readUint32(data, offset) {
- return (data[offset] << 24) | (data[offset + 1] << 16) |
- (data[offset + 2] << 8) | data[offset + 3];
- }
- function readUint16(data, offset) {
- return (data[offset] << 8) | data[offset + 1];
- }
- function log2(x) {
- var n = 1, i = 0;
- while (x > n) {
- n <<= 1;
- i++;
- }
- return i;
- }
function calculateComponentDimensions(component, siz) {
// Section B.2 Component mapping
component.x0 = Math.ceil(siz.XOsiz / component.XRsiz);
@@ -35490,12 +35485,12 @@ var JpxImage = (function JpxImageClosure() {
function calculateTileGrids(context, components) {
var siz = context.SIZ;
// Section B.3 Division into tile and tile-components
- var tiles = [];
+ var tile, tiles = [];
var numXtiles = Math.ceil((siz.Xsiz - siz.XTOsiz) / siz.XTsiz);
var numYtiles = Math.ceil((siz.Ysiz - siz.YTOsiz) / siz.YTsiz);
for (var q = 0; q < numYtiles; q++) {
for (var p = 0; p < numXtiles; p++) {
- var tile = {};
+ tile = {};
tile.tx0 = Math.max(siz.XTOsiz + p * siz.XTsiz, siz.XOsiz);
tile.ty0 = Math.max(siz.YTOsiz + q * siz.YTsiz, siz.YOsiz);
tile.tx1 = Math.min(siz.XTOsiz + (p + 1) * siz.XTsiz, siz.Xsiz);
@@ -35511,9 +35506,9 @@ var JpxImage = (function JpxImageClosure() {
var componentsCount = siz.Csiz;
for (var i = 0, ii = componentsCount; i < ii; i++) {
var component = components[i];
- var tileComponents = [];
for (var j = 0, jj = tiles.length; j < jj; j++) {
- var tileComponent = {}, tile = tiles[j];
+ var tileComponent = {};
+ tile = tiles[j];
tileComponent.tcx0 = Math.ceil(tile.tx0 / component.XRsiz);
tileComponent.tcy0 = Math.ceil(tile.ty0 / component.YRsiz);
tileComponent.tcx1 = Math.ceil(tile.tx1 / component.XRsiz);
@@ -35535,27 +35530,27 @@ var JpxImage = (function JpxImageClosure() {
result.PPy = codOrCoc.precinctsSizes[r].PPy;
}
// calculate codeblock size as described in section B.7
- result.xcb_ = r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :
- Math.min(codOrCoc.xcb, result.PPx);
- result.ycb_ = r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :
- Math.min(codOrCoc.ycb, result.PPy);
+ result.xcb_ = (r > 0 ? Math.min(codOrCoc.xcb, result.PPx - 1) :
+ Math.min(codOrCoc.xcb, result.PPx));
+ result.ycb_ = (r > 0 ? Math.min(codOrCoc.ycb, result.PPy - 1) :
+ Math.min(codOrCoc.ycb, result.PPy));
return result;
}
function buildPrecincts(context, resolution, dimensions) {
// Section B.6 Division resolution to precincts
var precinctWidth = 1 << dimensions.PPx;
var precinctHeight = 1 << dimensions.PPy;
- var numprecinctswide = resolution.trx1 > resolution.trx0 ?
+ var numprecinctswide = (resolution.trx1 > resolution.trx0 ?
Math.ceil(resolution.trx1 / precinctWidth) -
- Math.floor(resolution.trx0 / precinctWidth) : 0;
- var numprecinctshigh = resolution.try1 > resolution.try0 ?
+ Math.floor(resolution.trx0 / precinctWidth) : 0);
+ var numprecinctshigh = (resolution.try1 > resolution.try0 ?
Math.ceil(resolution.try1 / precinctHeight) -
- Math.floor(resolution.try0 / precinctHeight) : 0;
+ Math.floor(resolution.try0 / precinctHeight) : 0);
var numprecincts = numprecinctswide * numprecinctshigh;
var precinctXOffset = Math.floor(resolution.trx0 / precinctWidth) *
- precinctWidth;
+ precinctWidth;
var precinctYOffset = Math.floor(resolution.try0 / precinctHeight) *
- precinctHeight;
+ precinctHeight;
resolution.precinctParameters = {
precinctXOffset: precinctXOffset,
precinctYOffset: precinctYOffset,
@@ -35572,16 +35567,17 @@ var JpxImage = (function JpxImageClosure() {
var ycb_ = dimensions.ycb_;
var codeblockWidth = 1 << xcb_;
var codeblockHeight = 1 << ycb_;
- var cbx0 = Math.floor(subband.tbx0 / codeblockWidth);
- var cby0 = Math.floor(subband.tby0 / codeblockHeight);
- var cbx1 = Math.ceil(subband.tbx1 / codeblockWidth);
- var cby1 = Math.ceil(subband.tby1 / codeblockHeight);
+ var cbx0 = subband.tbx0 >> xcb_;
+ var cby0 = subband.tby0 >> ycb_;
+ var cbx1 = (subband.tbx1 + codeblockWidth - 1) >> xcb_;
+ var cby1 = (subband.tby1 + codeblockHeight - 1) >> ycb_;
var precinctParameters = subband.resolution.precinctParameters;
var codeblocks = [];
var precincts = [];
- for (var j = cby0; j < cby1; j++) {
- for (var i = cbx0; i < cbx1; i++) {
- var codeblock = {
+ var i, j, codeblock, precinctNumber;
+ for (j = cby0; j < cby1; j++) {
+ for (i = cbx0; i < cbx1; i++) {
+ codeblock = {
cbx: i,
cby: j,
tbx0: codeblockWidth * i,
@@ -35591,31 +35587,33 @@ var JpxImage = (function JpxImageClosure() {
};
// calculate precinct number
var pi = Math.floor((codeblock.tbx0 -
- precinctParameters.precinctXOffset) /
- precinctParameters.precinctWidth);
+ precinctParameters.precinctXOffset) /
+ precinctParameters.precinctWidth);
var pj = Math.floor((codeblock.tby0 -
- precinctParameters.precinctYOffset) /
- precinctParameters.precinctHeight);
- var precinctNumber = pj +
- pi * precinctParameters.numprecinctswide;
+ precinctParameters.precinctYOffset) /
+ precinctParameters.precinctHeight);
+ precinctNumber = pj + pi * precinctParameters.numprecinctswide;
codeblock.tbx0_ = Math.max(subband.tbx0, codeblock.tbx0);
codeblock.tby0_ = Math.max(subband.tby0, codeblock.tby0);
codeblock.tbx1_ = Math.min(subband.tbx1, codeblock.tbx1);
codeblock.tby1_ = Math.min(subband.tby1, codeblock.tby1);
codeblock.precinctNumber = precinctNumber;
codeblock.subbandType = subband.type;
- var coefficientsLength = (codeblock.tbx1_ - codeblock.tbx0_) *
- (codeblock.tby1_ - codeblock.tby0_);
codeblock.Lblock = 3;
codeblocks.push(codeblock);
// building precinct for the sub-band
- var precinct;
- if (precinctNumber in precincts) {
- precinct = precincts[precinctNumber];
- precinct.cbxMin = Math.min(precinct.cbxMin, i);
- precinct.cbyMin = Math.min(precinct.cbyMin, j);
- precinct.cbxMax = Math.max(precinct.cbxMax, i);
- precinct.cbyMax = Math.max(precinct.cbyMax, j);
+ var precinct = precincts[precinctNumber];
+ if (precinct !== undefined) {
+ if (i < precinct.cbxMin) {
+ precinct.cbxMin = i;
+ } else if (i > precinct.cbxMax) {
+ precinct.cbxMax = i;
+ }
+ if (j < precinct.cbyMin) {
+ precinct.cbxMin = j;
+ } else if (j > precinct.cbyMax) {
+ precinct.cbyMax = j;
+ }
} else {
precincts[precinctNumber] = precinct = {
cbxMin: i,
@@ -35631,13 +35629,9 @@ var JpxImage = (function JpxImageClosure() {
codeblockWidth: xcb_,
codeblockHeight: ycb_,
numcodeblockwide: cbx1 - cbx0 + 1,
- numcodeblockhigh: cby1 - cby1 + 1
+ numcodeblockhigh: cby1 - cby0 + 1
};
subband.codeblocks = codeblocks;
- for (var i = 0, ii = codeblocks.length; i < ii; i++) {
- var codeblock = codeblocks[i];
- var precinctNumber = codeblock.precinctNumber;
- }
subband.precincts = precincts;
}
function createPacket(resolution, precinctNumber, layerNumber) {
@@ -35650,8 +35644,9 @@ var JpxImage = (function JpxImageClosure() {
var codeblocks = subband.codeblocks;
for (var j = 0, jj = codeblocks.length; j < jj; j++) {
var codeblock = codeblocks[j];
- if (codeblock.precinctNumber != precinctNumber)
+ if (codeblock.precinctNumber !== precinctNumber) {
continue;
+ }
precinctCodeblocks.push(codeblock);
}
}
@@ -35680,8 +35675,9 @@ var JpxImage = (function JpxImageClosure() {
for (; r <= maxDecompositionLevelsCount; r++) {
for (; i < componentsCount; i++) {
var component = tile.components[i];
- if (r > component.codingStyleParameters.decompositionLevelsCount)
+ if (r > component.codingStyleParameters.decompositionLevelsCount) {
continue;
+ }
var resolution = component.resolutions[r];
var numprecincts = resolution.precinctParameters.numprecincts;
@@ -35696,7 +35692,7 @@ var JpxImage = (function JpxImageClosure() {
}
r = 0;
}
- throw 'Out of packets';
+ throw new Error('JPX Error: Out of packets');
};
}
function ResolutionLayerComponentPositionIterator(context) {
@@ -35719,8 +35715,9 @@ var JpxImage = (function JpxImageClosure() {
for (; l < layersCount; l++) {
for (; i < componentsCount; i++) {
var component = tile.components[i];
- if (r > component.codingStyleParameters.decompositionLevelsCount)
+ if (r > component.codingStyleParameters.decompositionLevelsCount) {
continue;
+ }
var resolution = component.resolutions[r];
var numprecincts = resolution.precinctParameters.numprecincts;
@@ -35735,7 +35732,7 @@ var JpxImage = (function JpxImageClosure() {
}
l = 0;
}
- throw 'Out of packets';
+ throw new Error('JPX Error: Out of packets');
};
}
function buildPackets(context) {
@@ -35820,7 +35817,6 @@ var JpxImage = (function JpxImageClosure() {
}
// Generate the packets sequence
var progressionOrder = tile.codingStyleDefaultParameters.progressionOrder;
- var packetsIterator;
switch (progressionOrder) {
case 0:
tile.packetsIterator =
@@ -35831,7 +35827,8 @@ var JpxImage = (function JpxImageClosure() {
new ResolutionLayerComponentPositionIterator(context);
break;
default:
- throw 'Unsupported progression order ' + progressionOrder;
+ throw new Error('JPX Error: Unsupported progression order ' +
+ progressionOrder);
}
}
function parseTilePackets(context, data, offset, dataLength) {
@@ -35849,7 +35846,7 @@ var JpxImage = (function JpxImageClosure() {
buffer = (buffer << 8) | b;
bufferSize += 8;
}
- if (b == 0xFF) {
+ if (b === 0xFF) {
skipNextBit = true;
}
}
@@ -35864,20 +35861,22 @@ var JpxImage = (function JpxImageClosure() {
}
}
function readCodingpasses() {
- var value = readBits(1);
- if (value === 0)
+ if (readBits(1) === 0) {
return 1;
- value = (value << 1) | readBits(1);
- if (value == 0x02)
+ }
+ if (readBits(1) === 0) {
return 2;
- value = (value << 2) | readBits(2);
- if (value <= 0x0E)
- return (value & 0x03) + 3;
- value = (value << 5) | readBits(5);
- if (value <= 0x1FE)
- return (value & 0x1F) + 6;
- value = (value << 7) | readBits(7);
- return (value & 0x7F) + 37;
+ }
+ var value = readBits(2);
+ if (value < 3) {
+ return value + 3;
+ }
+ value = readBits(5);
+ if (value < 31) {
+ return value + 6;
+ }
+ value = readBits(7);
+ return value + 37;
}
var tileIndex = context.currentTile.index;
var tile = context.tiles[tileIndex];
@@ -35889,19 +35888,20 @@ var JpxImage = (function JpxImageClosure() {
continue;
}
var layerNumber = packet.layerNumber;
- var queue = [];
+ var queue = [], codeblock;
for (var i = 0, ii = packet.codeblocks.length; i < ii; i++) {
- var codeblock = packet.codeblocks[i];
+ codeblock = packet.codeblocks[i];
var precinct = codeblock.precinct;
var codeblockColumn = codeblock.cbx - precinct.cbxMin;
var codeblockRow = codeblock.cby - precinct.cbyMin;
var codeblockIncluded = false;
var firstTimeInclusion = false;
+ var valueReady;
if ('included' in codeblock) {
codeblockIncluded = !!readBits(1);
} else {
// reading inclusion tree
- var precinct = codeblock.precinct;
+ precinct = codeblock.precinct;
var inclusionTree, zeroBitPlanesTree;
if ('inclusionTree' in precinct) {
inclusionTree = precinct.inclusionTree;
@@ -35918,7 +35918,7 @@ var JpxImage = (function JpxImageClosure() {
if (inclusionTree.reset(codeblockColumn, codeblockRow, layerNumber)) {
while (true) {
if (readBits(1)) {
- var valueReady = !inclusionTree.nextLevel();
+ valueReady = !inclusionTree.nextLevel();
if (valueReady) {
codeblock.included = true;
codeblockIncluded = firstTimeInclusion = true;
@@ -35931,24 +35931,28 @@ var JpxImage = (function JpxImageClosure() {
}
}
}
- if (!codeblockIncluded)
+ if (!codeblockIncluded) {
continue;
+ }
if (firstTimeInclusion) {
zeroBitPlanesTree = precinct.zeroBitPlanesTree;
zeroBitPlanesTree.reset(codeblockColumn, codeblockRow);
while (true) {
if (readBits(1)) {
- var valueReady = !zeroBitPlanesTree.nextLevel();
- if (valueReady)
+ valueReady = !zeroBitPlanesTree.nextLevel();
+ if (valueReady) {
break;
- } else
+ }
+ } else {
zeroBitPlanesTree.incrementValue();
+ }
}
codeblock.zeroBitPlanes = zeroBitPlanesTree.value;
}
var codingpasses = readCodingpasses();
- while (readBits(1))
+ while (readBits(1)) {
codeblock.Lblock++;
+ }
var codingpassesLog2 = log2(codingpasses);
// rounding down log2
var bits = ((codingpasses < (1 << codingpassesLog2)) ?
@@ -35963,9 +35967,10 @@ var JpxImage = (function JpxImageClosure() {
alignToByte();
while (queue.length > 0) {
var packetItem = queue.shift();
- var codeblock = packetItem.codeblock;
- if (!('data' in codeblock))
+ codeblock = packetItem.codeblock;
+ if (!('data' in codeblock)) {
codeblock.data = [];
+ }
codeblock.data.push({
data: data,
start: offset + position,
@@ -35977,43 +35982,52 @@ var JpxImage = (function JpxImageClosure() {
}
return position;
}
- function copyCoefficients(coefficients, x0, y0, width, height,
- delta, mb, codeblocks, transformation,
- segmentationSymbolUsed) {
- var r = 0.5; // formula (E-6)
+ function copyCoefficients(coefficients, levelWidth, levelHeight, subband,
+ delta, mb, reversible, segmentationSymbolUsed) {
+ var x0 = subband.tbx0;
+ var y0 = subband.tby0;
+ var width = subband.tbx1 - subband.tbx0;
+ var codeblocks = subband.codeblocks;
+ var right = subband.type.charAt(0) === 'H' ? 1 : 0;
+ var bottom = subband.type.charAt(1) === 'H' ? levelWidth : 0;
+
for (var i = 0, ii = codeblocks.length; i < ii; ++i) {
var codeblock = codeblocks[i];
var blockWidth = codeblock.tbx1_ - codeblock.tbx0_;
var blockHeight = codeblock.tby1_ - codeblock.tby0_;
- if (blockWidth === 0 || blockHeight === 0)
+ if (blockWidth === 0 || blockHeight === 0) {
continue;
- if (!('data' in codeblock))
+ }
+ if (!('data' in codeblock)) {
continue;
+ }
var bitModel, currentCodingpassType;
bitModel = new BitModel(blockWidth, blockHeight, codeblock.subbandType,
- codeblock.zeroBitPlanes);
+ codeblock.zeroBitPlanes, mb);
currentCodingpassType = 2; // first bit plane starts from cleanup
// collect data
var data = codeblock.data, totalLength = 0, codingpasses = 0;
- for (var q = 0, qq = data.length; q < qq; q++) {
- var dataItem = data[q];
+ var j, jj, dataItem;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
totalLength += dataItem.end - dataItem.start;
codingpasses += dataItem.codingpasses;
}
- var encodedData = new Uint8Array(totalLength), k = 0;
- for (var q = 0, qq = data.length; q < qq; q++) {
- var dataItem = data[q];
+ var encodedData = new Uint8Array(totalLength);
+ var position = 0;
+ for (j = 0, jj = data.length; j < jj; j++) {
+ dataItem = data[j];
var chunk = dataItem.data.subarray(dataItem.start, dataItem.end);
- encodedData.set(chunk, k);
- k += chunk.length;
+ encodedData.set(chunk, position);
+ position += chunk.length;
}
// decoding the item
var decoder = new ArithmeticDecoder(encodedData, 0, totalLength);
bitModel.setDecoder(decoder);
- for (var q = 0; q < codingpasses; q++) {
+ for (j = 0; j < codingpasses; j++) {
switch (currentCodingpassType) {
case 0:
bitModel.runSignificancePropogationPass();
@@ -36023,28 +36037,43 @@ var JpxImage = (function JpxImageClosure() {
break;
case 2:
bitModel.runCleanupPass();
- if (segmentationSymbolUsed)
+ if (segmentationSymbolUsed) {
bitModel.checkSegmentationSymbol();
+ }
break;
}
currentCodingpassType = (currentCodingpassType + 1) % 3;
}
var offset = (codeblock.tbx0_ - x0) + (codeblock.tby0_ - y0) * width;
- var position = 0;
- for (var j = 0; j < blockHeight; j++) {
- for (var k = 0; k < blockWidth; k++) {
- var n = (bitModel.coefficentsSign[position] ? -1 : 1) *
- bitModel.coefficentsMagnitude[position];
- var nb = bitModel.bitsDecoded[position], correction;
- if (transformation === 0 || mb > nb) {
- // use r only if transformation is irreversible or
- // not all bitplanes were decoded for reversible transformation
- n += n < 0 ? n - r : n > 0 ? n + r : 0;
- correction = 1 << (mb - nb);
- } else
- correction = 1;
- coefficients[offset++] = n * correction * delta;
+ var sign = bitModel.coefficentsSign;
+ var magnitude = bitModel.coefficentsMagnitude;
+ var bitsDecoded = bitModel.bitsDecoded;
+ var magnitudeCorrection = reversible ? 0 : 0.5;
+ var k, n, nb;
+ position = 0;
+ // Do the interleaving of Section F.3.3 here, so we do not need
+ // to copy later. LL level is not interleaved, just copied.
+ var interleave = (subband.type !== 'LL');
+ for (j = 0; j < blockHeight; j++) {
+ var row = (offset / width) | 0; // row in the non-interleaved subband
+ var levelOffset = 2 * row * (levelWidth - width) + right + bottom;
+ for (k = 0; k < blockWidth; k++) {
+ n = magnitude[position];
+ if (n !== 0) {
+ n = (n + magnitudeCorrection) * delta;
+ if (sign[position] !== 0) {
+ n = -n;
+ }
+ nb = bitsDecoded[position];
+ var pos = interleave ? (levelOffset + (offset << 1)) : offset;
+ if (reversible && (nb >= mb)) {
+ coefficients[pos] = n;
+ } else {
+ coefficients[pos] = n * (1 << (mb - nb));
+ }
+ }
+ offset++;
position++;
}
offset += width - blockWidth;
@@ -36060,15 +36089,23 @@ var JpxImage = (function JpxImageClosure() {
var spqcds = quantizationParameters.SPqcds;
var scalarExpounded = quantizationParameters.scalarExpounded;
var guardBits = quantizationParameters.guardBits;
- var transformation = codingStyleParameters.transformation;
var segmentationSymbolUsed = codingStyleParameters.segmentationSymbolUsed;
var precision = context.components[c].precision;
+ var reversible = codingStyleParameters.reversibleTransformation;
+ var transform = (reversible ? new ReversibleTransform() :
+ new IrreversibleTransform());
+
var subbandCoefficients = [];
- var k = 0, b = 0;
+ var b = 0;
for (var i = 0; i <= decompositionLevelsCount; i++) {
var resolution = component.resolutions[i];
+ var width = resolution.trx1 - resolution.trx0;
+ var height = resolution.try1 - resolution.try0;
+ // Allocate space for the whole sublevel.
+ var coefficients = new Float32Array(width * height);
+
for (var j = 0, jj = resolution.subbands.length; j < jj; j++) {
var mu, epsilon;
if (!scalarExpounded) {
@@ -36078,38 +36115,34 @@ var JpxImage = (function JpxImageClosure() {
} else {
mu = spqcds[b].mu;
epsilon = spqcds[b].epsilon;
+ b++;
}
var subband = resolution.subbands[j];
- var width = subband.tbx1 - subband.tbx0;
- var height = subband.tby1 - subband.tby0;
var gainLog2 = SubbandsGainLog2[subband.type];
// calulate quantization coefficient (Section E.1.1.1)
- var delta = Math.pow(2, (precision + gainLog2) - epsilon) *
- (1 + mu / 2048);
+ var delta = (reversible ? 1 :
+ Math.pow(2, precision + gainLog2 - epsilon) * (1 + mu / 2048));
var mb = (guardBits + epsilon - 1);
- var coefficients = new Float32Array(width * height);
- copyCoefficients(coefficients, subband.tbx0, subband.tby0,
- width, height, delta, mb, subband.codeblocks, transformation,
- segmentationSymbolUsed);
-
- subbandCoefficients.push({
- width: width,
- height: height,
- items: coefficients
- });
-
- b++;
+ // In the first resolution level, copyCoefficients will fill the
+ // whole array with coefficients. In the succeding passes,
+ // copyCoefficients will consecutively fill in the values that belong
+ // to the interleaved positions of the HL, LH, and HH coefficients.
+ // The LL coefficients will then be interleaved in Transform.iterate().
+ copyCoefficients(coefficients, width, height, subband, delta, mb,
+ reversible, segmentationSymbolUsed);
}
+ subbandCoefficients.push({
+ width: width,
+ height: height,
+ items: coefficients
+ });
}
- var transformation = codingStyleParameters.transformation;
- var transform = transformation === 0 ? new IrreversibleTransform() :
- new ReversibleTransform();
var result = transform.calculate(subbandCoefficients,
- component.tcx0, component.tcy0);
+ component.tcx0, component.tcy0);
return {
left: component.tcx0,
top: component.tcy0,
@@ -36125,54 +36158,91 @@ var JpxImage = (function JpxImageClosure() {
var resultImages = [];
for (var i = 0, ii = context.tiles.length; i < ii; i++) {
var tile = context.tiles[i];
- var result = [];
- for (var c = 0; c < componentsCount; c++) {
- var image = transformTile(context, tile, c);
- result.push(image);
+ var transformedTiles = [];
+ var c;
+ for (c = 0; c < componentsCount; c++) {
+ transformedTiles[c] = transformTile(context, tile, c);
}
+ var tile0 = transformedTiles[0];
+ var out = new Uint8Array(tile0.items.length * componentsCount);
+ var result = {
+ left: tile0.left,
+ top: tile0.top,
+ width: tile0.width,
+ height: tile0.height,
+ items: out
+ };
// Section G.2.2 Inverse multi component transform
+ var shift, offset, max, min, maxK;
+ var pos = 0, j, jj, y0, y1, y2, r, g, b, k, val;
if (tile.codingStyleDefaultParameters.multipleComponentTransform) {
- var y0items = result[0].items;
- var y1items = result[1].items;
- var y2items = result[2].items;
- for (var j = 0, jj = y0items.length; j < jj; j++) {
- var y0 = y0items[j], y1 = y1items[j], y2 = y2items[j];
- var i1 = y0 - ((y2 + y1) >> 2);
- y1items[j] = i1;
- y0items[j] = y2 + i1;
- y2items[j] = y1 + i1;
+ var fourComponents = componentsCount === 4;
+ var y0items = transformedTiles[0].items;
+ var y1items = transformedTiles[1].items;
+ var y2items = transformedTiles[2].items;
+ var y3items = fourComponents ? transformedTiles[3].items : null;
+
+ // HACK: The multiple component transform formulas below assume that
+ // all components have the same precision. With this in mind, we
+ // compute shift and offset only once.
+ shift = components[0].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = 255 * (1 << shift);
+ maxK = max * 0.5;
+ min = -maxK;
+
+ var component0 = tile.components[0];
+ var alpha01 = componentsCount - 3;
+ jj = y0items.length;
+ if (!component0.codingStyleParameters.reversibleTransformation) {
+ // inverse irreversible multiple component transform
+ for (j = 0; j < jj; j++, pos += alpha01) {
+ y0 = y0items[j] + offset;
+ y1 = y1items[j];
+ y2 = y2items[j];
+ r = y0 + 1.402 * y2;
+ g = y0 - 0.34413 * y1 - 0.71414 * y2;
+ b = y0 + 1.772 * y1;
+ out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
+ out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
+ out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
+ }
+ } else {
+ // inverse reversible multiple component transform
+ for (j = 0; j < jj; j++, pos += alpha01) {
+ y0 = y0items[j] + offset;
+ y1 = y1items[j];
+ y2 = y2items[j];
+ g = y0 - ((y2 + y1) >> 2);
+ r = g + y2;
+ b = g + y1;
+ out[pos++] = r <= 0 ? 0 : r >= max ? 255 : r >> shift;
+ out[pos++] = g <= 0 ? 0 : g >= max ? 255 : g >> shift;
+ out[pos++] = b <= 0 ? 0 : b >= max ? 255 : b >> shift;
+ }
+ }
+ if (fourComponents) {
+ for (j = 0, pos = 3; j < jj; j++, pos += 4) {
+ k = y3items[j];
+ out[pos] = k <= min ? 0 : k >= maxK ? 255 : (k + offset) >> shift;
+ }
+ }
+ } else { // no multi-component transform
+ for (c = 0; c < componentsCount; c++) {
+ var items = transformedTiles[c].items;
+ shift = components[c].precision - 8;
+ offset = (128 << shift) + 0.5;
+ max = (127.5 * (1 << shift));
+ min = -max;
+ for (pos = c, j = 0, jj = items.length; j < jj; j++) {
+ val = items[j];
+ out[pos] = val <= min ? 0 :
+ val >= max ? 255 : (val + offset) >> shift;
+ pos += componentsCount;
+ }
}
}
-
- // Section G.1 DC level shifting to unsigned component values
- for (var c = 0; c < componentsCount; c++) {
- var component = components[c];
- if (component.isSigned)
- continue;
-
- var offset = 1 << (component.precision - 1);
- var tileImage = result[c];
- var items = tileImage.items;
- for (var j = 0, jj = items.length; j < jj; j++)
- items[j] += offset;
- }
-
- // To simplify things: shift and clamp output to 8 bit unsigned
- for (var c = 0; c < componentsCount; c++) {
- var component = components[c];
- var offset = component.isSigned ? 128 : 0;
- var shift = component.precision - 8;
- var tileImage = result[c];
- var items = tileImage.items;
- var data = new Uint8Array(items.length);
- for (var j = 0, jj = items.length; j < jj; j++) {
- var value = (items[j] >> shift) + offset;
- data[j] = value < 0 ? 0 : value > 255 ? 255 : value;
- }
- result[c].items = data;
- }
-
resultImages.push(result);
}
return resultImages;
@@ -36181,14 +36251,13 @@ var JpxImage = (function JpxImageClosure() {
var siz = context.SIZ;
var componentsCount = siz.Csiz;
var tile = context.tiles[tileIndex];
- var resultTiles = [];
for (var c = 0; c < componentsCount; c++) {
var component = tile.components[c];
- var qcdOrQcc = c in context.currentTile.QCC ?
- context.currentTile.QCC[c] : context.currentTile.QCD;
+ var qcdOrQcc = (c in context.currentTile.QCC ?
+ context.currentTile.QCC[c] : context.currentTile.QCD);
component.quantizationParameters = qcdOrQcc;
- var codOrCoc = c in context.currentTile.COC ?
- context.currentTile.COC[c] : context.currentTile.COD;
+ var codOrCoc = (c in context.currentTile.COC ?
+ context.currentTile.COC[c] : context.currentTile.COD);
component.codingStyleParameters = codOrCoc;
}
tile.codingStyleDefaultParameters = context.currentTile.COD;
@@ -36212,9 +36281,9 @@ var JpxImage = (function JpxImageClosure() {
}
TagTree.prototype = {
reset: function TagTree_reset(i, j) {
- var currentLevel = 0, value = 0;
+ var currentLevel = 0, value = 0, level;
while (currentLevel < this.levels.length) {
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
var index = i + j * level.width;
if (index in level.items) {
value = level.items[index];
@@ -36226,7 +36295,7 @@ var JpxImage = (function JpxImageClosure() {
currentLevel++;
}
currentLevel--;
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
level.items[level.index] = value;
this.currentLevel = currentLevel;
delete this.value;
@@ -36246,7 +36315,7 @@ var JpxImage = (function JpxImageClosure() {
}
this.currentLevel = currentLevel;
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
level.items[level.index] = value;
return true;
}
@@ -36260,8 +36329,9 @@ var JpxImage = (function JpxImageClosure() {
this.levels = [];
for (var i = 0; i < levelsLength; i++) {
var items = new Uint8Array(width * height);
- for (var j = 0, jj = items.length; j < jj; j++)
+ for (var j = 0, jj = items.length; j < jj; j++) {
items[j] = defaultValue;
+ }
var level = {
width: width,
@@ -36283,8 +36353,9 @@ var JpxImage = (function JpxImageClosure() {
level.index = index;
var value = level.items[index];
- if (value == 0xFF)
+ if (value === 0xFF) {
break;
+ }
if (value > stopValue) {
this.currentLevel = currentLevel;
@@ -36310,7 +36381,7 @@ var JpxImage = (function JpxImageClosure() {
var level = this.levels[levelIndex];
var currentValue = level.items[level.index];
while (--levelIndex >= 0) {
- var level = this.levels[levelIndex];
+ level = this.levels[levelIndex];
level.items[level.index] = currentValue;
}
},
@@ -36320,11 +36391,12 @@ var JpxImage = (function JpxImageClosure() {
var value = level.items[level.index];
level.items[level.index] = 0xFF;
currentLevel--;
- if (currentLevel < 0)
+ if (currentLevel < 0) {
return false;
+ }
this.currentLevel = currentLevel;
- var level = this.levels[currentLevel];
+ level = this.levels[currentLevel];
level.items[level.index] = value;
return true;
}
@@ -36332,171 +36404,10 @@ var JpxImage = (function JpxImageClosure() {
return InclusionTree;
})();
- // Implements C.3. Arithmetic decoding procedures
- var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
- var QeTable = [
- {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
- {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
- {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
- {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
- {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
- {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
- {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
- {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
- {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
- {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
- {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
- {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
- {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
- {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
- {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
- {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
- {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
- {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
- {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
- {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
- {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
- {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
- {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
- {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
- {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
- {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
- {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
- {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
- {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
- {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
- {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
- {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
- {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
- {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
- {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
- {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
- {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
- {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
- {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
- {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
- {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
- {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
- {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
- {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
- {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
- {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
- {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
- ];
-
- function ArithmeticDecoder(data, start, end) {
- this.data = data;
- this.bp = start;
- this.dataEnd = end;
-
- this.chigh = data[start];
- this.clow = 0;
-
- this.byteIn();
-
- this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
- this.clow = (this.clow << 7) & 0xFFFF;
- this.ct -= 7;
- this.a = 0x8000;
- }
-
- ArithmeticDecoder.prototype = {
- byteIn: function ArithmeticDecoder_byteIn() {
- var data = this.data;
- var bp = this.bp;
- if (data[bp] == 0xFF) {
- var b1 = data[bp + 1];
- if (b1 > 0x8F) {
- this.clow += 0xFF00;
- this.ct = 8;
- } else {
- bp++;
- this.clow += (data[bp] << 9);
- this.ct = 7;
- this.bp = bp;
- }
- } else {
- bp++;
- this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
- this.ct = 8;
- this.bp = bp;
- }
- if (this.clow > 0xFFFF) {
- this.chigh += (this.clow >> 16);
- this.clow &= 0xFFFF;
- }
- },
- readBit: function ArithmeticDecoder_readBit(cx) {
- var qeIcx = QeTable[cx.index].qe;
- this.a -= qeIcx;
-
- if (this.chigh < qeIcx) {
- var d = this.exchangeLps(cx);
- this.renormD();
- return d;
- } else {
- this.chigh -= qeIcx;
- if ((this.a & 0x8000) === 0) {
- var d = this.exchangeMps(cx);
- this.renormD();
- return d;
- } else {
- return cx.mps;
- }
- }
- },
- renormD: function ArithmeticDecoder_renormD() {
- do {
- if (this.ct === 0)
- this.byteIn();
-
- this.a <<= 1;
- this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
- this.clow = (this.clow << 1) & 0xFFFF;
- this.ct--;
- } while ((this.a & 0x8000) === 0);
- },
- exchangeMps: function ArithmeticDecoder_exchangeMps(cx) {
- var d;
- var qeTableIcx = QeTable[cx.index];
- if (this.a < qeTableIcx.qe) {
- d = 1 - cx.mps;
-
- if (qeTableIcx.switchFlag == 1) {
- cx.mps = 1 - cx.mps;
- }
- cx.index = qeTableIcx.nlps;
- } else {
- d = cx.mps;
- cx.index = qeTableIcx.nmps;
- }
- return d;
- },
- exchangeLps: function ArithmeticDecoder_exchangeLps(cx) {
- var d;
- var qeTableIcx = QeTable[cx.index];
- if (this.a < qeTableIcx.qe) {
- this.a = qeTableIcx.qe;
- d = cx.mps;
- cx.index = qeTableIcx.nmps;
- } else {
- this.a = qeTableIcx.qe;
- d = 1 - cx.mps;
-
- if (qeTableIcx.switchFlag == 1) {
- cx.mps = 1 - cx.mps;
- }
- cx.index = qeTableIcx.nlps;
- }
- return d;
- }
- };
-
- return ArithmeticDecoder;
- })();
-
// Section D. Coefficient bit modeling
var BitModel = (function BitModelClosure() {
+ var UNIFORM_CONTEXT = 17;
+ var RUNLENGTH_CONTEXT = 18;
// Table D-1
// The index is binary presentation: 0dddvvhh, ddd - sum of Di (0..4),
// vv - sum of Vi (0..2), and hh - sum of Hi (0..2)
@@ -36516,35 +36427,12 @@ var JpxImage = (function JpxImageClosure() {
8, 0, 8, 8, 8, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, 8, 8, 0, 8, 8, 8, 0, 8, 8, 8
]);
- // Table D-2
- function calcSignContribution(significance0, sign0, significance1, sign1) {
- if (significance1) {
- if (!sign1)
- return significance0 ? (!sign0 ? 1 : 0) : 1;
- else
- return significance0 ? (!sign0 ? 0 : -1) : -1;
- } else
- return significance0 ? (!sign0 ? 1 : -1) : 0;
- }
- // Table D-3
- var SignContextLabels = [
- {contextLabel: 13, xorBit: 0},
- {contextLabel: 12, xorBit: 0},
- {contextLabel: 11, xorBit: 0},
- {contextLabel: 10, xorBit: 0},
- {contextLabel: 9, xorBit: 0},
- {contextLabel: 10, xorBit: 1},
- {contextLabel: 11, xorBit: 1},
- {contextLabel: 12, xorBit: 1},
- {contextLabel: 13, xorBit: 1}
- ];
-
- function BitModel(width, height, subband, zeroBitPlanes) {
+ function BitModel(width, height, subband, zeroBitPlanes, mb) {
this.width = width;
this.height = height;
- this.contextLabelTable = subband == 'HH' ? HHContextLabel :
- subband == 'HL' ? HLContextLabel : LLAndLHContextsLabel;
+ this.contextLabelTable = (subband === 'HH' ? HHContextLabel :
+ (subband === 'HL' ? HLContextLabel : LLAndLHContextsLabel));
var coefficientCount = width * height;
@@ -36552,12 +36440,17 @@ var JpxImage = (function JpxImageClosure() {
// add border state cells for significanceState
this.neighborsSignificance = new Uint8Array(coefficientCount);
this.coefficentsSign = new Uint8Array(coefficientCount);
- this.coefficentsMagnitude = new Uint32Array(coefficientCount);
+ this.coefficentsMagnitude = mb > 14 ? new Uint32Array(coefficientCount) :
+ mb > 6 ? new Uint16Array(coefficientCount) :
+ new Uint8Array(coefficientCount);
this.processingFlags = new Uint8Array(coefficientCount);
- var bitsDecoded = new Uint8Array(this.width * this.height);
- for (var i = 0, ii = bitsDecoded.length; i < ii; i++)
- bitsDecoded[i] = zeroBitPlanes;
+ var bitsDecoded = new Uint8Array(coefficientCount);
+ if (zeroBitPlanes !== 0) {
+ for (var i = 0; i < coefficientCount; i++) {
+ bitsDecoded[i] = zeroBitPlanes;
+ }
+ }
this.bitsDecoded = bitsDecoded;
this.reset();
@@ -36568,36 +36461,52 @@ var JpxImage = (function JpxImageClosure() {
this.decoder = decoder;
},
reset: function BitModel_reset() {
- this.uniformContext = {index: 46, mps: 0};
- this.runLengthContext = {index: 3, mps: 0};
- this.contexts = [];
- this.contexts.push({index: 4, mps: 0});
- for (var i = 1; i <= 16; i++)
- this.contexts.push({index: 0, mps: 0});
+ // We have 17 contexts that are accessed via context labels,
+ // plus the uniform and runlength context.
+ this.contexts = new Int8Array(19);
+
+ // Contexts are packed into 1 byte:
+ // highest 7 bits carry the index, lowest bit carries mps
+ this.contexts[0] = (4 << 1) | 0;
+ this.contexts[UNIFORM_CONTEXT] = (46 << 1) | 0;
+ this.contexts[RUNLENGTH_CONTEXT] = (3 << 1) | 0;
},
setNeighborsSignificance:
- function BitModel_setNeighborsSignificance(row, column) {
+ function BitModel_setNeighborsSignificance(row, column, index) {
var neighborsSignificance = this.neighborsSignificance;
var width = this.width, height = this.height;
- var index = row * width + column;
+ var left = (column > 0);
+ var right = (column + 1 < width);
+ var i;
+
if (row > 0) {
- if (column > 0)
- neighborsSignificance[index - width - 1] += 0x10;
- if (column + 1 < width)
- neighborsSignificance[index - width + 1] += 0x10;
- neighborsSignificance[index - width] += 0x04;
+ i = index - width;
+ if (left) {
+ neighborsSignificance[i - 1] += 0x10;
+ }
+ if (right) {
+ neighborsSignificance[i + 1] += 0x10;
+ }
+ neighborsSignificance[i] += 0x04;
}
+
if (row + 1 < height) {
- if (column > 0)
- neighborsSignificance[index + width - 1] += 0x10;
- if (column + 1 < width)
- neighborsSignificance[index + width + 1] += 0x10;
- neighborsSignificance[index + width] += 0x04;
+ i = index + width;
+ if (left) {
+ neighborsSignificance[i - 1] += 0x10;
+ }
+ if (right) {
+ neighborsSignificance[i + 1] += 0x10;
+ }
+ neighborsSignificance[i] += 0x04;
}
- if (column > 0)
+
+ if (left) {
neighborsSignificance[index - 1] += 0x01;
- if (column + 1 < width)
+ }
+ if (right) {
neighborsSignificance[index + 1] += 0x01;
+ }
neighborsSignificance[index] |= 0x80;
},
runSignificancePropogationPass:
@@ -36606,38 +36515,38 @@ var JpxImage = (function JpxImageClosure() {
var width = this.width, height = this.height;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
- var contextLabels = this.contextLabels;
var neighborsSignificance = this.neighborsSignificance;
var processingFlags = this.processingFlags;
var contexts = this.contexts;
var labels = this.contextLabelTable;
var bitsDecoded = this.bitsDecoded;
- // clear processed flag
var processedInverseMask = ~1;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
- for (var q = 0, qq = width * height; q < qq; q++)
- processingFlags[q] &= processedInverseMask;
for (var i0 = 0; i0 < height; i0 += 4) {
for (var j = 0; j < width; j++) {
var index = i0 * width + j;
for (var i1 = 0; i1 < 4; i1++, index += width) {
var i = i0 + i1;
- if (i >= height)
+ if (i >= height) {
break;
+ }
+ // clear processed flag first
+ processingFlags[index] &= processedInverseMask;
- if (coefficentsMagnitude[index] || !neighborsSignificance[index])
+ if (coefficentsMagnitude[index] ||
+ !neighborsSignificance[index]) {
continue;
+ }
var contextLabel = labels[neighborsSignificance[index]];
- var cx = contexts[contextLabel];
- var decision = decoder.readBit(cx);
+ var decision = decoder.readBit(contexts, contextLabel);
if (decision) {
- var sign = this.decodeSignBit(i, j);
+ var sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
+ this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
}
bitsDecoded[index]++;
@@ -36646,28 +36555,56 @@ var JpxImage = (function JpxImageClosure() {
}
}
},
- decodeSignBit: function BitModel_decodeSignBit(row, column) {
+ decodeSignBit: function BitModel_decodeSignBit(row, column, index) {
var width = this.width, height = this.height;
- var index = row * width + column;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
- var horizontalContribution = calcSignContribution(
- column > 0 && coefficentsMagnitude[index - 1],
- coefficentsSign[index - 1],
- column + 1 < width && coefficentsMagnitude[index + 1],
- coefficentsSign[index + 1]);
- var verticalContribution = calcSignContribution(
- row > 0 && coefficentsMagnitude[index - width],
- coefficentsSign[index - width],
- row + 1 < height && coefficentsMagnitude[index + width],
- coefficentsSign[index + width]);
+ var contribution, sign0, sign1, significance1;
+ var contextLabel, decoded;
- var contextLabelAndXor = SignContextLabels[
- 3 * (1 - horizontalContribution) + (1 - verticalContribution)];
- var contextLabel = contextLabelAndXor.contextLabel;
- var cx = this.contexts[contextLabel];
- var decoded = this.decoder.readBit(cx);
- return decoded ^ contextLabelAndXor.xorBit;
+ // calculate horizontal contribution
+ significance1 = (column > 0 && coefficentsMagnitude[index - 1] !== 0);
+ if (column + 1 < width && coefficentsMagnitude[index + 1] !== 0) {
+ sign1 = coefficentsSign[index + 1];
+ if (significance1) {
+ sign0 = coefficentsSign[index - 1];
+ contribution = 1 - sign1 - sign0;
+ } else {
+ contribution = 1 - sign1 - sign1;
+ }
+ } else if (significance1) {
+ sign0 = coefficentsSign[index - 1];
+ contribution = 1 - sign0 - sign0;
+ } else {
+ contribution = 0;
+ }
+ var horizontalContribution = 3 * contribution;
+
+ // calculate vertical contribution and combine with the horizontal
+ significance1 = (row > 0 && coefficentsMagnitude[index - width] !== 0);
+ if (row + 1 < height && coefficentsMagnitude[index + width] !== 0) {
+ sign1 = coefficentsSign[index + width];
+ if (significance1) {
+ sign0 = coefficentsSign[index - width];
+ contribution = 1 - sign1 - sign0 + horizontalContribution;
+ } else {
+ contribution = 1 - sign1 - sign1 + horizontalContribution;
+ }
+ } else if (significance1) {
+ sign0 = coefficentsSign[index - width];
+ contribution = 1 - sign0 - sign0 + horizontalContribution;
+ } else {
+ contribution = horizontalContribution;
+ }
+
+ if (contribution >= 0) {
+ contextLabel = 9 + contribution;
+ decoded = this.decoder.readBit(this.contexts, contextLabel);
+ } else {
+ contextLabel = 9 - contribution;
+ decoded = this.decoder.readBit(this.contexts, contextLabel) ^ 1;
+ }
+ return decoded;
},
runMagnitudeRefinementPass:
function BitModel_runMagnitudeRefinementPass() {
@@ -36680,32 +36617,29 @@ var JpxImage = (function JpxImageClosure() {
var processingFlags = this.processingFlags;
var processedMask = 1;
var firstMagnitudeBitMask = 2;
- for (var i0 = 0; i0 < height; i0 += 4) {
+ var length = width * height;
+ var width4 = width * 4;
+
+ for (var index0 = 0, indexNext; index0 < length; index0 = indexNext) {
+ indexNext = Math.min(length, index0 + width4);
for (var j = 0; j < width; j++) {
- for (var i1 = 0; i1 < 4; i1++) {
- var i = i0 + i1;
- if (i >= height)
- break;
- var index = i * width + j;
+ for (var index = index0 + j; index < indexNext; index += width) {
// significant but not those that have just become
if (!coefficentsMagnitude[index] ||
- (processingFlags[index] & processedMask) !== 0)
+ (processingFlags[index] & processedMask) !== 0) {
continue;
-
- var contextLabel = 16;
- if ((processingFlags[index] &
- firstMagnitudeBitMask) !== 0) {
- processingFlags[i * width + j] ^= firstMagnitudeBitMask;
- // first refinement
- var significance = neighborsSignificance[index];
- var sumOfSignificance = (significance & 3) +
- ((significance >> 2) & 3) + ((significance >> 4) & 7);
- contextLabel = sumOfSignificance >= 1 ? 15 : 14;
}
- var cx = contexts[contextLabel];
- var bit = decoder.readBit(cx);
+ var contextLabel = 16;
+ if ((processingFlags[index] & firstMagnitudeBitMask) !== 0) {
+ processingFlags[index] ^= firstMagnitudeBitMask;
+ // first refinement
+ var significance = neighborsSignificance[index] & 127;
+ contextLabel = significance === 0 ? 15 : 14;
+ }
+
+ var bit = decoder.readBit(contexts, contextLabel);
coefficentsMagnitude[index] =
(coefficentsMagnitude[index] << 1) | bit;
bitsDecoded[index]++;
@@ -36718,7 +36652,6 @@ var JpxImage = (function JpxImageClosure() {
var decoder = this.decoder;
var width = this.width, height = this.height;
var neighborsSignificance = this.neighborsSignificance;
- var significanceState = this.significanceState;
var coefficentsMagnitude = this.coefficentsMagnitude;
var coefficentsSign = this.coefficentsSign;
var contexts = this.contexts;
@@ -36730,12 +36663,16 @@ var JpxImage = (function JpxImageClosure() {
var oneRowDown = width;
var twoRowsDown = width * 2;
var threeRowsDown = width * 3;
- for (var i0 = 0; i0 < height; i0 += 4) {
+ var iNext;
+ for (var i0 = 0; i0 < height; i0 = iNext) {
+ iNext = Math.min(i0 + 4, height);
+ var indexBase = i0 * width;
+ var checkAllEmpty = i0 + 3 < height;
for (var j = 0; j < width; j++) {
- var index0 = i0 * width + j;
- // using the property: labels[neighborsSignificance[index]] == 0
- // when neighborsSignificance[index] == 0
- var allEmpty = i0 + 3 < height &&
+ var index0 = indexBase + j;
+ // using the property: labels[neighborsSignificance[index]] === 0
+ // when neighborsSignificance[index] === 0
+ var allEmpty = (checkAllEmpty &&
processingFlags[index0] === 0 &&
processingFlags[index0 + oneRowDown] === 0 &&
processingFlags[index0 + twoRowsDown] === 0 &&
@@ -36743,12 +36680,12 @@ var JpxImage = (function JpxImageClosure() {
neighborsSignificance[index0] === 0 &&
neighborsSignificance[index0 + oneRowDown] === 0 &&
neighborsSignificance[index0 + twoRowsDown] === 0 &&
- neighborsSignificance[index0 + threeRowsDown] === 0;
+ neighborsSignificance[index0 + threeRowsDown] === 0);
var i1 = 0, index = index0;
- var cx, i;
+ var i = i0, sign;
if (allEmpty) {
- cx = this.runLengthContext;
- var hasSignificantCoefficent = decoder.readBit(cx);
+ var hasSignificantCoefficent =
+ decoder.readBit(contexts, RUNLENGTH_CONTEXT);
if (!hasSignificantCoefficent) {
bitsDecoded[index0]++;
bitsDecoded[index0 + oneRowDown]++;
@@ -36756,40 +36693,39 @@ var JpxImage = (function JpxImageClosure() {
bitsDecoded[index0 + threeRowsDown]++;
continue; // next column
}
- cx = this.uniformContext;
- i1 = (decoder.readBit(cx) << 1) | decoder.readBit(cx);
- i = i0 + i1;
- index += i1 * width;
+ i1 = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
+ decoder.readBit(contexts, UNIFORM_CONTEXT);
+ if (i1 !== 0) {
+ i = i0 + i1;
+ index += i1 * width;
+ }
- var sign = this.decodeSignBit(i, j);
+ sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
+ this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
index = index0;
- for (var i2 = i0; i2 <= i; i2++, index += width)
+ for (var i2 = i0; i2 <= i; i2++, index += width) {
bitsDecoded[index]++;
+ }
i1++;
}
- for (; i1 < 4; i1++, index += width) {
- i = i0 + i1;
- if (i >= height)
- break;
-
+ for (i = i0 + i1; i < iNext; i++, index += width) {
if (coefficentsMagnitude[index] ||
- (processingFlags[index] & processedMask) !== 0)
+ (processingFlags[index] & processedMask) !== 0) {
continue;
+ }
var contextLabel = labels[neighborsSignificance[index]];
- cx = contexts[contextLabel];
- var decision = decoder.readBit(cx);
- if (decision == 1) {
- var sign = this.decodeSignBit(i, j);
+ var decision = decoder.readBit(contexts, contextLabel);
+ if (decision === 1) {
+ sign = this.decodeSignBit(i, j, index);
coefficentsSign[index] = sign;
coefficentsMagnitude[index] = 1;
- this.setNeighborsSignificance(i, j);
+ this.setNeighborsSignificance(i, j, index);
processingFlags[index] |= firstMagnitudeBitMask;
}
bitsDecoded[index]++;
@@ -36799,128 +36735,139 @@ var JpxImage = (function JpxImageClosure() {
},
checkSegmentationSymbol: function BitModel_checkSegmentationSymbol() {
var decoder = this.decoder;
- var cx = this.uniformContext;
- var symbol = (decoder.readBit(cx) << 3) | (decoder.readBit(cx) << 2) |
- (decoder.readBit(cx) << 1) | decoder.readBit(cx);
- if (symbol != 0xA)
- throw 'Invalid segmentation symbol';
+ var contexts = this.contexts;
+ var symbol = (decoder.readBit(contexts, UNIFORM_CONTEXT) << 3) |
+ (decoder.readBit(contexts, UNIFORM_CONTEXT) << 2) |
+ (decoder.readBit(contexts, UNIFORM_CONTEXT) << 1) |
+ decoder.readBit(contexts, UNIFORM_CONTEXT);
+ if (symbol !== 0xA) {
+ throw new Error('JPX Error: Invalid segmentation symbol');
+ }
}
};
return BitModel;
})();
- // Section F, Discrete wavelet transofrmation
+ // Section F, Discrete wavelet transformation
var Transform = (function TransformClosure() {
- function Transform() {
- }
+ function Transform() {}
+
Transform.prototype.calculate =
function transformCalculate(subbands, u0, v0) {
var ll = subbands[0];
- for (var i = 1, ii = subbands.length, j = 1; i < ii; i += 3, j++) {
- ll = this.iterate(ll, subbands[i], subbands[i + 1],
- subbands[i + 2], u0, v0);
+ for (var i = 1, ii = subbands.length; i < ii; i++) {
+ ll = this.iterate(ll, subbands[i], u0, v0);
}
return ll;
};
- Transform.prototype.expand = function expand(buffer, bufferPadding, step) {
- // Section F.3.7 extending... using max extension of 4
- var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
- var i2 = bufferPadding + step - 2, j2 = bufferPadding + step;
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
- buffer[i1--] = buffer[j1++];
- buffer[j2++] = buffer[i2--];
+ Transform.prototype.extend = function extend(buffer, offset, size) {
+ // Section F.3.7 extending... using max extension of 4
+ var i1 = offset - 1, j1 = offset + 1;
+ var i2 = offset + size - 2, j2 = offset + size;
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1--] = buffer[j1++];
+ buffer[j2++] = buffer[i2--];
+ buffer[i1] = buffer[j1];
+ buffer[j2] = buffer[i2];
};
- Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh,
- u0, v0) {
+ Transform.prototype.iterate = function Transform_iterate(ll, hl_lh_hh,
+ u0, v0) {
var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
- var hlWidth = hl.width, hlHeight = hl.height, hlItems = hl.items;
- var lhWidth = lh.width, lhHeight = lh.height, lhItems = lh.items;
- var hhWidth = hh.width, hhHeight = hh.height, hhItems = hh.items;
+ var width = hl_lh_hh.width;
+ var height = hl_lh_hh.height;
+ var items = hl_lh_hh.items;
+ var i, j, k, l, u, v;
- // Section F.3.3 interleave
- var width = llWidth + hlWidth;
- var height = llHeight + lhHeight;
- var items = new Float32Array(width * height);
- for (var i = 0, ii = llHeight; i < ii; i++) {
- var k = i * llWidth, l = i * 2 * width;
- for (var j = 0, jj = llWidth; j < jj; j++, k++, l += 2)
+ // Interleave LL according to Section F.3.3
+ for (k = 0, i = 0; i < llHeight; i++) {
+ l = i * 2 * width;
+ for (j = 0; j < llWidth; j++, k++, l += 2) {
items[l] = llItems[k];
+ }
}
- for (var i = 0, ii = hlHeight; i < ii; i++) {
- var k = i * hlWidth, l = i * 2 * width + 1;
- for (var j = 0, jj = hlWidth; j < jj; j++, k++, l += 2)
- items[l] = hlItems[k];
- }
- for (var i = 0, ii = lhHeight; i < ii; i++) {
- var k = i * lhWidth, l = (i * 2 + 1) * width;
- for (var j = 0, jj = lhWidth; j < jj; j++, k++, l += 2)
- items[l] = lhItems[k];
- }
- for (var i = 0, ii = hhHeight; i < ii; i++) {
- var k = i * hhWidth, l = (i * 2 + 1) * width + 1;
- for (var j = 0, jj = hhWidth; j < jj; j++, k++, l += 2)
- items[l] = hhItems[k];
- }
+ // The LL band is not needed anymore.
+ llItems = ll.items = null;
var bufferPadding = 4;
- var bufferLength = new Float32Array(Math.max(width, height) +
- 2 * bufferPadding);
- var buffer = new Float32Array(bufferLength);
- var bufferOut = new Float32Array(bufferLength);
+ var rowBuffer = new Float32Array(width + 2 * bufferPadding);
// Section F.3.4 HOR_SR
- for (var v = 0; v < height; v++) {
- if (width == 1) {
- // if width = 1, when u0 even keep items as is, when odd divide by 2
- if ((u0 % 1) !== 0) {
- items[v * width] /= 2;
+ if (width === 1) {
+ // if width = 1, when u0 even keep items as is, when odd divide by 2
+ if ((u0 & 1) !== 0) {
+ for (v = 0, k = 0; v < height; v++, k += width) {
+ items[k] *= 0.5;
}
- continue;
}
+ } else {
+ for (v = 0, k = 0; v < height; v++, k += width) {
+ rowBuffer.set(items.subarray(k, k + width), bufferPadding);
- var k = v * width;
- var l = bufferPadding;
- for (var u = 0; u < width; u++, k++, l++)
- buffer[l] = items[k];
+ this.extend(rowBuffer, bufferPadding, width);
+ this.filter(rowBuffer, bufferPadding, width);
- this.expand(buffer, bufferPadding, width);
- this.filter(buffer, bufferPadding, width, u0, bufferOut);
-
- k = v * width;
- l = bufferPadding;
- for (var u = 0; u < width; u++, k++, l++)
- items[k] = bufferOut[l];
+ items.set(
+ rowBuffer.subarray(bufferPadding, bufferPadding + width),
+ k);
+ }
}
+ // Accesses to the items array can take long, because it may not fit into
+ // CPU cache and has to be fetched from main memory. Since subsequent
+ // accesses to the items array are not local when reading columns, we
+ // have a cache miss every time. To reduce cache misses, get up to
+ // 'numBuffers' items at a time and store them into the individual
+ // buffers. The colBuffers should be small enough to fit into CPU cache.
+ var numBuffers = 16;
+ var colBuffers = [];
+ for (i = 0; i < numBuffers; i++) {
+ colBuffers.push(new Float32Array(height + 2 * bufferPadding));
+ }
+ var b, currentBuffer = 0;
+ ll = bufferPadding + height;
+
// Section F.3.5 VER_SR
- for (var u = 0; u < width; u++) {
- if (height == 1) {
+ if (height === 1) {
// if height = 1, when v0 even keep items as is, when odd divide by 2
- if ((v0 % 1) !== 0) {
- items[u] /= 2;
+ if ((v0 & 1) !== 0) {
+ for (u = 0; u < width; u++) {
+ items[u] *= 0.5;
}
- continue;
}
+ } else {
+ for (u = 0; u < width; u++) {
+ // if we ran out of buffers, copy several image columns at once
+ if (currentBuffer === 0) {
+ numBuffers = Math.min(width - u, numBuffers);
+ for (k = u, l = bufferPadding; l < ll; k += width, l++) {
+ for (b = 0; b < numBuffers; b++) {
+ colBuffers[b][l] = items[k + b];
+ }
+ }
+ currentBuffer = numBuffers;
+ }
- var k = u;
- var l = bufferPadding;
- for (var v = 0; v < height; v++, k += width, l++)
- buffer[l] = items[k];
+ currentBuffer--;
+ var buffer = colBuffers[currentBuffer];
+ this.extend(buffer, bufferPadding, height);
+ this.filter(buffer, bufferPadding, height);
- this.expand(buffer, bufferPadding, height);
- this.filter(buffer, bufferPadding, height, v0, bufferOut);
-
- k = u;
- l = bufferPadding;
- for (var v = 0; v < height; v++, k += width, l++)
- items[k] = bufferOut[l];
+ // If this is last buffer in this group of buffers, flush all buffers.
+ if (currentBuffer === 0) {
+ k = u - numBuffers + 1;
+ for (l = bufferPadding; l < ll; k += width, l++) {
+ for (b = 0; b < numBuffers; b++) {
+ items[k + b] = colBuffers[b][l];
+ }
+ }
+ }
+ }
}
+
return {
width: width,
height: height,
@@ -36938,10 +36885,10 @@ var JpxImage = (function JpxImageClosure() {
IrreversibleTransform.prototype = Object.create(Transform.prototype);
IrreversibleTransform.prototype.filter =
- function irreversibleTransformFilter(y, offset, length, i0, x) {
- var i0_ = Math.floor(i0 / 2);
- var i1_ = Math.floor((i0 + length) / 2);
- var offset_ = offset - (i0 % 1);
+ function irreversibleTransformFilter(x, offset, length) {
+ var len = length >> 1;
+ offset = offset | 0;
+ var j, n, current, next;
var alpha = -1.586134342059924;
var beta = -0.052980118572961;
@@ -36950,35 +36897,75 @@ var JpxImage = (function JpxImageClosure() {
var K = 1.230174104914001;
var K_ = 1 / K;
- // step 1
- var j = offset_ - 2;
- for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2)
- x[j] = K * y[j];
+ // step 1 is combined with step 3
// step 2
- var j = offset_ - 3;
- for (var n = i0_ - 2, nn = i1_ + 2; n < nn; n++, j += 2)
- x[j] = K_ * y[j];
+ j = offset - 3;
+ for (n = len + 4; n--; j += 2) {
+ x[j] *= K_;
+ }
- // step 3
- var j = offset_ - 2;
- for (var n = i0_ - 1, nn = i1_ + 2; n < nn; n++, j += 2)
- x[j] -= delta * (x[j - 1] + x[j + 1]);
+ // step 1 & 3
+ j = offset - 2;
+ current = delta * x[j -1];
+ for (n = len + 3; n--; j += 2) {
+ next = delta * x[j + 1];
+ x[j] = K * x[j] - current - next;
+ if (n--) {
+ j += 2;
+ current = delta * x[j + 1];
+ x[j] = K * x[j] - current - next;
+ } else {
+ break;
+ }
+ }
// step 4
- var j = offset_ - 1;
- for (var n = i0_ - 1, nn = i1_ + 1; n < nn; n++, j += 2)
- x[j] -= gamma * (x[j - 1] + x[j + 1]);
+ j = offset - 1;
+ current = gamma * x[j - 1];
+ for (n = len + 2; n--; j += 2) {
+ next = gamma * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = gamma * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
+ }
// step 5
- var j = offset_;
- for (var n = i0_, nn = i1_ + 1; n < nn; n++, j += 2)
- x[j] -= beta * (x[j - 1] + x[j + 1]);
+ j = offset;
+ current = beta * x[j - 1];
+ for (n = len + 1; n--; j += 2) {
+ next = beta * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = beta * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
+ }
// step 6
- var j = offset_ + 1;
- for (var n = i0_, nn = i1_; n < nn; n++, j += 2)
- x[j] -= alpha * (x[j - 1] + x[j + 1]);
+ if (len !== 0) {
+ j = offset + 1;
+ current = alpha * x[j - 1];
+ for (n = len; n--; j += 2) {
+ next = alpha * x[j + 1];
+ x[j] -= current + next;
+ if (n--) {
+ j += 2;
+ current = alpha * x[j + 1];
+ x[j] -= current + next;
+ } else {
+ break;
+ }
+ }
+ }
};
return IrreversibleTransform;
@@ -36992,16 +36979,18 @@ var JpxImage = (function JpxImageClosure() {
ReversibleTransform.prototype = Object.create(Transform.prototype);
ReversibleTransform.prototype.filter =
- function reversibleTransformFilter(y, offset, length, i0, x) {
- var i0_ = Math.floor(i0 / 2);
- var i1_ = Math.floor((i0 + length) / 2);
- var offset_ = offset - (i0 % 1);
+ function reversibleTransformFilter(x, offset, length) {
+ var len = length >> 1;
+ offset = offset | 0;
+ var j, n;
- for (var n = i0_, nn = i1_ + 1, j = offset_; n < nn; n++, j += 2)
- x[j] = y[j] - Math.floor((y[j - 1] + y[j + 1] + 2) / 4);
+ for (j = offset, n = len + 1; n--; j += 2) {
+ x[j] -= (x[j - 1] + x[j + 1] + 2) >> 2;
+ }
- for (var n = i0_, nn = i1_, j = offset_ + 1; n < nn; n++, j += 2)
- x[j] = y[j] + Math.floor((x[j - 1] + x[j + 1]) / 2);
+ for (j = offset + 1, n = len; n--; j += 2) {
+ x[j] += (x[j - 1] + x[j + 1]) >> 1;
+ }
};
return ReversibleTransform;
@@ -37013,171 +37002,15 @@ var JpxImage = (function JpxImageClosure() {
var Jbig2Image = (function Jbig2ImageClosure() {
-
- // Annex E. Arithmetic Coding
- var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
- var QeTable = [
- {qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
- {qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
- {qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
- {qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
- {qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
- {qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
- {qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
- {qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
- {qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
- {qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
- {qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
- {qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
- {qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
- {qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
- {qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
- {qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
- {qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
- {qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
- {qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
- {qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
- {qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
- {qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
- {qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
- {qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
- {qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
- {qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
- {qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
- {qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
- {qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
- {qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
- {qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
- {qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
- {qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
- {qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
- {qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
- {qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
- {qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
- {qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
- {qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
- {qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
- {qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
- {qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
- {qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
- {qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
- {qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
- {qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
- {qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
- ];
-
- function ArithmeticDecoder(data, start, end) {
- this.data = data;
- this.bp = start;
- this.dataEnd = end;
-
- this.chigh = data[start];
- this.clow = 0;
-
- this.byteIn();
-
- this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
- this.clow = (this.clow << 7) & 0xFFFF;
- this.ct -= 7;
- this.a = 0x8000;
- }
-
- ArithmeticDecoder.prototype = {
- byteIn: function ArithmeticDecoder_byteIn() {
- var data = this.data;
- var bp = this.bp;
- if (data[bp] == 0xFF) {
- var b1 = data[bp + 1];
- if (b1 > 0x8F) {
- this.clow += 0xFF00;
- this.ct = 8;
- } else {
- bp++;
- this.clow += (data[bp] << 9);
- this.ct = 7;
- this.bp = bp;
- }
- } else {
- bp++;
- this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
- this.ct = 8;
- this.bp = bp;
- }
- if (this.clow > 0xFFFF) {
- this.chigh += (this.clow >> 16);
- this.clow &= 0xFFFF;
- }
- },
- readBit: function ArithmeticDecoder_readBit(contexts, pos) {
- // contexts are packed into 1 byte:
- // highest 7 bits carry cx.index, lowest bit carries cx.mps
- var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
- var qeTableIcx = QeTable[cx_index];
- var qeIcx = qeTableIcx.qe;
- var nmpsIcx = qeTableIcx.nmps;
- var nlpsIcx = qeTableIcx.nlps;
- var switchIcx = qeTableIcx.switchFlag;
- var d;
- this.a -= qeIcx;
-
- if (this.chigh < qeIcx) {
- // exchangeLps
- if (this.a < qeIcx) {
- this.a = qeIcx;
- d = cx_mps;
- cx_index = nmpsIcx;
- } else {
- this.a = qeIcx;
- d = 1 - cx_mps;
- if (switchIcx) {
- cx_mps = d;
- }
- cx_index = nlpsIcx;
- }
- } else {
- this.chigh -= qeIcx;
- if ((this.a & 0x8000) !== 0) {
- return cx_mps;
- }
- // exchangeMps
- if (this.a < qeIcx) {
- d = 1 - cx_mps;
- if (switchIcx) {
- cx_mps = d;
- }
- cx_index = nlpsIcx;
- } else {
- d = cx_mps;
- cx_index = nmpsIcx;
- }
- }
- // renormD;
- do {
- if (this.ct === 0)
- this.byteIn();
-
- this.a <<= 1;
- this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
- this.clow = (this.clow << 1) & 0xFFFF;
- this.ct--;
- } while ((this.a & 0x8000) === 0);
-
- contexts[pos] = cx_index << 1 | cx_mps;
- return d;
- }
- };
-
- return ArithmeticDecoder;
- })();
-
// Utility data structures
function ContextCache() {}
ContextCache.prototype = {
getContexts: function(id) {
- if (id in this)
+ if (id in this) {
return this[id];
- return (this[id] = new Int8Array(1<<16));
+ }
+ return (this[id] = new Int8Array(1 << 16));
}
};
@@ -37202,58 +37035,32 @@ var Jbig2Image = (function Jbig2ImageClosure() {
// A.2 Procedure for decoding values
function decodeInteger(contextCache, procedure, decoder) {
var contexts = contextCache.getContexts(procedure);
-
var prev = 1;
- var state = 1, v = 0, s;
- var toRead = 32, offset = 4436; // defaults for state 7
- while (state) {
- var bit = decoder.readBit(contexts, prev);
- prev = prev < 256 ? (prev << 1) | bit :
- (((prev << 1) | bit) & 511) | 256;
- switch (state) {
- case 1:
- s = !!bit;
- break;
- case 2:
- if (bit) break;
- state = 7;
- toRead = 2;
- offset = 0;
- break;
- case 3:
- if (bit) break;
- state = 7;
- toRead = 4;
- offset = 4;
- break;
- case 4:
- if (bit) break;
- state = 7;
- toRead = 6;
- offset = 20;
- break;
- case 5:
- if (bit) break;
- state = 7;
- toRead = 8;
- offset = 84;
- break;
- case 6:
- if (bit) break;
- state = 7;
- toRead = 12;
- offset = 340;
- break;
- default:
- v = v * 2 + bit;
- if (--toRead === 0)
- state = 0;
- continue;
+
+ function readBits(length) {
+ var v = 0;
+ for (var i = 0; i < length; i++) {
+ var bit = decoder.readBit(contexts, prev);
+ prev = (prev < 256 ? (prev << 1) | bit :
+ (((prev << 1) | bit) & 511) | 256);
+ v = (v << 1) | bit;
}
- state++;
+ return v >>> 0;
}
- v += offset;
- return !s ? v : v > 0 ? -v : null;
+
+ var sign = readBits(1);
+ var value = readBits(1) ?
+ (readBits(1) ?
+ (readBits(1) ?
+ (readBits(1) ?
+ (readBits(1) ?
+ (readBits(32) + 4436) :
+ readBits(12) + 340) :
+ readBits(8) + 84) :
+ readBits(6) + 20) :
+ readBits(4) + 4) :
+ readBits(2);
+ return (sign === 0 ? value : (value > 0 ? -value : null));
}
// A.3 The IAID decoding procedure
@@ -37263,12 +37070,12 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var prev = 1;
for (var i = 0; i < codeLength; i++) {
var bit = decoder.readBit(contexts, prev);
- prev = (prev * 2) + bit;
+ prev = (prev << 1) | bit;
}
- if (codeLength < 31)
+ if (codeLength < 31) {
return prev & ((1 << codeLength) - 1);
- else
- return prev - Math.pow(2, codeLength);
+ }
+ return prev & 0x7FFFFFFF;
}
// 7.3 Segment types
@@ -37315,11 +37122,12 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
];
+ // See 6.2.5.7 Decoding the bitmap.
var ReusedContexts = [
- 0x1CD3, // '00111001101' (template) + '0011' (at),
- 0x079A, // '001111001101' + '0',
- 0x00E3, // '001110001' + '1',
- 0x018B // '011000101' + '1'
+ 0x9B25, // 10011 0110010 0101
+ 0x0795, // 0011 110010 101
+ 0x00E5, // 001 11001 01
+ 0x0195 // 011001 0101
];
var RefinementReusedContexts = [
@@ -37327,79 +37135,162 @@ var Jbig2Image = (function Jbig2ImageClosure() {
0x0008 // '0000' + '001000'
];
- function log2(x) {
- var n = 1, i = 0;
- while (x > n) {
- n <<= 1;
- i++;
+ function decodeBitmapTemplate0(width, height, decodingContext) {
+ var decoder = decodingContext.decoder;
+ var contexts = decodingContext.contextCache.getContexts('GB');
+ var contextLabel, i, j, pixel, row, row1, row2, bitmap = [];
+
+ // ...ooooo....
+ // ..ooooooo... Context template for current pixel (X)
+ // .ooooX...... (concatenate values of 'o'-pixels to get contextLabel)
+ var OLD_PIXEL_MASK = 0x7BF7; // 01111 0111111 0111
+
+ for (i = 0; i < height; i++) {
+ row = bitmap[i] = new Uint8Array(width);
+ row1 = (i < 1) ? row : bitmap[i - 1];
+ row2 = (i < 2) ? row : bitmap[i - 2];
+
+ // At the beginning of each row:
+ // Fill contextLabel with pixels that are above/right of (X)
+ contextLabel = (row2[0] << 13) | (row2[1] << 12) | (row2[2] << 11) |
+ (row1[0] << 7) | (row1[1] << 6) | (row1[2] << 5) |
+ (row1[3] << 4);
+
+ for (j = 0; j < width; j++) {
+ row[j] = pixel = decoder.readBit(contexts, contextLabel);
+
+ // At each pixel: Clear contextLabel pixels that are shifted
+ // out of the context, then add new ones.
+ // If j + n is out of range at the right image border, then
+ // the undefined value of bitmap[i - 2][j + n] is shifted to 0
+ contextLabel = ((contextLabel & OLD_PIXEL_MASK) << 1) |
+ (row2[j + 3] << 11) | (row1[j + 4] << 4) | pixel;
+ }
}
- return i;
- }
- function readInt32(data, start) {
- return (data[start] << 24) | (data[start + 1] << 16) |
- (data[start + 2] << 8) | data[start + 3];
- }
-
- function readUint32(data, start) {
- var value = readInt32(data, start);
- return value & 0x80000000 ? (value + 4294967296) : value;
- }
-
- function readUint16(data, start) {
- return (data[start] << 8) | data[start + 1];
- }
-
- function readInt8(data, start) {
- return (data[start] << 24) >> 24;
+ return bitmap;
}
// 6.2 Generic Region Decoding Procedure
function decodeBitmap(mmr, width, height, templateIndex, prediction, skip, at,
decodingContext) {
- if (mmr)
+ if (mmr) {
error('JBIG2 error: MMR encoding is not supported');
+ }
+
+ // Use optimized version for the most common case
+ if (templateIndex === 0 && !skip && !prediction && at.length === 4 &&
+ at[0].x === 3 && at[0].y === -1 && at[1].x === -3 && at[1].y === -1 &&
+ at[2].x === 2 && at[2].y === -2 && at[3].x === -2 && at[3].y === -2) {
+ return decodeBitmapTemplate0(width, height, decodingContext);
+ }
var useskip = !!skip;
var template = CodingTemplates[templateIndex].concat(at);
+
+ // Sorting is non-standard, and it is not required. But sorting increases
+ // the number of template bits that can be reused from the previous
+ // contextLabel in the main loop.
+ template.sort(function (a, b) {
+ return (a.y - b.y) || (a.x - b.x);
+ });
+
var templateLength = template.length;
- var templateX = new Int32Array(templateLength);
- var templateY = new Int32Array(templateLength);
- for (var k = 0; k < templateLength; k++) {
+ var templateX = new Int8Array(templateLength);
+ var templateY = new Int8Array(templateLength);
+ var changingTemplateEntries = [];
+ var reuseMask = 0, minX = 0, maxX = 0, minY = 0;
+ var c, k;
+
+ for (k = 0; k < templateLength; k++) {
templateX[k] = template[k].x;
templateY[k] = template[k].y;
+ minX = Math.min(minX, template[k].x);
+ maxX = Math.max(maxX, template[k].x);
+ minY = Math.min(minY, template[k].y);
+ // Check if the template pixel appears in two consecutive context labels,
+ // so it can be reused. Otherwise, we add it to the list of changing
+ // template entries.
+ if (k < templateLength - 1 &&
+ template[k].y === template[k + 1].y &&
+ template[k].x === template[k + 1].x - 1) {
+ reuseMask |= 1 << (templateLength - 1 - k);
+ } else {
+ changingTemplateEntries.push(k);
+ }
+ }
+ var changingEntriesLength = changingTemplateEntries.length;
+
+ var changingTemplateX = new Int8Array(changingEntriesLength);
+ var changingTemplateY = new Int8Array(changingEntriesLength);
+ var changingTemplateBit = new Uint16Array(changingEntriesLength);
+ for (c = 0; c < changingEntriesLength; c++) {
+ k = changingTemplateEntries[c];
+ changingTemplateX[c] = template[k].x;
+ changingTemplateY[c] = template[k].y;
+ changingTemplateBit[c] = 1 << (templateLength - 1 - k);
}
+ // Get the safe bounding box edges from the width, height, minX, maxX, minY
+ var sbb_left = -minX;
+ var sbb_top = -minY;
+ var sbb_right = width - maxX;
+
var pseudoPixelContext = ReusedContexts[templateIndex];
+ var row = new Uint8Array(width);
var bitmap = [];
var decoder = decodingContext.decoder;
var contexts = decodingContext.contextCache.getContexts('GB');
- var ltp = 0;
+ var ltp = 0, j, i0, j0, contextLabel = 0, bit, shift;
for (var i = 0; i < height; i++) {
if (prediction) {
var sltp = decoder.readBit(contexts, pseudoPixelContext);
ltp ^= sltp;
+ if (ltp) {
+ bitmap.push(row); // duplicate previous row
+ continue;
+ }
}
- if (ltp) {
- bitmap.push(bitmap[bitmap.length - 1]); // duplicate previous row
- continue;
- }
- var row = new Uint8Array(width);
+ row = new Uint8Array(row);
bitmap.push(row);
- for (var j = 0; j < width; j++) {
+ for (j = 0; j < width; j++) {
if (useskip && skip[i][j]) {
row[j] = 0;
continue;
}
- var contextLabel = 0;
- for (var k = 0; k < templateLength; k++) {
- var i0 = i + templateY[k], j0 = j + templateX[k];
- if (i0 < 0 || j0 < 0 || j0 >= width)
- contextLabel <<= 1; // out of bound pixel
- else
- contextLabel = (contextLabel << 1) | bitmap[i0][j0];
+ // Are we in the middle of a scanline, so we can reuse contextLabel
+ // bits?
+ if (j >= sbb_left && j < sbb_right && i >= sbb_top) {
+ // If yes, we can just shift the bits that are reusable and only
+ // fetch the remaining ones.
+ contextLabel = (contextLabel << 1) & reuseMask;
+ for (k = 0; k < changingEntriesLength; k++) {
+ i0 = i + changingTemplateY[k];
+ j0 = j + changingTemplateX[k];
+ bit = bitmap[i0][j0];
+ if (bit) {
+ bit = changingTemplateBit[k];
+ contextLabel |= bit;
+ }
+ }
+ } else {
+ // compute the contextLabel from scratch
+ contextLabel = 0;
+ shift = templateLength - 1;
+ for (k = 0; k < templateLength; k++, shift--) {
+ j0 = j + templateX[k];
+ if (j0 >= 0 && j0 < width) {
+ i0 = i + templateY[k];
+ if (i0 >= 0) {
+ bit = bitmap[i0][j0];
+ if (bit) {
+ contextLabel |= bit << shift;
+ }
+ }
+ }
+ }
}
var pixel = decoder.readBit(contexts, contextLabel);
row[j] = pixel;
@@ -37413,22 +37304,26 @@ var Jbig2Image = (function Jbig2ImageClosure() {
offsetX, offsetY, prediction, at,
decodingContext) {
var codingTemplate = RefinementTemplates[templateIndex].coding;
- if (templateIndex === 0)
+ if (templateIndex === 0) {
codingTemplate = codingTemplate.concat([at[0]]);
+ }
var codingTemplateLength = codingTemplate.length;
var codingTemplateX = new Int32Array(codingTemplateLength);
var codingTemplateY = new Int32Array(codingTemplateLength);
- for (var k = 0; k < codingTemplateLength; k++) {
+ var k;
+ for (k = 0; k < codingTemplateLength; k++) {
codingTemplateX[k] = codingTemplate[k].x;
codingTemplateY[k] = codingTemplate[k].y;
}
+
var referenceTemplate = RefinementTemplates[templateIndex].reference;
- if (templateIndex === 0)
+ if (templateIndex === 0) {
referenceTemplate = referenceTemplate.concat([at[1]]);
+ }
var referenceTemplateLength = referenceTemplate.length;
var referenceTemplateX = new Int32Array(referenceTemplateLength);
var referenceTemplateY = new Int32Array(referenceTemplateLength);
- for (var k = 0; k < referenceTemplateLength; k++) {
+ for (k = 0; k < referenceTemplateLength; k++) {
referenceTemplateX[k] = referenceTemplate[k].x;
referenceTemplateY[k] = referenceTemplate[k].y;
}
@@ -37446,28 +37341,33 @@ var Jbig2Image = (function Jbig2ImageClosure() {
if (prediction) {
var sltp = decoder.readBit(contexts, pseudoPixelContext);
ltp ^= sltp;
+ if (ltp) {
+ error('JBIG2 error: prediction is not supported');
+ }
}
var row = new Uint8Array(width);
bitmap.push(row);
for (var j = 0; j < width; j++) {
- if (ltp)
- error('JBIG2 error: prediction is not supported');
-
+ var i0, j0;
var contextLabel = 0;
- for (var k = 0; k < codingTemplateLength; k++) {
- var i0 = i + codingTemplateY[k], j0 = j + codingTemplateX[k];
- if (i0 < 0 || j0 < 0 || j0 >= width)
+ for (k = 0; k < codingTemplateLength; k++) {
+ i0 = i + codingTemplateY[k];
+ j0 = j + codingTemplateX[k];
+ if (i0 < 0 || j0 < 0 || j0 >= width) {
contextLabel <<= 1; // out of bound pixel
- else
+ } else {
contextLabel = (contextLabel << 1) | bitmap[i0][j0];
+ }
}
- for (var k = 0; k < referenceTemplateLength; k++) {
- var i0 = i + referenceTemplateY[k] + offsetY;
- var j0 = j + referenceTemplateX[k] + offsetX;
- if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth)
+ for (k = 0; k < referenceTemplateLength; k++) {
+ i0 = i + referenceTemplateY[k] + offsetY;
+ j0 = j + referenceTemplateX[k] + offsetX;
+ if (i0 < 0 || i0 >= referenceHeight || j0 < 0 ||
+ j0 >= referenceWidth) {
contextLabel <<= 1; // out of bound pixel
- else
+ } else {
contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
+ }
}
var pixel = decoder.readBit(contexts, contextLabel);
row[j] = pixel;
@@ -37483,8 +37383,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
huffmanTables, templateIndex, at,
refinementTemplateIndex, refinementAt,
decodingContext) {
- if (huffman)
+ if (huffman) {
error('JBIG2 error: huffman is not supported');
+ }
var newSymbols = [];
var currentHeight = 0;
@@ -37500,24 +37401,38 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var totalWidth = 0;
while (true) {
var deltaWidth = decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
- if (deltaWidth === null)
+ if (deltaWidth === null) {
break; // OOB
+ }
currentWidth += deltaWidth;
totalWidth += currentWidth;
var bitmap;
if (refinement) {
// 6.5.8.2 Refinement/aggregate-coded symbol bitmap
var numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
- if (numberOfInstances > 1)
- error('JBIG2 error: number of instances > 1 is not supported');
- var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
- var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
- var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
- var symbol = symbolId < symbols.length ? symbols[symbolId] :
- newSymbols[symbolId - symbols.length];
- bitmap = decodeRefinement(currentWidth, currentHeight,
+ if (numberOfInstances > 1) {
+ bitmap = decodeTextRegion(huffman, refinement,
+ currentWidth, currentHeight, 0,
+ numberOfInstances, 1, //strip size
+ symbols.concat(newSymbols),
+ symbolCodeLength,
+ 0, //transposed
+ 0, //ds offset
+ 1, //top left 7.4.3.1.1
+ 0, //OR operator
+ huffmanTables,
+ refinementTemplateIndex, refinementAt,
+ decodingContext);
+ } else {
+ var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
+ var rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
+ var rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
+ var symbol = (symbolId < symbols.length ? symbols[symbolId] :
+ newSymbols[symbolId - symbols.length]);
+ bitmap = decodeRefinement(currentWidth, currentHeight,
refinementTemplateIndex, symbol, rdx, rdy, false, refinementAt,
decodingContext);
+ }
} else {
// 6.5.8.1 Direct-coded symbol bitmap
bitmap = decodeBitmap(false, currentWidth, currentHeight,
@@ -37532,14 +37447,21 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var totalSymbolsLength = symbols.length + numberOfNewSymbols;
while (flags.length < totalSymbolsLength) {
var runLength = decodeInteger(contextCache, 'IAEX', decoder);
- while (runLength--)
+ while (runLength--) {
flags.push(currentFlag);
+ }
currentFlag = !currentFlag;
}
- for (var i = 0, ii = symbols.length; i < ii; i++)
- if (flags[i]) exportedSymbols.push(symbols[i]);
- for (var j = 0; j < numberOfNewSymbols; i++, j++)
- if (flags[i]) exportedSymbols.push(newSymbols[j]);
+ for (var i = 0, ii = symbols.length; i < ii; i++) {
+ if (flags[i]) {
+ exportedSymbols.push(symbols[i]);
+ }
+ }
+ for (var j = 0; j < numberOfNewSymbols; i++, j++) {
+ if (flags[i]) {
+ exportedSymbols.push(newSymbols[j]);
+ }
+ }
return exportedSymbols;
}
@@ -37550,16 +37472,19 @@ var Jbig2Image = (function Jbig2ImageClosure() {
combinationOperator, huffmanTables,
refinementTemplateIndex, refinementAt,
decodingContext) {
- if (huffman)
+ if (huffman) {
error('JBIG2 error: huffman is not supported');
+ }
// Prepare bitmap
var bitmap = [];
- for (var i = 0; i < height; i++) {
- var row = new Uint8Array(width);
+ var i, row;
+ for (i = 0; i < height; i++) {
+ row = new Uint8Array(width);
if (defaultPixelValue) {
- for (var j = 0; j < width; j++)
+ for (var j = 0; j < width; j++) {
row[j] = defaultPixelValue;
+ }
}
bitmap.push(row);
}
@@ -37568,7 +37493,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var contextCache = decodingContext.contextCache;
var stripT = -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
var firstS = 0;
- var i = 0;
+ i = 0;
while (i < numberOfSymbolInstances) {
var deltaT = decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
stripT += deltaT;
@@ -37577,12 +37502,12 @@ var Jbig2Image = (function Jbig2ImageClosure() {
firstS += deltaFirstS;
var currentS = firstS;
do {
- var currentT = stripSize == 1 ? 0 :
- decodeInteger(contextCache, 'IAIT', decoder); // 6.4.9
+ var currentT = (stripSize === 1 ? 0 :
+ decodeInteger(contextCache, 'IAIT', decoder)); // 6.4.9
var t = stripSize * stripT + currentT;
var symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
- var applyRefinement = refinement &&
- decodeInteger(contextCache, 'IARI', decoder);
+ var applyRefinement = (refinement &&
+ decodeInteger(contextCache, 'IARI', decoder));
var symbolBitmap = inputSymbols[symbolId];
var symbolWidth = symbolBitmap[0].length;
var symbolHeight = symbolBitmap.length;
@@ -37600,25 +37525,26 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
var offsetT = t - ((referenceCorner & 1) ? 0 : symbolHeight);
var offsetS = currentS - ((referenceCorner & 2) ? symbolWidth : 0);
+ var s2, t2, symbolRow;
if (transposed) {
- // Place Symbol Bitmap from T1,S1
- for (var s2 = 0; s2 < symbolHeight; s2++) {
- var row = bitmap[offsetS + s2];
+ // Place Symbol Bitmap from T1,S1
+ for (s2 = 0; s2 < symbolHeight; s2++) {
+ row = bitmap[offsetS + s2];
if (!row) {
continue;
}
- var symbolRow = symbolBitmap[s2];
+ symbolRow = symbolBitmap[s2];
// To ignore Parts of Symbol bitmap which goes
// outside bitmap region
var maxWidth = Math.min(width - offsetT, symbolWidth);
switch (combinationOperator) {
case 0: // OR
- for (var t2 = 0; t2 < maxWidth; t2++) {
+ for (t2 = 0; t2 < maxWidth; t2++) {
row[offsetT + t2] |= symbolRow[t2];
}
break;
case 2: // XOR
- for (var t2 = 0; t2 < maxWidth; t2++) {
+ for (t2 = 0; t2 < maxWidth; t2++) {
row[offsetT + t2] ^= symbolRow[t2];
}
break;
@@ -37629,20 +37555,20 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
currentS += symbolHeight - 1;
} else {
- for (var t2 = 0; t2 < symbolHeight; t2++) {
- var row = bitmap[offsetT + t2];
+ for (t2 = 0; t2 < symbolHeight; t2++) {
+ row = bitmap[offsetT + t2];
if (!row) {
continue;
}
- var symbolRow = symbolBitmap[t2];
+ symbolRow = symbolBitmap[t2];
switch (combinationOperator) {
case 0: // OR
- for (var s2 = 0; s2 < symbolWidth; s2++) {
+ for (s2 = 0; s2 < symbolWidth; s2++) {
row[offsetS + s2] |= symbolRow[s2];
}
break;
case 2: // XOR
- for (var s2 = 0; s2 < symbolWidth; s2++) {
+ for (s2 = 0; s2 < symbolWidth; s2++) {
row[offsetS + s2] ^= symbolRow[s2];
}
break;
@@ -37655,8 +37581,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
}
i++;
var deltaS = decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
- if (deltaS === null)
+ if (deltaS === null) {
break; // OOB
+ }
currentS += deltaS + dsOffset;
} while (true);
}
@@ -37668,47 +37595,53 @@ var Jbig2Image = (function Jbig2ImageClosure() {
segmentHeader.number = readUint32(data, start);
var flags = data[start + 4];
var segmentType = flags & 0x3F;
- if (!SegmentTypes[segmentType])
+ if (!SegmentTypes[segmentType]) {
error('JBIG2 error: invalid segment type: ' + segmentType);
+ }
segmentHeader.type = segmentType;
segmentHeader.typeName = SegmentTypes[segmentType];
segmentHeader.deferredNonRetain = !!(flags & 0x80);
+
var pageAssociationFieldSize = !!(flags & 0x40);
var referredFlags = data[start + 5];
var referredToCount = (referredFlags >> 5) & 7;
var retainBits = [referredFlags & 31];
var position = start + 6;
- if (referredFlags == 7) {
- referredToCount = readInt32(data, position - 1) & 0x1FFFFFFF;
+ if (referredFlags === 7) {
+ referredToCount = readUint32(data, position - 1) & 0x1FFFFFFF;
position += 3;
var bytes = (referredToCount + 7) >> 3;
retainBits[0] = data[position++];
while (--bytes > 0) {
retainBits.push(data[position++]);
}
- } else if (referredFlags == 5 || referredFlags == 6)
+ } else if (referredFlags === 5 || referredFlags === 6) {
error('JBIG2 error: invalid referred-to flags');
+ }
+
segmentHeader.retainBits = retainBits;
- var referredToSegmentNumberSize = segmentHeader.number <= 256 ? 1 :
- segmentHeader.number <= 65536 ? 2 : 4;
+ var referredToSegmentNumberSize = (segmentHeader.number <= 256 ? 1 :
+ (segmentHeader.number <= 65536 ? 2 : 4));
var referredTo = [];
- for (var i = 0; i < referredToCount; i++) {
- var number = referredToSegmentNumberSize == 1 ? data[position] :
- referredToSegmentNumberSize == 2 ? readUint16(data, position) :
- readUint32(data, position);
+ var i, ii;
+ for (i = 0; i < referredToCount; i++) {
+ var number = (referredToSegmentNumberSize === 1 ? data[position] :
+ (referredToSegmentNumberSize === 2 ? readUint16(data, position) :
+ readUint32(data, position)));
referredTo.push(number);
position += referredToSegmentNumberSize;
}
segmentHeader.referredTo = referredTo;
- if (!pageAssociationFieldSize)
+ if (!pageAssociationFieldSize) {
segmentHeader.pageAssociation = data[position++];
- else {
+ } else {
segmentHeader.pageAssociation = readUint32(data, position);
position += 4;
}
segmentHeader.length = readUint32(data, position);
position += 4;
- if (segmentHeader.length == 0xFFFFFFFF) {
+
+ if (segmentHeader.length === 0xFFFFFFFF) {
// 7.2.7 Segment data length, unknown segment length
if (segmentType === 38) { // ImmediateGenericRegion
var genericRegionInfo = readRegionSegmentInformation(data, position);
@@ -37726,17 +37659,17 @@ var Jbig2Image = (function Jbig2ImageClosure() {
searchPattern[3] = (genericRegionInfo.height >> 16) & 0xFF;
searchPattern[4] = (genericRegionInfo.height >> 8) & 0xFF;
searchPattern[5] = genericRegionInfo.height & 0xFF;
- for (var i = position, ii = data.length; i < ii; i++) {
+ for (i = position, ii = data.length; i < ii; i++) {
var j = 0;
while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
j++;
}
- if (j == searchPatternLength) {
+ if (j === searchPatternLength) {
segmentHeader.length = i + searchPatternLength;
break;
}
}
- if (segmentHeader.length == 0xFFFFFFFF) {
+ if (segmentHeader.length === 0xFFFFFFFF) {
error('JBIG2 error: segment end was not found');
}
} else {
@@ -37763,8 +37696,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
segment.end = position;
}
segments.push(segment);
- if (segmentHeader.type == 51)
+ if (segmentHeader.type === 51) {
break; // end of file is found
+ }
}
if (header.randomAccess) {
for (var i = 0, ii = segments.length; i < ii; i++) {
@@ -37792,7 +37726,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var header = segment.header;
var data = segment.data, position = segment.start, end = segment.end;
- var args;
+ var args, at, i, atLength;
switch (header.type) {
case 0: // SymbolDictionary
// 7.4.2 Symbol dictionary segment syntax
@@ -37810,9 +37744,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
position += 2;
if (!dictionary.huffman) {
- var atLength = dictionary.template === 0 ? 4 : 1;
- var at = [];
- for (var i = 0; i < atLength; i++) {
+ atLength = dictionary.template === 0 ? 4 : 1;
+ at = [];
+ for (i = 0; i < atLength; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -37822,8 +37756,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
dictionary.at = at;
}
if (dictionary.refinement && !dictionary.refinementTemplate) {
- var at = [];
- for (var i = 0; i < 2; i++) {
+ at = [];
+ for (i = 0; i < 2; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -37869,8 +37803,8 @@ var Jbig2Image = (function Jbig2ImageClosure() {
!!(textRegionHuffmanFlags & 14);
}
if (textRegion.refinement && !textRegion.refinementTemplate) {
- var at = [];
- for (var i = 0; i < 2; i++) {
+ at = [];
+ for (i = 0; i < 2; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -37882,8 +37816,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
textRegion.numberOfSymbolInstances = readUint32(data, position);
position += 4;
// TODO 7.4.3.1.7 Symbol ID Huffman table decoding
- if (textRegion.huffman)
+ if (textRegion.huffman) {
error('JBIG2 error: huffman is not supported');
+ }
args = [textRegion, header.referredTo, data, position, end];
break;
case 38: // ImmediateGenericRegion
@@ -37896,9 +37831,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
if (!genericRegion.mmr) {
- var atLength = genericRegion.template === 0 ? 4 : 1;
- var at = [];
- for (var i = 0; i < atLength; i++) {
+ atLength = genericRegion.template === 0 ? 4 : 1;
+ at = [];
+ for (i = 0; i < atLength; i++) {
at.push({
x: readInt8(data, position),
y: readInt8(data, position + 1)
@@ -37916,8 +37851,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
resolutionX: readUint32(data, position + 8),
resolutionY: readUint32(data, position + 12)
};
- if (pageInfo.height == 0xFFFFFFFF)
+ if (pageInfo.height === 0xFFFFFFFF) {
delete pageInfo.height;
+ }
var pageSegmentFlags = data[position + 16];
var pageStripingInformatiom = readUint16(data, position + 17);
pageInfo.lossless = !!(pageSegmentFlags & 1);
@@ -37942,22 +37878,25 @@ var Jbig2Image = (function Jbig2ImageClosure() {
header.type + ') is not implemented');
}
var callbackName = 'on' + header.typeName;
- if (callbackName in visitor)
+ if (callbackName in visitor) {
visitor[callbackName].apply(visitor, args);
+ }
}
function processSegments(segments, visitor) {
- for (var i = 0, ii = segments.length; i < ii; i++)
+ for (var i = 0, ii = segments.length; i < ii; i++) {
processSegment(segments[i], visitor);
+ }
}
function parseJbig2(data, start, end) {
var position = start;
- if (data[position] != 0x97 || data[position + 1] != 0x4A ||
- data[position + 2] != 0x42 || data[position + 3] != 0x32 ||
- data[position + 4] != 0x0D || data[position + 5] != 0x0A ||
- data[position + 6] != 0x1A || data[position + 7] != 0x0A)
+ if (data[position] !== 0x97 || data[position + 1] !== 0x4A ||
+ data[position + 2] !== 0x42 || data[position + 3] !== 0x32 ||
+ data[position + 4] !== 0x0D || data[position + 5] !== 0x0A ||
+ data[position + 6] !== 0x1A || data[position + 7] !== 0x0A) {
error('JBIG2 error: invalid header');
+ }
var header = {};
position += 8;
var flags = data[position++];
@@ -37988,9 +37927,13 @@ var Jbig2Image = (function Jbig2ImageClosure() {
this.currentPageInfo = info;
var rowSize = (info.width + 7) >> 3;
var buffer = new Uint8Array(rowSize * info.height);
- var fill = info.defaultPixelValue ? 0xFF : 0;
- for (var i = 0, ii = buffer.length; i < ii; i++)
- buffer[i] = fill;
+ // The contents of ArrayBuffers are initialized to 0.
+ // Fill the buffer with 0xFF only if info.defaultPixelValue is set
+ if (info.defaultPixelValue) {
+ for (var i = 0, ii = buffer.length; i < ii; i++) {
+ buffer[i] = 0xFF;
+ }
+ }
this.buffer = buffer;
},
drawBitmap: function SimpleSegmentVisitor_drawBitmap(regionInfo, bitmap) {
@@ -38000,34 +37943,47 @@ var Jbig2Image = (function Jbig2ImageClosure() {
var combinationOperator = pageInfo.combinationOperatorOverride ?
regionInfo.combinationOperator : pageInfo.combinationOperator;
var buffer = this.buffer;
- for (var i = 0; i < height; i++) {
- var mask = 128 >> (regionInfo.x & 7);
- var offset = (i + regionInfo.y) * rowSize + (regionInfo.x >> 3);
- switch (combinationOperator) {
- case 0: // OR
- for (var j = 0; j < width; j++) {
- buffer[offset] |= bitmap[i][j] ? mask : 0;
+ var mask0 = 128 >> (regionInfo.x & 7);
+ var offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
+ var i, j, mask, offset;
+ switch (combinationOperator) {
+ case 0: // OR
+ for (i = 0; i < height; i++) {
+ mask = mask0;
+ offset = offset0;
+ for (j = 0; j < width; j++) {
+ if (bitmap[i][j]) {
+ buffer[offset] |= mask;
+ }
mask >>= 1;
if (!mask) {
mask = 128;
offset++;
}
}
- break;
- case 2: // XOR
- for (var j = 0; j < width; j++) {
- buffer[offset] ^= bitmap[i][j] ? mask : 0;
+ offset0 += rowSize;
+ }
+ break;
+ case 2: // XOR
+ for (i = 0; i < height; i++) {
+ mask = mask0;
+ offset = offset0;
+ for (j = 0; j < width; j++) {
+ if (bitmap[i][j]) {
+ buffer[offset] ^= mask;
+ }
mask >>= 1;
if (!mask) {
mask = 128;
offset++;
}
}
- break;
- default:
- error('JBIG2 error: operator ' + combinationOperator +
- ' is not supported');
- }
+ offset0 += rowSize;
+ }
+ break;
+ default:
+ error('JBIG2 error: operator ' + combinationOperator +
+ ' is not supported');
}
},
onImmediateGenericRegion:
@@ -38050,17 +38006,20 @@ var Jbig2Image = (function Jbig2ImageClosure() {
referredSegments,
data, start, end) {
var huffmanTables;
- if (dictionary.huffman)
+ if (dictionary.huffman) {
error('JBIG2 error: huffman is not supported');
+ }
// Combines exported symbols from all referred segments
var symbols = this.symbols;
- if (!symbols)
+ if (!symbols) {
this.symbols = symbols = {};
+ }
var inputSymbols = [];
- for (var i = 0, ii = referredSegments.length; i < ii; i++)
+ for (var i = 0, ii = referredSegments.length; i < ii; i++) {
inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
+ }
var decodingContext = new DecodingContext(data, start, end);
symbols[currentSegment] = decodeSymbolDictionary(dictionary.huffman,
@@ -38080,8 +38039,9 @@ var Jbig2Image = (function Jbig2ImageClosure() {
// Combines exported symbols from all referred segments
var symbols = this.symbols;
var inputSymbols = [];
- for (var i = 0, ii = referredSegments.length; i < ii; i++)
+ for (var i = 0, ii = referredSegments.length; i < ii; i++) {
inputSymbols = inputSymbols.concat(symbols[referredSegments[i]]);
+ }
var symbolCodeLength = log2(inputSymbols.length);
var decodingContext = new DecodingContext(data, start, end);
@@ -38095,7 +38055,7 @@ var Jbig2Image = (function Jbig2ImageClosure() {
},
onImmediateLosslessTextRegion:
function SimpleSegmentVisitor_onImmediateLosslessTextRegion() {
- this.onImmediateTextRegion.apply(this, arguments);
+ this.onImmediateTextRegion.apply(this, arguments);
}
};
@@ -38170,10 +38130,10 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
function findUnequal(arr, start, value) {
- var j;
for (var j = start, jj = arr.length; j < jj; ++j) {
- if (arr[j] != value)
+ if (arr[j] !== value) {
return j;
+ }
}
return j;
}
@@ -38192,94 +38152,61 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
}
- function mirrorGlyphs(c) {
- /*
- # BidiMirroring-1.txt
- 0028; 0029 # LEFT PARENTHESIS
- 0029; 0028 # RIGHT PARENTHESIS
- 003C; 003E # LESS-THAN SIGN
- 003E; 003C # GREATER-THAN SIGN
- 005B; 005D # LEFT SQUARE BRACKET
- 005D; 005B # RIGHT SQUARE BRACKET
- 007B; 007D # LEFT CURLY BRACKET
- 007D; 007B # RIGHT CURLY BRACKET
- 00AB; 00BB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
- 00BB; 00AB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- */
- switch (c) {
- case '(':
- return ')';
- case ')':
- return '(';
- case '<':
- return '>';
- case '>':
- return '<';
- case ']':
- return '[';
- case '[':
- return ']';
- case '}':
- return '{';
- case '{':
- return '}';
- case '\u00AB':
- return '\u00BB';
- case '\u00BB':
- return '\u00AB';
- default:
- return c;
- }
+ function createBidiText(str, isLTR, vertical) {
+ return {
+ str: str,
+ dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
+ };
}
- function BidiResult(str, isLTR, vertical) {
- this.str = str;
- this.dir = vertical ? 'ttb' : isLTR ? 'ltr' : 'rtl';
- }
+ // These are used in bidi(), which is called frequently. We re-use them on
+ // each call to avoid unnecessary allocations.
+ var chars = [];
+ var types = [];
function bidi(str, startLevel, vertical) {
var isLTR = true;
var strLength = str.length;
- if (strLength === 0 || vertical)
- return new BidiResult(str, isLTR, vertical);
+ if (strLength === 0 || vertical) {
+ return createBidiText(str, isLTR, vertical);
+ }
- // get types, fill arrays
-
- var chars = [];
- var types = [];
- var oldtypes = [];
+ // Get types and fill arrays
+ chars.length = strLength;
+ types.length = strLength;
var numBidi = 0;
- for (var i = 0; i < strLength; ++i) {
+ var i, ii;
+ for (i = 0; i < strLength; ++i) {
chars[i] = str.charAt(i);
var charCode = str.charCodeAt(i);
var charType = 'L';
- if (charCode <= 0x00ff)
+ if (charCode <= 0x00ff) {
charType = baseTypes[charCode];
- else if (0x0590 <= charCode && charCode <= 0x05f4)
+ } else if (0x0590 <= charCode && charCode <= 0x05f4) {
charType = 'R';
- else if (0x0600 <= charCode && charCode <= 0x06ff)
+ } else if (0x0600 <= charCode && charCode <= 0x06ff) {
charType = arabicTypes[charCode & 0xff];
- else if (0x0700 <= charCode && charCode <= 0x08AC)
+ } else if (0x0700 <= charCode && charCode <= 0x08AC) {
charType = 'AL';
-
- if (charType == 'R' || charType == 'AL' || charType == 'AN')
+ }
+ if (charType === 'R' || charType === 'AL' || charType === 'AN') {
numBidi++;
-
- oldtypes[i] = types[i] = charType;
+ }
+ types[i] = charType;
}
- // detect the bidi method
- // if there are no rtl characters then no bidi needed
- // if less than 30% chars are rtl then string is primarily ltr
- // if more than 30% chars are rtl then string is primarily rtl
+ // Detect the bidi method
+ // - If there are no rtl characters then no bidi needed
+ // - If less than 30% chars are rtl then string is primarily ltr
+ // - If more than 30% chars are rtl then string is primarily rtl
if (numBidi === 0) {
isLTR = true;
- return new BidiResult(str, isLTR);
+ return createBidiText(str, isLTR);
}
- if (startLevel == -1) {
+ if (startLevel === -1) {
if ((strLength / numBidi) < 0.3) {
isLTR = true;
startLevel = 0;
@@ -38290,16 +38217,14 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
}
var levels = [];
-
- for (var i = 0; i < strLength; ++i) {
+ for (i = 0; i < strLength; ++i) {
levels[i] = startLevel;
}
/*
X1-X10: skip most of this, since we are NOT doing the embeddings.
*/
-
- var e = isOdd(startLevel) ? 'R' : 'L';
+ var e = (isOdd(startLevel) ? 'R' : 'L');
var sor = e;
var eor = sor;
@@ -38308,13 +38233,13 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
type of the NSM to the type of the previous character. If the NSM is at the
start of the level run, it will get the type of sor.
*/
-
var lastType = sor;
- for (var i = 0; i < strLength; ++i) {
- if (types[i] == 'NSM')
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === 'NSM') {
types[i] = lastType;
- else
+ } else {
lastType = types[i];
+ }
}
/*
@@ -38322,24 +38247,25 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
first strong type (R, L, AL, or sor) is found. If an AL is found, change
the type of the European number to Arabic number.
*/
-
- var lastType = sor;
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
- if (t == 'EN')
- types[i] = (lastType == 'AL') ? 'AN' : 'EN';
- else if (t == 'R' || t == 'L' || t == 'AL')
+ lastType = sor;
+ var t;
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === 'EN') {
+ types[i] = (lastType === 'AL') ? 'AN' : 'EN';
+ } else if (t === 'R' || t === 'L' || t === 'AL') {
lastType = t;
+ }
}
/*
W3. Change all ALs to R.
*/
-
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
- if (t == 'AL')
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === 'AL') {
types[i] = 'R';
+ }
}
/*
@@ -38347,32 +38273,36 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
European number. A single common separator between two numbers of the same
type changes to that type:
*/
-
- for (var i = 1; i < strLength - 1; ++i) {
- if (types[i] == 'ES' && types[i - 1] == 'EN' && types[i + 1] == 'EN')
+ for (i = 1; i < strLength - 1; ++i) {
+ if (types[i] === 'ES' && types[i - 1] === 'EN' && types[i + 1] === 'EN') {
types[i] = 'EN';
- if (types[i] == 'CS' && (types[i - 1] == 'EN' || types[i - 1] == 'AN') &&
- types[i + 1] == types[i - 1])
+ }
+ if (types[i] === 'CS' &&
+ (types[i - 1] === 'EN' || types[i - 1] === 'AN') &&
+ types[i + 1] === types[i - 1]) {
types[i] = types[i - 1];
+ }
}
/*
W5. A sequence of European terminators adjacent to European numbers changes
to all European numbers:
*/
-
- for (var i = 0; i < strLength; ++i) {
- if (types[i] == 'EN') {
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === 'EN') {
// do before
- for (var j = i - 1; j >= 0; --j) {
- if (types[j] != 'ET')
+ var j;
+ for (j = i - 1; j >= 0; --j) {
+ if (types[j] !== 'ET') {
break;
+ }
types[j] = 'EN';
}
// do after
- for (var j = i + 1; j < strLength; --j) {
- if (types[j] != 'ET')
+ for (j = i + 1; j < strLength; --j) {
+ if (types[j] !== 'ET') {
break;
+ }
types[j] = 'EN';
}
}
@@ -38381,11 +38311,11 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
/*
W6. Otherwise, separators and terminators change to Other Neutral:
*/
-
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
- if (t == 'WS' || t == 'ES' || t == 'ET' || t == 'CS')
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === 'WS' || t === 'ES' || t === 'ET' || t === 'CS') {
types[i] = 'ON';
+ }
}
/*
@@ -38393,14 +38323,14 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
first strong type (R, L, or sor) is found. If an L is found, then change
the type of the European number to L.
*/
-
- var lastType = sor;
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
- if (t == 'EN')
- types[i] = (lastType == 'L') ? 'L' : 'EN';
- else if (t == 'R' || t == 'L')
+ lastType = sor;
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
+ if (t === 'EN') {
+ types[i] = ((lastType === 'L') ? 'L' : 'EN');
+ } else if (t === 'R' || t === 'L') {
lastType = t;
+ }
}
/*
@@ -38409,22 +38339,27 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
numbers are treated as though they were R. Start-of-level-run (sor) and
end-of-level-run (eor) are used at level run boundaries.
*/
-
- for (var i = 0; i < strLength; ++i) {
- if (types[i] == 'ON') {
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === 'ON') {
var end = findUnequal(types, i + 1, 'ON');
var before = sor;
- if (i > 0)
+ if (i > 0) {
before = types[i - 1];
+ }
+
var after = eor;
- if (end + 1 < strLength)
+ if (end + 1 < strLength) {
after = types[end + 1];
- if (before != 'L')
+ }
+ if (before !== 'L') {
before = 'R';
- if (after != 'L')
+ }
+ if (after !== 'L') {
after = 'R';
- if (before == after)
+ }
+ if (before === after) {
setValues(types, i, end, before);
+ }
i = end - 1; // reset to end (-1 so next iteration is ok)
}
}
@@ -38432,10 +38367,10 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
/*
N2. Any remaining neutrals take the embedding direction.
*/
-
- for (var i = 0; i < strLength; ++i) {
- if (types[i] == 'ON')
+ for (i = 0; i < strLength; ++i) {
+ if (types[i] === 'ON') {
types[i] = e;
+ }
}
/*
@@ -38445,17 +38380,16 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
I2. For all characters with an odd (right-to-left) embedding direction,
those of type L, EN or AN go up one level.
*/
-
- for (var i = 0; i < strLength; ++i) {
- var t = types[i];
+ for (i = 0; i < strLength; ++i) {
+ t = types[i];
if (isEven(levels[i])) {
- if (t == 'R') {
+ if (t === 'R') {
levels[i] += 1;
- } else if (t == 'AN' || t == 'EN') {
+ } else if (t === 'AN' || t === 'EN') {
levels[i] += 2;
}
- } else { // isOdd, so
- if (t == 'L' || t == 'AN' || t == 'EN') {
+ } else { // isOdd
+ if (t === 'L' || t === 'AN' || t === 'EN') {
levels[i] += 1;
}
}
@@ -38481,23 +38415,24 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
*/
// find highest level & lowest odd level
-
var highestLevel = -1;
var lowestOddLevel = 99;
- for (var i = 0, ii = levels.length; i < ii; ++i) {
- var level = levels[i];
- if (highestLevel < level)
+ var level;
+ for (i = 0, ii = levels.length; i < ii; ++i) {
+ level = levels[i];
+ if (highestLevel < level) {
highestLevel = level;
- if (lowestOddLevel > level && isOdd(level))
+ }
+ if (lowestOddLevel > level && isOdd(level)) {
lowestOddLevel = level;
+ }
}
// now reverse between those limits
-
- for (var level = highestLevel; level >= lowestOddLevel; --level) {
+ for (level = highestLevel; level >= lowestOddLevel; --level) {
// find segments to reverse
var start = -1;
- for (var i = 0, ii = levels.length; i < ii; ++i) {
+ for (i = 0, ii = levels.length; i < ii; ++i) {
if (levels[i] < level) {
if (start >= 0) {
reverseValues(chars, start, i);
@@ -38530,1414 +38465,183 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
// don't mirror as characters are already mirrored in the pdf
// Finally, return string
-
var result = '';
- for (var i = 0, ii = chars.length; i < ii; ++i) {
+ for (i = 0, ii = chars.length; i < ii; ++i) {
var ch = chars[i];
- if (ch != '<' && ch != '>')
+ if (ch !== '<' && ch !== '>') {
result += ch;
+ }
}
-
- return new BidiResult(result, isLTR);
+ return createBidiText(result, isLTR);
}
return bidi;
})();
-
-var CMAP_CODESPACES = {
- 'Adobe-CNS1-0': [[], [0, 14335]],
- 'Adobe-CNS1-1': [[], [0, 17407]],
- 'Adobe-CNS1-2': [[], [0, 17663]],
- 'Adobe-CNS1-3': [[], [0, 18943]],
- 'Adobe-CNS1-4': [[], [0, 19199]],
- 'Adobe-CNS1-5': [[], [0, 19199]],
- 'Adobe-CNS1-6': [[], [0, 19199]],
- 'Adobe-CNS1-UCS2': [[], [0, 65535]],
- 'B5-H': [[0, 128], [41280, 65278]],
- 'B5-V': [[0, 128], [41280, 65278]],
- 'B5pc-H': [[0, 128, 253, 255], [41280, 64766]],
- 'B5pc-V': [[0, 128, 253, 255], [41280, 64766]],
- 'CNS-EUC-H': [[0, 128], [41377, 65278], [],
- [2392957345, 2392981246, 2393022881, 2393046782, 2393088417, 2393112318]],
- 'CNS-EUC-V': [[0, 128], [41377, 65278], [],
- [2392957345, 2392981246, 2393022881, 2393046782, 2393088417, 2393112318]],
- 'CNS1-H': [[], [8481, 32382]],
- 'CNS1-V': [[], [8481, 32382]],
- 'CNS2-H': [[], [8481, 32382]],
- 'CNS2-V': [[], [8481, 32382]],
- 'ETen-B5-H': [[0, 128], [41280, 65278]],
- 'ETen-B5-V': [[0, 128], [41280, 65278]],
- 'ETenms-B5-H': [[0, 128], [41280, 65278]],
- 'ETenms-B5-V': [[0, 128], [41280, 65278]],
- 'ETHK-B5-H': [[0, 128], [34624, 65278]],
- 'ETHK-B5-V': [[0, 128], [34624, 65278]],
- 'HKdla-B5-H': [[0, 128], [41280, 65278]],
- 'HKdla-B5-V': [[0, 128], [41280, 65278]],
- 'HKdlb-B5-H': [[0, 128], [36416, 65278]],
- 'HKdlb-B5-V': [[0, 128], [36416, 65278]],
- 'HKgccs-B5-H': [[0, 128], [35392, 65278]],
- 'HKgccs-B5-V': [[0, 128], [35392, 65278]],
- 'HKm314-B5-H': [[0, 128], [41280, 65278]],
- 'HKm314-B5-V': [[0, 128], [41280, 65278]],
- 'HKm471-B5-H': [[0, 128], [41280, 65278]],
- 'HKm471-B5-V': [[0, 128], [41280, 65278]],
- 'HKscs-B5-H': [[0, 128], [34624, 65278]],
- 'HKscs-B5-V': [[0, 128], [34624, 65278]],
- 'UniCNS-UCS2-H': [[], [0, 55295, 57344, 65535]],
- 'UniCNS-UCS2-V': [[], [0, 55295, 57344, 65535]],
- 'UniCNS-UTF16-H': [[], [0, 55295, 57344, 65535], [],
- [3623934976, 3690979327]],
- 'UniCNS-UTF16-V': [[], [0, 55295, 57344, 65535], [],
- [3623934976, 3690979327]],
- 'Adobe-GB1-0': [[], [0, 7935]],
- 'Adobe-GB1-1': [[], [0, 9983]],
- 'Adobe-GB1-2': [[], [0, 22271]],
- 'Adobe-GB1-3': [[], [0, 22527]],
- 'Adobe-GB1-4': [[], [0, 29183]],
- 'Adobe-GB1-5': [[], [0, 30463]],
- 'Adobe-GB1-UCS2': [[], [0, 65535]],
- 'GB-EUC-H': [[0, 128], [41377, 65278]],
- 'GB-EUC-V': [[0, 128], [41377, 65278]],
- 'GB-H': [[], [8481, 32382]],
- 'GB-V': [[], [8481, 32382]],
- 'GBK-EUC-H': [[0, 128], [33088, 65278]],
- 'GBK-EUC-V': [[0, 128], [33088, 65278]],
- 'GBK2K-H': [[0, 127], [33088, 65278], [], [2167439664, 4265213497]],
- 'GBK2K-V': [[0, 127], [33088, 65278], [], [2167439664, 4265213497]],
- 'GBKp-EUC-H': [[0, 128], [33088, 65278]],
- 'GBKp-EUC-V': [[0, 128], [33088, 65278]],
- 'GBpc-EUC-H': [[0, 128, 253, 255], [41377, 64766]],
- 'GBpc-EUC-V': [[0, 128, 253, 255], [41377, 64766]],
- 'GBT-EUC-H': [[0, 128], [41377, 65278]],
- 'GBT-EUC-V': [[0, 128], [41377, 65278]],
- 'GBT-H': [[], [8481, 32382]],
- 'GBT-V': [[], [8481, 32382]],
- 'GBTpc-EUC-H': [[0, 128, 253, 255], [41377, 64766]],
- 'GBTpc-EUC-V': [[0, 128, 253, 255], [41377, 64766]],
- 'UniGB-UCS2-H': [[], [0, 55295, 57344, 65535]],
- 'UniGB-UCS2-V': [[], [0, 55295, 57344, 65535]],
- 'UniGB-UTF16-H': [[], [0, 55295, 57344, 65535], [], [3623934976, 3690979327]],
- 'UniGB-UTF16-V': [[], [0, 55295, 57344, 65535], [], [3623934976, 3690979327]],
- '78-EUC-H': [[0, 128], [36512, 36575, 41377, 65278]],
- '78-EUC-V': [[0, 128], [36512, 36575, 41377, 65278]],
- '78-H': [[], [8481, 32382]],
- '78-RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '78-RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '78-V': [[], [8481, 32382]],
- '78ms-RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '78ms-RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '83pv-RKSJ-H': [[0, 128, 160, 223, 253, 255], [33088, 40956, 57408, 64764]],
- '90ms-RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '90ms-RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '90msp-RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '90msp-RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- '90pv-RKSJ-H': [[0, 128, 160, 223, 253, 255], [33088, 40956, 57408, 64764]],
- '90pv-RKSJ-V': [[0, 128, 160, 223, 253, 255], [33088, 40956, 57408, 64764]],
- 'Add-H': [[], [8481, 32382]],
- 'Add-RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- 'Add-RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- 'Add-V': [[], [8481, 32382]],
- 'Adobe-Japan1-0': [[], [0, 8447]],
- 'Adobe-Japan1-1': [[], [0, 8447]],
- 'Adobe-Japan1-2': [[], [0, 8959]],
- 'Adobe-Japan1-3': [[], [0, 9471]],
- 'Adobe-Japan1-4': [[], [0, 15615]],
- 'Adobe-Japan1-5': [[], [0, 20479]],
- 'Adobe-Japan1-6': [[], [0, 23295]],
- 'Adobe-Japan1-UCS2': [[], [0, 65535]],
- 'Adobe-Japan2-0': [[], [0, 6143]],
- 'EUC-H': [[0, 128], [36512, 36575, 41377, 65278]],
- 'EUC-V': [[0, 128], [36512, 36575, 41377, 65278]],
- 'Ext-H': [[], [8481, 32382]],
- 'Ext-RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- 'Ext-RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- 'Ext-V': [[], [8481, 32382]],
- 'H': [[], [8481, 32382]],
- 'Hankaku': [[0, 255], []],
- 'Hiragana': [[0, 255], []],
- 'Hojo-EUC-H': [[], [], [9413025, 9436926], []],
- 'Hojo-EUC-V': [[], [], [9413025, 9436926], []],
- 'Hojo-H': [[], [8481, 32382]],
- 'Hojo-V': [[], [8481, 32382]],
- 'Katakana': [[0, 255], []],
- 'NWP-H': [[], [8481, 32382]],
- 'NWP-V': [[], [8481, 32382]],
- 'RKSJ-H': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- 'RKSJ-V': [[0, 128, 160, 223], [33088, 40956, 57408, 64764]],
- 'Roman': [[0, 255], []],
- 'UniHojo-UCS2-H': [[], [0, 55295, 57344, 65535]],
- 'UniHojo-UCS2-V': [[], [0, 55295, 57344, 65535]],
- 'UniHojo-UTF16-H': [[], [0, 55295, 57344, 65535], [],
- [3623934976, 3690979327]],
- 'UniHojo-UTF16-V': [[], [0, 55295, 57344, 65535], [],
- [3623934976, 3690979327]],
- 'UniJIS-UCS2-H': [[], [0, 55295, 57344, 65535]],
- 'UniJIS-UCS2-HW-H': [[], [0, 55295, 57344, 65535]],
- 'UniJIS-UCS2-HW-V': [[], [0, 55295, 57344, 65535]],
- 'UniJIS-UCS2-V': [[], [0, 55295, 57344, 65535]],
- 'UniJIS-UTF16-H': [[], [0, 55295, 57344, 65535], [],
- [3623934976, 3690979327]],
- 'UniJIS-UTF16-V': [[], [0, 55295, 57344, 65535], [],
- [3623934976, 3690979327]],
- 'UniJISPro-UCS2-HW-V': [[], [0, 55295, 57344, 65535]],
- 'UniJISPro-UCS2-V': [[], [0, 55295, 57344, 65535]],
- 'V': [[], [8481, 32382]],
- 'WP-Symbol': [[0, 255], []],
- 'Adobe-Korea1-0': [[], [0, 9471]],
- 'Adobe-Korea1-1': [[], [0, 18175]],
- 'Adobe-Korea1-2': [[], [0, 18431]],
- 'Adobe-Korea1-UCS2': [[], [0, 65535]],
- 'KSC-EUC-H': [[0, 128], [41377, 65278]],
- 'KSC-EUC-V': [[0, 128], [41377, 65278]],
- 'KSC-H': [[], [8481, 32382]],
- 'KSC-Johab-H': [[0, 128], [33857, 54270, 55345, 57086, 57393, 63998]],
- 'KSC-Johab-V': [[0, 128], [33857, 54270, 55345, 57086, 57393, 63998]],
- 'KSC-V': [[], [8481, 32382]],
- 'KSCms-UHC-H': [[0, 128], [33089, 65278]],
- 'KSCms-UHC-HW-H': [[0, 128], [33089, 65278]],
- 'KSCms-UHC-HW-V': [[0, 128], [33089, 65278]],
- 'KSCms-UHC-V': [[0, 128], [33089, 65278]],
- 'KSCpc-EUC-H': [[0, 132, 254, 255], [41281, 65022]],
- 'KSCpc-EUC-V': [[0, 132, 254, 255], [41281, 65022]],
- 'UniKS-UCS2-H': [[], [0, 55295, 57344, 65535]],
- 'UniKS-UCS2-V': [[], [0, 55295, 57344, 65535]],
- 'UniKS-UTF16-H': [[], [0, 55295, 57344, 65535], [], [3623934976, 3690979327]],
- 'UniKS-UTF16-V': [[], [0, 55295, 57344, 65535], [], [3623934976, 3690979327]]
-};
-
-// CMap, not to be confused with TrueType's cmap.
-var CMap = (function CMapClosure() {
- function CMap() {
- // Codespace ranges are stored as follows:
- // [[1BytePairs], [2BytePairs], [3BytePairs], [4BytePairs]]
- // where nBytePairs are ranges e.g. [low1, high1, low2, high2, ...]
- this.codespaceRanges = [[], [], [], []];
- this.map = [];
- this.vertical = false;
- }
- CMap.prototype = {
- addCodespaceRange: function(n, low, high) {
- this.codespaceRanges[n - 1].push(low, high);
- },
-
- mapRange: function(low, high, dstLow) {
- var lastByte = dstLow.length - 1;
- while (low <= high) {
- this.map[low] = dstLow;
- // Only the last byte has to be incremented.
- dstLow = dstLow.substr(0, lastByte) +
- String.fromCharCode(dstLow.charCodeAt(lastByte) + 1);
- ++low;
- }
- },
-
- mapRangeToArray: function(low, high, array) {
- var i = 0;
- while (low <= high) {
- this.map[low] = array[i++];
- ++low;
- }
- },
-
- mapOne: function(src, dst) {
- this.map[src] = dst;
- },
-
- lookup: function(code) {
- return this.map[code];
- },
-
- readCharCode: function(str, offset) {
- var c = 0;
- var codespaceRanges = this.codespaceRanges;
- var codespaceRangesLen = this.codespaceRanges.length;
- // 9.7.6.2 CMap Mapping
- // The code length is at most 4.
- for (var n = 0; n < codespaceRangesLen; n++) {
- c = ((c << 8) | str.charCodeAt(offset + n)) >>> 0;
- // Check each codespace range to see if it falls within.
- var codespaceRange = codespaceRanges[n];
- for (var k = 0, kk = codespaceRange.length; k < kk;) {
- var low = codespaceRange[k++];
- var high = codespaceRange[k++];
- if (c >= low && c <= high) {
- return [c, n + 1];
- }
- }
- }
-
- return [0, 1];
- }
-
- };
- return CMap;
-})();
-
-var IdentityCMap = (function IdentityCMapClosure() {
- function IdentityCMap(vertical, n) {
- CMap.call(this);
- this.vertical = vertical;
- this.addCodespaceRange(n, 0, 0xffff);
- this.mapRange(0, 0xffff, '\u0000');
- }
- Util.inherit(IdentityCMap, CMap, {});
-
- return IdentityCMap;
-})();
-
-var CMapFactory = (function CMapFactoryClosure() {
- function strToInt(str) {
- var a = 0;
- for (var i = 0; i < str.length; i++) {
- a = (a << 8) | str.charCodeAt(i);
- }
- return a >>> 0;
- }
-
- function expectString(obj) {
- if (!isString(obj)) {
- error('Malformed CMap: expected string.');
- }
- }
-
- function expectInt(obj) {
- if (!isInt(obj)) {
- error('Malformed CMap: expected int.');
- }
- }
-
- function parseBfChar(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endbfchar')) {
- return;
- }
- expectString(obj);
- var src = strToInt(obj);
- obj = lexer.getObj();
- // TODO are /dstName used?
- expectString(obj);
- var dst = obj;
- cMap.mapOne(src, dst);
- }
- }
-
- function parseBfRange(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endbfrange')) {
- return;
- }
- expectString(obj);
- var low = strToInt(obj);
- obj = lexer.getObj();
- expectString(obj);
- var high = strToInt(obj);
- obj = lexer.getObj();
- if (isInt(obj) || isString(obj)) {
- var dstLow = isInt(obj) ? String.fromCharCode(obj) : obj;
- cMap.mapRange(low, high, dstLow);
- } else if (isCmd(obj, '[')) {
- obj = lexer.getObj();
- var array = [];
- while (!isCmd(obj, ']') && !isEOF(obj)) {
- array.push(obj);
- obj = lexer.getObj();
- }
- cMap.mapRangeToArray(low, high, array);
- } else {
- break;
- }
- }
- error('Invalid bf range.');
- }
-
- function parseCidChar(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endcidchar')) {
- return;
- }
- expectString(obj);
- var src = strToInt(obj);
- obj = lexer.getObj();
- expectInt(obj);
- var dst = String.fromCharCode(obj);
- cMap.mapOne(src, dst);
- }
- }
-
- function parseCidRange(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endcidrange')) {
- return;
- }
- expectString(obj);
- var low = strToInt(obj);
- obj = lexer.getObj();
- expectString(obj);
- var high = strToInt(obj);
- obj = lexer.getObj();
- expectInt(obj);
- var dstLow = String.fromCharCode(obj);
- cMap.mapRange(low, high, dstLow);
- }
- }
-
- function parseCodespaceRange(cMap, lexer) {
- while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- }
- if (isCmd(obj, 'endcodespacerange')) {
- return;
- }
- if (!isString(obj)) {
- break;
- }
- var low = strToInt(obj);
- obj = lexer.getObj();
- if (!isString(obj)) {
- break;
- }
- var high = strToInt(obj);
- cMap.addCodespaceRange(obj.length, low, high);
- }
- error('Invalid codespace range.');
- }
-
- function parseCmap(cMap, lexer) {
- objLoop: while (true) {
- var obj = lexer.getObj();
- if (isEOF(obj)) {
- break;
- } else if (isCmd(obj)) {
- switch (obj.cmd) {
- case 'endcMap':
- break objLoop;
- case 'usecMap':
- // TODO
- break;
- case 'begincodespacerange':
- parseCodespaceRange(cMap, lexer);
- break;
- case 'beginbfchar':
- parseBfChar(cMap, lexer);
- break;
- case 'begincidchar':
- parseCidChar(cMap, lexer);
- break;
- case 'beginbfrange':
- parseBfRange(cMap, lexer);
- break;
- case 'begincidrange':
- parseCidRange(cMap, lexer);
- break;
- }
- }
- }
- }
- return {
- create: function (encoding) {
- if (isName(encoding)) {
- switch (encoding.name) {
- case 'Identity-H':
- return new IdentityCMap(false, 2);
- case 'Identity-V':
- return new IdentityCMap(true, 2);
- default:
- if (encoding.name in CMAP_CODESPACES) {
- // XXX: Temporary hack so the correct amount of bytes are read in
- // CMap.readCharCode.
- var cMap = new CMap();
- cMap.codespaceRanges = CMAP_CODESPACES[encoding.name];
- return cMap;
- }
- return null;
- }
- } else if (isStream(encoding)) {
- var cMap = new CMap();
- var lexer = new Lexer(encoding);
- try {
- parseCmap(cMap, lexer);
- } catch (e) {
- warn('Invalid CMap data. ' + e);
- }
- return cMap;
- }
- error('Encoding required.');
- }
- };
-})();
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-/*
- Copyright 2011 notmasteryet
- 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
+/* Copyright 2014 Opera Software ASA
+ *
+ * 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.
+ *
+ *
+ * Based on https://code.google.com/p/smhasher/wiki/MurmurHash3.
+ * Hashes roughly 100 KB per millisecond on i7 3.4 GHz.
+ */
+/* globals Uint32ArrayView */
- http://www.apache.org/licenses/LICENSE-2.0
+'use strict';
- 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.
-*/
+var MurmurHash3_64 = (function MurmurHash3_64Closure (seed) {
+ // Workaround for missing math precison in JS.
+ var MASK_HIGH = 0xffff0000;
+ var MASK_LOW = 0xffff;
-// - The JPEG specification can be found in the ITU CCITT Recommendation T.81
-// (www.w3.org/Graphics/JPEG/itu-t81.pdf)
-// - The JFIF specification can be found in the JPEG File Interchange Format
-// (www.w3.org/Graphics/JPEG/jfif3.pdf)
-// - The Adobe Application-Specific JPEG markers in the Supporting the DCT Filters
-// in PostScript Level 2, Technical Note #5116
-// (partners.adobe.com/public/developer/en/ps/sdk/5116.DCT_Filter.pdf)
-
-var JpegImage = (function jpegImage() {
- "use strict";
- var dctZigZag = new Int32Array([
- 0,
- 1, 8,
- 16, 9, 2,
- 3, 10, 17, 24,
- 32, 25, 18, 11, 4,
- 5, 12, 19, 26, 33, 40,
- 48, 41, 34, 27, 20, 13, 6,
- 7, 14, 21, 28, 35, 42, 49, 56,
- 57, 50, 43, 36, 29, 22, 15,
- 23, 30, 37, 44, 51, 58,
- 59, 52, 45, 38, 31,
- 39, 46, 53, 60,
- 61, 54, 47,
- 55, 62,
- 63
- ]);
-
- var dctCos1 = 4017 // cos(pi/16)
- var dctSin1 = 799 // sin(pi/16)
- var dctCos3 = 3406 // cos(3*pi/16)
- var dctSin3 = 2276 // sin(3*pi/16)
- var dctCos6 = 1567 // cos(6*pi/16)
- var dctSin6 = 3784 // sin(6*pi/16)
- var dctSqrt2 = 5793 // sqrt(2)
- var dctSqrt1d2 = 2896 // sqrt(2) / 2
-
- function constructor() {
+ function MurmurHash3_64 (seed) {
+ var SEED = 0xc3d2e1f0;
+ this.h1 = seed ? seed & 0xffffffff : SEED;
+ this.h2 = seed ? seed & 0xffffffff : SEED;
}
- function buildHuffmanTable(codeLengths, values) {
- var k = 0, code = [], i, j, length = 16;
- while (length > 0 && !codeLengths[length - 1])
- length--;
- code.push({children: [], index: 0});
- var p = code[0], q;
- for (i = 0; i < length; i++) {
- for (j = 0; j < codeLengths[i]; j++) {
- p = code.pop();
- p.children[p.index] = values[k];
- while (p.index > 0) {
- p = code.pop();
- }
- p.index++;
- code.push(p);
- while (code.length <= i) {
- code.push(q = {children: [], index: 0});
- p.children[p.index] = q.children;
- p = q;
- }
- k++;
- }
- if (i + 1 < length) {
- // p here points to last code
- code.push(q = {children: [], index: 0});
- p.children[p.index] = q.children;
- p = q;
- }
- }
- return code[0].children;
+ var alwaysUseUint32ArrayView = false;
+ // old webkits have issues with non-aligned arrays
+ try {
+ new Uint32Array(new Uint8Array(5).buffer, 0, 1);
+ } catch (e) {
+ alwaysUseUint32ArrayView = true;
}
- function decodeScan(data, offset,
- frame, components, resetInterval,
- spectralStart, spectralEnd,
- successivePrev, successive) {
- var precision = frame.precision;
- var samplesPerLine = frame.samplesPerLine;
- var scanLines = frame.scanLines;
- var mcusPerLine = frame.mcusPerLine;
- var progressive = frame.progressive;
- var maxH = frame.maxH, maxV = frame.maxV;
-
- var startOffset = offset, bitsData = 0, bitsCount = 0;
- function readBit() {
- if (bitsCount > 0) {
- bitsCount--;
- return (bitsData >> bitsCount) & 1;
- }
- bitsData = data[offset++];
- if (bitsData == 0xFF) {
- var nextByte = data[offset++];
- if (nextByte) {
- throw "unexpected marker: " + ((bitsData << 8) | nextByte).toString(16);
- }
- // unstuff 0
- }
- bitsCount = 7;
- return bitsData >>> 7;
- }
- function decodeHuffman(tree) {
- var node = tree, bit;
- while ((bit = readBit()) !== null) {
- node = node[bit];
- if (typeof node === 'number')
- return node;
- if (typeof node !== 'object')
- throw "invalid huffman sequence";
- }
- return null;
- }
- function receive(length) {
- var n = 0;
- while (length > 0) {
- var bit = readBit();
- if (bit === null) return;
- n = (n << 1) | bit;
- length--;
- }
- return n;
- }
- function receiveAndExtend(length) {
- var n = receive(length);
- if (n >= 1 << (length - 1))
- return n;
- return n + (-1 << length) + 1;
- }
- function decodeBaseline(component, zz) {
- var t = decodeHuffman(component.huffmanTableDC);
- var diff = t === 0 ? 0 : receiveAndExtend(t);
- zz[0]= (component.pred += diff);
- var k = 1;
- while (k < 64) {
- var rs = decodeHuffman(component.huffmanTableAC);
- var s = rs & 15, r = rs >> 4;
- if (s === 0) {
- if (r < 15)
- break;
- k += 16;
- continue;
- }
- k += r;
- var z = dctZigZag[k];
- zz[z] = receiveAndExtend(s);
- k++;
- }
- }
- function decodeDCFirst(component, zz) {
- var t = decodeHuffman(component.huffmanTableDC);
- var diff = t === 0 ? 0 : (receiveAndExtend(t) << successive);
- zz[0] = (component.pred += diff);
- }
- function decodeDCSuccessive(component, zz) {
- zz[0] |= readBit() << successive;
- }
- var eobrun = 0;
- function decodeACFirst(component, zz) {
- if (eobrun > 0) {
- eobrun--;
- return;
- }
- var k = spectralStart, e = spectralEnd;
- while (k <= e) {
- var rs = decodeHuffman(component.huffmanTableAC);
- var s = rs & 15, r = rs >> 4;
- if (s === 0) {
- if (r < 15) {
- eobrun = receive(r) + (1 << r) - 1;
- break;
- }
- k += 16;
- continue;
- }
- k += r;
- var z = dctZigZag[k];
- zz[z] = receiveAndExtend(s) * (1 << successive);
- k++;
- }
- }
- var successiveACState = 0, successiveACNextValue;
- function decodeACSuccessive(component, zz) {
- var k = spectralStart, e = spectralEnd, r = 0;
- while (k <= e) {
- var z = dctZigZag[k];
- switch (successiveACState) {
- case 0: // initial state
- var rs = decodeHuffman(component.huffmanTableAC);
- var s = rs & 15, r = rs >> 4;
- if (s === 0) {
- if (r < 15) {
- eobrun = receive(r) + (1 << r);
- successiveACState = 4;
- } else {
- r = 16;
- successiveACState = 1;
- }
- } else {
- if (s !== 1)
- throw "invalid ACn encoding";
- successiveACNextValue = receiveAndExtend(s);
- successiveACState = r ? 2 : 3;
- }
- continue;
- case 1: // skipping r zero items
- case 2:
- if (zz[z])
- zz[z] += (readBit() << successive);
- else {
- r--;
- if (r === 0)
- successiveACState = successiveACState == 2 ? 3 : 0;
- }
- break;
- case 3: // set value for a zero item
- if (zz[z])
- zz[z] += (readBit() << successive);
- else {
- zz[z] = successiveACNextValue << successive;
- successiveACState = 0;
- }
- break;
- case 4: // eob
- if (zz[z])
- zz[z] += (readBit() << successive);
- break;
- }
- k++;
- }
- if (successiveACState === 4) {
- eobrun--;
- if (eobrun === 0)
- successiveACState = 0;
- }
- }
- function decodeMcu(component, decode, mcu, row, col) {
- var mcuRow = (mcu / mcusPerLine) | 0;
- var mcuCol = mcu % mcusPerLine;
- var blockRow = mcuRow * component.v + row;
- var blockCol = mcuCol * component.h + col;
- decode(component, component.blocks[blockRow][blockCol]);
- }
- function decodeBlock(component, decode, mcu) {
- var blockRow = (mcu / component.blocksPerLine) | 0;
- var blockCol = mcu % component.blocksPerLine;
- decode(component, component.blocks[blockRow][blockCol]);
- }
-
- var componentsLength = components.length;
- var component, i, j, k, n;
- var decodeFn;
- if (progressive) {
- if (spectralStart === 0)
- decodeFn = successivePrev === 0 ? decodeDCFirst : decodeDCSuccessive;
- else
- decodeFn = successivePrev === 0 ? decodeACFirst : decodeACSuccessive;
- } else {
- decodeFn = decodeBaseline;
- }
-
- var mcu = 0, marker;
- var mcuExpected;
- if (componentsLength == 1) {
- mcuExpected = components[0].blocksPerLine * components[0].blocksPerColumn;
- } else {
- mcuExpected = mcusPerLine * frame.mcusPerColumn;
- }
- if (!resetInterval) resetInterval = mcuExpected;
-
- var h, v;
- while (mcu < mcuExpected) {
- // reset interval stuff
- for (i = 0; i < componentsLength; i++)
- components[i].pred = 0;
- eobrun = 0;
-
- if (componentsLength == 1) {
- component = components[0];
- for (n = 0; n < resetInterval; n++) {
- decodeBlock(component, decodeFn, mcu);
- mcu++;
- }
- } else {
- for (n = 0; n < resetInterval; n++) {
- for (i = 0; i < componentsLength; i++) {
- component = components[i];
- h = component.h;
- v = component.v;
- for (j = 0; j < v; j++) {
- for (k = 0; k < h; k++) {
- decodeMcu(component, decodeFn, mcu, j, k);
- }
- }
- }
- mcu++;
- }
- }
-
- // find marker
- bitsCount = 0;
- marker = (data[offset] << 8) | data[offset + 1];
- if (marker <= 0xFF00) {
- throw "marker was not found";
- }
-
- if (marker >= 0xFFD0 && marker <= 0xFFD7) { // RSTx
- offset += 2;
- }
- else
- break;
- }
-
- return offset - startOffset;
- }
-
- function buildComponentData(frame, component) {
- var lines = [];
- var blocksPerLine = component.blocksPerLine;
- var blocksPerColumn = component.blocksPerColumn;
- var samplesPerLine = blocksPerLine << 3;
- var R = new Int32Array(64), r = new Uint8Array(64);
-
- // A port of poppler's IDCT method which in turn is taken from:
- // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
- // "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
- // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
- // 988-991.
- function quantizeAndInverse(zz, dataOut, dataIn) {
- var qt = component.quantizationTable;
- var v0, v1, v2, v3, v4, v5, v6, v7, t;
- var p = dataIn;
+ MurmurHash3_64.prototype = {
+ update: function MurmurHash3_64_update(input) {
+ var useUint32ArrayView = alwaysUseUint32ArrayView;
var i;
-
- // dequant
- for (i = 0; i < 64; i++)
- p[i] = zz[i] * qt[i];
-
- // inverse DCT on rows
- for (i = 0; i < 8; ++i) {
- var row = 8 * i;
-
- // check for all-zero AC coefficients
- if (p[1 + row] == 0 && p[2 + row] == 0 && p[3 + row] == 0 &&
- p[4 + row] == 0 && p[5 + row] == 0 && p[6 + row] == 0 &&
- p[7 + row] == 0) {
- t = (dctSqrt2 * p[0 + row] + 512) >> 10;
- p[0 + row] = t;
- p[1 + row] = t;
- p[2 + row] = t;
- p[3 + row] = t;
- p[4 + row] = t;
- p[5 + row] = t;
- p[6 + row] = t;
- p[7 + row] = t;
- continue;
- }
-
- // stage 4
- v0 = (dctSqrt2 * p[0 + row] + 128) >> 8;
- v1 = (dctSqrt2 * p[4 + row] + 128) >> 8;
- v2 = p[2 + row];
- v3 = p[6 + row];
- v4 = (dctSqrt1d2 * (p[1 + row] - p[7 + row]) + 128) >> 8;
- v7 = (dctSqrt1d2 * (p[1 + row] + p[7 + row]) + 128) >> 8;
- v5 = p[3 + row] << 4;
- v6 = p[5 + row] << 4;
-
- // stage 3
- t = (v0 - v1+ 1) >> 1;
- v0 = (v0 + v1 + 1) >> 1;
- v1 = t;
- t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
- v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
- v3 = t;
- t = (v4 - v6 + 1) >> 1;
- v4 = (v4 + v6 + 1) >> 1;
- v6 = t;
- t = (v7 + v5 + 1) >> 1;
- v5 = (v7 - v5 + 1) >> 1;
- v7 = t;
-
- // stage 2
- t = (v0 - v3 + 1) >> 1;
- v0 = (v0 + v3 + 1) >> 1;
- v3 = t;
- t = (v1 - v2 + 1) >> 1;
- v1 = (v1 + v2 + 1) >> 1;
- v2 = t;
- t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
- v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
- v7 = t;
- t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
- v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
- v6 = t;
-
- // stage 1
- p[0 + row] = v0 + v7;
- p[7 + row] = v0 - v7;
- p[1 + row] = v1 + v6;
- p[6 + row] = v1 - v6;
- p[2 + row] = v2 + v5;
- p[5 + row] = v2 - v5;
- p[3 + row] = v3 + v4;
- p[4 + row] = v3 - v4;
- }
-
- // inverse DCT on columns
- for (i = 0; i < 8; ++i) {
- var col = i;
-
- // check for all-zero AC coefficients
- if (p[1*8 + col] == 0 && p[2*8 + col] == 0 && p[3*8 + col] == 0 &&
- p[4*8 + col] == 0 && p[5*8 + col] == 0 && p[6*8 + col] == 0 &&
- p[7*8 + col] == 0) {
- t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14;
- p[0*8 + col] = t;
- p[1*8 + col] = t;
- p[2*8 + col] = t;
- p[3*8 + col] = t;
- p[4*8 + col] = t;
- p[5*8 + col] = t;
- p[6*8 + col] = t;
- p[7*8 + col] = t;
- continue;
- }
-
- // stage 4
- v0 = (dctSqrt2 * p[0*8 + col] + 2048) >> 12;
- v1 = (dctSqrt2 * p[4*8 + col] + 2048) >> 12;
- v2 = p[2*8 + col];
- v3 = p[6*8 + col];
- v4 = (dctSqrt1d2 * (p[1*8 + col] - p[7*8 + col]) + 2048) >> 12;
- v7 = (dctSqrt1d2 * (p[1*8 + col] + p[7*8 + col]) + 2048) >> 12;
- v5 = p[3*8 + col];
- v6 = p[5*8 + col];
-
- // stage 3
- t = (v0 - v1 + 1) >> 1;
- v0 = (v0 + v1 + 1) >> 1;
- v1 = t;
- t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
- v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
- v3 = t;
- t = (v4 - v6 + 1) >> 1;
- v4 = (v4 + v6 + 1) >> 1;
- v6 = t;
- t = (v7 + v5 + 1) >> 1;
- v5 = (v7 - v5 + 1) >> 1;
- v7 = t;
-
- // stage 2
- t = (v0 - v3 + 1) >> 1;
- v0 = (v0 + v3 + 1) >> 1;
- v3 = t;
- t = (v1 - v2 + 1) >> 1;
- v1 = (v1 + v2 + 1) >> 1;
- v2 = t;
- t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
- v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
- v7 = t;
- t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
- v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
- v6 = t;
-
- // stage 1
- p[0*8 + col] = v0 + v7;
- p[7*8 + col] = v0 - v7;
- p[1*8 + col] = v1 + v6;
- p[6*8 + col] = v1 - v6;
- p[2*8 + col] = v2 + v5;
- p[5*8 + col] = v2 - v5;
- p[3*8 + col] = v3 + v4;
- p[4*8 + col] = v3 - v4;
- }
-
- // convert to 8-bit integers
- for (i = 0; i < 64; ++i) {
- var sample = 128 + ((p[i] + 8) >> 4);
- dataOut[i] = sample < 0 ? 0 : sample > 0xFF ? 0xFF : sample;
- }
- }
-
- var i, j;
- for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
- var scanLine = blockRow << 3;
- for (i = 0; i < 8; i++)
- lines.push(new Uint8Array(samplesPerLine));
- for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
- quantizeAndInverse(component.blocks[blockRow][blockCol], r, R);
-
- var offset = 0, sample = blockCol << 3;
- for (j = 0; j < 8; j++) {
- var line = lines[scanLine + j];
- for (i = 0; i < 8; i++)
- line[sample + i] = r[offset++];
- }
- }
- }
- return lines;
- }
-
- function clampTo8bit(a) {
- return a < 0 ? 0 : a > 255 ? 255 : a;
- }
-
- constructor.prototype = {
- load: function load(path) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", path, true);
- xhr.responseType = "arraybuffer";
- xhr.onload = (function() {
- // TODO catch parse error
- var data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer);
- this.parse(data);
- if (this.onload)
- this.onload();
- }).bind(this);
- xhr.send(null);
- },
- parse: function parse(data) {
- var offset = 0, length = data.length;
- function readUint16() {
- var value = (data[offset] << 8) | data[offset + 1];
- offset += 2;
- return value;
- }
- function readDataBlock() {
- var length = readUint16();
- var array = data.subarray(offset, offset + length - 2);
- offset += array.length;
- return array;
- }
- function prepareComponents(frame) {
- var maxH = 0, maxV = 0;
- var component, componentId;
- for (componentId in frame.components) {
- if (frame.components.hasOwnProperty(componentId)) {
- component = frame.components[componentId];
- if (maxH < component.h) maxH = component.h;
- if (maxV < component.v) maxV = component.v;
+ if (typeof input === 'string') {
+ var data = new Uint8Array(input.length * 2);
+ var length = 0;
+ for (i = 0; i < input.length; i++) {
+ var code = input.charCodeAt(i);
+ if (code <= 0xff) {
+ data[length++] = code;
+ }
+ else {
+ data[length++] = code >>> 8;
+ data[length++] = code & 0xff;
}
}
- var mcusPerLine = Math.ceil(frame.samplesPerLine / 8 / maxH);
- var mcusPerColumn = Math.ceil(frame.scanLines / 8 / maxV);
- for (componentId in frame.components) {
- if (frame.components.hasOwnProperty(componentId)) {
- component = frame.components[componentId];
- var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / maxH);
- var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines / 8) * component.v / maxV);
- var blocksPerLineForMcu = mcusPerLine * component.h;
- var blocksPerColumnForMcu = mcusPerColumn * component.v;
- var blocks = [];
- for (var i = 0; i < blocksPerColumnForMcu; i++) {
- var row = [];
- for (var j = 0; j < blocksPerLineForMcu; j++)
- row.push(new Int32Array(64));
- blocks.push(row);
- }
- component.blocksPerLine = blocksPerLine;
- component.blocksPerColumn = blocksPerColumn;
- component.blocks = blocks;
- }
+ } else if (input instanceof Uint8Array) {
+ data = input;
+ length = data.length;
+ } else if (typeof input === 'object' && ('length' in input)) {
+ // processing regular arrays as well, e.g. for IE9
+ data = input;
+ length = data.length;
+ useUint32ArrayView = true;
+ } else {
+ throw new Error('Wrong data format in MurmurHash3_64_update. ' +
+ 'Input must be a string or array.');
+ }
+
+ var blockCounts = length >> 2;
+ var tailLength = length - blockCounts * 4;
+ // we don't care about endianness here
+ var dataUint32 = useUint32ArrayView ?
+ new Uint32ArrayView(data, blockCounts) :
+ new Uint32Array(data.buffer, 0, blockCounts);
+ var k1 = 0;
+ var k2 = 0;
+ var h1 = this.h1;
+ var h2 = this.h2;
+ var C1 = 0xcc9e2d51;
+ var C2 = 0x1b873593;
+ var C1_LOW = C1 & MASK_LOW;
+ var C2_LOW = C2 & MASK_LOW;
+
+ for (i = 0; i < blockCounts; i++) {
+ if (i & 1) {
+ k1 = dataUint32[i];
+ k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
+ k1 = k1 << 15 | k1 >>> 17;
+ k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
+ h1 ^= k1;
+ h1 = h1 << 13 | h1 >>> 19;
+ h1 = h1 * 5 + 0xe6546b64;
+ } else {
+ k2 = dataUint32[i];
+ k2 = (k2 * C1 & MASK_HIGH) | (k2 * C1_LOW & MASK_LOW);
+ k2 = k2 << 15 | k2 >>> 17;
+ k2 = (k2 * C2 & MASK_HIGH) | (k2 * C2_LOW & MASK_LOW);
+ h2 ^= k2;
+ h2 = h2 << 13 | h2 >>> 19;
+ h2 = h2 * 5 + 0xe6546b64;
}
- frame.maxH = maxH;
- frame.maxV = maxV;
- frame.mcusPerLine = mcusPerLine;
- frame.mcusPerColumn = mcusPerColumn;
- }
- var jfif = null;
- var adobe = null;
- var pixels = null;
- var frame, resetInterval;
- var quantizationTables = [], frames = [];
- var huffmanTablesAC = [], huffmanTablesDC = [];
- var fileMarker = readUint16();
- if (fileMarker != 0xFFD8) { // SOI (Start of Image)
- throw "SOI not found";
}
- fileMarker = readUint16();
- while (fileMarker != 0xFFD9) { // EOI (End of image)
- var i, j, l;
- switch(fileMarker) {
- case 0xFFE0: // APP0 (Application Specific)
- case 0xFFE1: // APP1
- case 0xFFE2: // APP2
- case 0xFFE3: // APP3
- case 0xFFE4: // APP4
- case 0xFFE5: // APP5
- case 0xFFE6: // APP6
- case 0xFFE7: // APP7
- case 0xFFE8: // APP8
- case 0xFFE9: // APP9
- case 0xFFEA: // APP10
- case 0xFFEB: // APP11
- case 0xFFEC: // APP12
- case 0xFFED: // APP13
- case 0xFFEE: // APP14
- case 0xFFEF: // APP15
- case 0xFFFE: // COM (Comment)
- var appData = readDataBlock();
+ k1 = 0;
- if (fileMarker === 0xFFE0) {
- if (appData[0] === 0x4A && appData[1] === 0x46 && appData[2] === 0x49 &&
- appData[3] === 0x46 && appData[4] === 0) { // 'JFIF\x00'
- jfif = {
- version: { major: appData[5], minor: appData[6] },
- densityUnits: appData[7],
- xDensity: (appData[8] << 8) | appData[9],
- yDensity: (appData[10] << 8) | appData[11],
- thumbWidth: appData[12],
- thumbHeight: appData[13],
- thumbData: appData.subarray(14, 14 + 3 * appData[12] * appData[13])
- };
- }
- }
- // TODO APP1 - Exif
- if (fileMarker === 0xFFEE) {
- if (appData[0] === 0x41 && appData[1] === 0x64 && appData[2] === 0x6F &&
- appData[3] === 0x62 && appData[4] === 0x65 && appData[5] === 0) { // 'Adobe\x00'
- adobe = {
- version: appData[6],
- flags0: (appData[7] << 8) | appData[8],
- flags1: (appData[9] << 8) | appData[10],
- transformCode: appData[11]
- };
- }
- }
- break;
-
- case 0xFFDB: // DQT (Define Quantization Tables)
- var quantizationTablesLength = readUint16();
- var quantizationTablesEnd = quantizationTablesLength + offset - 2;
- while (offset < quantizationTablesEnd) {
- var quantizationTableSpec = data[offset++];
- var tableData = new Int32Array(64);
- if ((quantizationTableSpec >> 4) === 0) { // 8 bit values
- for (j = 0; j < 64; j++) {
- var z = dctZigZag[j];
- tableData[z] = data[offset++];
- }
- } else if ((quantizationTableSpec >> 4) === 1) { //16 bit
- for (j = 0; j < 64; j++) {
- var z = dctZigZag[j];
- tableData[z] = readUint16();
- }
- } else
- throw "DQT: invalid table spec";
- quantizationTables[quantizationTableSpec & 15] = tableData;
- }
- break;
-
- case 0xFFC0: // SOF0 (Start of Frame, Baseline DCT)
- case 0xFFC1: // SOF1 (Start of Frame, Extended DCT)
- case 0xFFC2: // SOF2 (Start of Frame, Progressive DCT)
- readUint16(); // skip data length
- frame = {};
- frame.extended = (fileMarker === 0xFFC1);
- frame.progressive = (fileMarker === 0xFFC2);
- frame.precision = data[offset++];
- frame.scanLines = readUint16();
- frame.samplesPerLine = readUint16();
- frame.components = {};
- frame.componentsOrder = [];
- var componentsCount = data[offset++], componentId;
- var maxH = 0, maxV = 0;
- for (i = 0; i < componentsCount; i++) {
- componentId = data[offset];
- var h = data[offset + 1] >> 4;
- var v = data[offset + 1] & 15;
- var qId = data[offset + 2];
- frame.componentsOrder.push(componentId);
- frame.components[componentId] = {
- h: h,
- v: v,
- quantizationTable: quantizationTables[qId]
- };
- offset += 3;
- }
- prepareComponents(frame);
- frames.push(frame);
- break;
-
- case 0xFFC4: // DHT (Define Huffman Tables)
- var huffmanLength = readUint16();
- for (i = 2; i < huffmanLength;) {
- var huffmanTableSpec = data[offset++];
- var codeLengths = new Uint8Array(16);
- var codeLengthSum = 0;
- for (j = 0; j < 16; j++, offset++)
- codeLengthSum += (codeLengths[j] = data[offset]);
- var huffmanValues = new Uint8Array(codeLengthSum);
- for (j = 0; j < codeLengthSum; j++, offset++)
- huffmanValues[j] = data[offset];
- i += 17 + codeLengthSum;
-
- ((huffmanTableSpec >> 4) === 0 ?
- huffmanTablesDC : huffmanTablesAC)[huffmanTableSpec & 15] =
- buildHuffmanTable(codeLengths, huffmanValues);
- }
- break;
-
- case 0xFFDD: // DRI (Define Restart Interval)
- readUint16(); // skip data length
- resetInterval = readUint16();
- break;
-
- case 0xFFDA: // SOS (Start of Scan)
- var scanLength = readUint16();
- var selectorsCount = data[offset++];
- var components = [], component;
- for (i = 0; i < selectorsCount; i++) {
- component = frame.components[data[offset++]];
- var tableSpec = data[offset++];
- component.huffmanTableDC = huffmanTablesDC[tableSpec >> 4];
- component.huffmanTableAC = huffmanTablesAC[tableSpec & 15];
- components.push(component);
- }
- var spectralStart = data[offset++];
- var spectralEnd = data[offset++];
- var successiveApproximation = data[offset++];
- var processed = decodeScan(data, offset,
- frame, components, resetInterval,
- spectralStart, spectralEnd,
- successiveApproximation >> 4, successiveApproximation & 15);
- offset += processed;
- break;
- default:
- if (data[offset - 3] == 0xFF &&
- data[offset - 2] >= 0xC0 && data[offset - 2] <= 0xFE) {
- // could be incorrect encoding -- last 0xFF byte of the previous
- // block was eaten by the encoder
- offset -= 3;
- break;
- }
- throw "unknown JPEG marker " + fileMarker.toString(16);
- }
- fileMarker = readUint16();
- }
- if (frames.length != 1)
- throw "only single frame JPEGs supported";
-
- this.width = frame.samplesPerLine;
- this.height = frame.scanLines;
- this.jfif = jfif;
- this.adobe = adobe;
- this.components = [];
- for (var i = 0; i < frame.componentsOrder.length; i++) {
- var component = frame.components[frame.componentsOrder[i]];
- this.components.push({
- lines: buildComponentData(frame, component),
- scaleX: component.h / frame.maxH,
- scaleY: component.v / frame.maxV
- });
- }
- },
- getData: function getData(width, height) {
- var scaleX = this.width / width, scaleY = this.height / height;
-
- var component1, component2, component3, component4;
- var component1Line, component2Line, component3Line, component4Line;
- var x, y;
- var offset = 0;
- var Y, Cb, Cr, K, C, M, Ye, R, G, B;
- var colorTransform;
- var dataLength = width * height * this.components.length;
- var data = new Uint8Array(dataLength);
- switch (this.components.length) {
- case 1:
- component1 = this.components[0];
- for (y = 0; y < height; y++) {
- component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
- for (x = 0; x < width; x++) {
- Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-
- data[offset++] = Y;
- }
- }
- break;
+ switch (tailLength) {
+ case 3:
+ k1 ^= data[blockCounts * 4 + 2] << 16;
+ /* falls through */
case 2:
- // PDF might compress two component data in custom colorspace
- component1 = this.components[0];
- component2 = this.components[1];
- for (y = 0; y < height; y++) {
- component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
- component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
- for (x = 0; x < width; x++) {
- Y = component1Line[0 | (x * component1.scaleX * scaleX)];
- data[offset++] = Y;
- Y = component2Line[0 | (x * component2.scaleX * scaleX)];
- data[offset++] = Y;
- }
- }
- break;
- case 3:
- // The default transform for three components is true
- colorTransform = true;
- // The adobe transform marker overrides any previous setting
- if (this.adobe && this.adobe.transformCode)
- colorTransform = true;
- else if (typeof this.colorTransform !== 'undefined')
- colorTransform = !!this.colorTransform;
-
- component1 = this.components[0];
- component2 = this.components[1];
- component3 = this.components[2];
- for (y = 0; y < height; y++) {
- component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
- component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
- component3Line = component3.lines[0 | (y * component3.scaleY * scaleY)];
- for (x = 0; x < width; x++) {
- if (!colorTransform) {
- R = component1Line[0 | (x * component1.scaleX * scaleX)];
- G = component2Line[0 | (x * component2.scaleX * scaleX)];
- B = component3Line[0 | (x * component3.scaleX * scaleX)];
- } else {
- Y = component1Line[0 | (x * component1.scaleX * scaleX)];
- Cb = component2Line[0 | (x * component2.scaleX * scaleX)];
- Cr = component3Line[0 | (x * component3.scaleX * scaleX)];
-
- R = clampTo8bit(Y + 1.402 * (Cr - 128));
- G = clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
- B = clampTo8bit(Y + 1.772 * (Cb - 128));
- }
-
- data[offset++] = R;
- data[offset++] = G;
- data[offset++] = B;
- }
- }
- break;
- case 4:
- // The default transform for four components is false
- colorTransform = false;
- // The adobe transform marker overrides any previous setting
- if (this.adobe && this.adobe.transformCode)
- colorTransform = true;
- else if (typeof this.colorTransform !== 'undefined')
- colorTransform = !!this.colorTransform;
-
- component1 = this.components[0];
- component2 = this.components[1];
- component3 = this.components[2];
- component4 = this.components[3];
- for (y = 0; y < height; y++) {
- component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
- component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
- component3Line = component3.lines[0 | (y * component3.scaleY * scaleY)];
- component4Line = component4.lines[0 | (y * component4.scaleY * scaleY)];
- for (x = 0; x < width; x++) {
- if (!colorTransform) {
- C = component1Line[0 | (x * component1.scaleX * scaleX)];
- M = component2Line[0 | (x * component2.scaleX * scaleX)];
- Ye = component3Line[0 | (x * component3.scaleX * scaleX)];
- K = component4Line[0 | (x * component4.scaleX * scaleX)];
- } else {
- Y = component1Line[0 | (x * component1.scaleX * scaleX)];
- Cb = component2Line[0 | (x * component2.scaleX * scaleX)];
- Cr = component3Line[0 | (x * component3.scaleX * scaleX)];
- K = component4Line[0 | (x * component4.scaleX * scaleX)];
-
- C = 255 - clampTo8bit(Y + 1.402 * (Cr - 128));
- M = 255 - clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
- Ye = 255 - clampTo8bit(Y + 1.772 * (Cb - 128));
- }
- data[offset++] = C;
- data[offset++] = M;
- data[offset++] = Ye;
- data[offset++] = K;
- }
- }
- break;
- default:
- throw 'Unsupported color mode';
- }
- return data;
- },
- copyToImageData: function copyToImageData(imageData) {
- var width = imageData.width, height = imageData.height;
- var imageDataArray = imageData.data;
- var data = this.getData(width, height);
- var i = 0, j = 0, x, y;
- var Y, K, C, M, R, G, B;
- switch (this.components.length) {
+ k1 ^= data[blockCounts * 4 + 1] << 8;
+ /* falls through */
case 1:
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- Y = data[i++];
-
- imageDataArray[j++] = Y;
- imageDataArray[j++] = Y;
- imageDataArray[j++] = Y;
- imageDataArray[j++] = 255;
- }
- }
- break;
- case 3:
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- R = data[i++];
- G = data[i++];
- B = data[i++];
-
- imageDataArray[j++] = R;
- imageDataArray[j++] = G;
- imageDataArray[j++] = B;
- imageDataArray[j++] = 255;
- }
- }
- break;
- case 4:
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- C = data[i++];
- M = data[i++];
- Y = data[i++];
- K = data[i++];
-
- R = 255 - clampTo8bit(C * (1 - K / 255) + K);
- G = 255 - clampTo8bit(M * (1 - K / 255) + K);
- B = 255 - clampTo8bit(Y * (1 - K / 255) + K);
-
- imageDataArray[j++] = R;
- imageDataArray[j++] = G;
- imageDataArray[j++] = B;
- imageDataArray[j++] = 255;
- }
- }
- break;
- default:
- throw 'Unsupported color mode';
+ k1 ^= data[blockCounts * 4];
+ /* falls through */
+ k1 = (k1 * C1 & MASK_HIGH) | (k1 * C1_LOW & MASK_LOW);
+ k1 = k1 << 15 | k1 >>> 17;
+ k1 = (k1 * C2 & MASK_HIGH) | (k1 * C2_LOW & MASK_LOW);
+ if (blockCounts & 1) {
+ h1 ^= k1;
+ } else {
+ h2 ^= k1;
+ }
}
+
+ this.h1 = h1;
+ this.h2 = h2;
+ return this;
+ },
+
+ hexdigest: function MurmurHash3_64_hexdigest () {
+ var h1 = this.h1;
+ var h2 = this.h2;
+
+ h1 ^= h2 >>> 1;
+ h1 = (h1 * 0xed558ccd & MASK_HIGH) | (h1 * 0x8ccd & MASK_LOW);
+ h2 = (h2 * 0xff51afd7 & MASK_HIGH) |
+ (((h2 << 16 | h1 >>> 16) * 0xafd7ed55 & MASK_HIGH) >>> 16);
+ h1 ^= h2 >>> 1;
+ h1 = (h1 * 0x1a85ec53 & MASK_HIGH) | (h1 * 0xec53 & MASK_LOW);
+ h2 = (h2 * 0xc4ceb9fe & MASK_HIGH) |
+ (((h2 << 16 | h1 >>> 16) * 0xb9fe1a85 & MASK_HIGH) >>> 16);
+ h1 ^= h2 >>> 1;
+
+ for (var i = 0, arr = [h1, h2], str = ''; i < arr.length; i++) {
+ var hex = (arr[i] >>> 0).toString(16);
+ while (hex.length < 8) {
+ hex = '0' + hex;
+ }
+ str += hex;
+ }
+
+ return str;
}
};
- return constructor;
+ return MurmurHash3_64;
})();
diff --git a/static/pdf.js/viewer.css b/static/pdf.js/viewer.css
index 24d4d4cd0..e54f6b1dc 100644
--- a/static/pdf.js/viewer.css
+++ b/static/pdf.js/viewer.css
@@ -1,4 +1,4 @@
-/* Copyright 2012 Mozilla Foundation
+/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,6 +13,159 @@
* limitations under the License.
*/
+.textLayer {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+}
+
+.textLayer > div {
+ color: transparent;
+ position: absolute;
+ white-space: pre;
+ cursor: text;
+ -webkit-transform-origin: 0% 0%;
+ -moz-transform-origin: 0% 0%;
+ -o-transform-origin: 0% 0%;
+ -ms-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+}
+
+.textLayer .highlight {
+ margin: -1px;
+ padding: 1px;
+
+ background-color: rgb(180, 0, 170);
+ border-radius: 4px;
+}
+
+.textLayer .highlight.begin {
+ border-radius: 4px 0px 0px 4px;
+}
+
+.textLayer .highlight.end {
+ border-radius: 0px 4px 4px 0px;
+}
+
+.textLayer .highlight.middle {
+ border-radius: 0px;
+}
+
+.textLayer .highlight.selected {
+ background-color: rgb(0, 100, 0);
+}
+
+.pdfViewer .canvasWrapper {
+ overflow: hidden;
+}
+
+.pdfViewer .page {
+ direction: ltr;
+ width: 816px;
+ height: 1056px;
+ margin: 1px auto -8px auto;
+ position: relative;
+ overflow: visible;
+ border: 9px solid transparent;
+ background-clip: content-box;
+ border-image: url(images/shadow.png) 9 9 repeat;
+ background-color: white;
+}
+
+.pdfViewer .page canvas {
+ margin: 0;
+ display: block;
+}
+
+.pdfViewer .page .loadingIcon {
+ position: absolute;
+ display: block;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ background: url('images/loading-icon.gif') center no-repeat;
+}
+
+.pdfViewer .page .annotLink > a:hover {
+ opacity: 0.2;
+ background: #ff0;
+ box-shadow: 0px 2px 10px #ff0;
+}
+
+:-webkit-full-screen .pdfViewer .page {
+ margin-bottom: 100%;
+ border: 0;
+}
+
+:-moz-full-screen .pdfViewer .page {
+ margin-bottom: 100%;
+ border: 0;
+}
+
+:-ms-fullscreen .pdfViewer .page {
+ margin-bottom: 100% !important;
+ border: 0;
+}
+
+:fullscreen .pdfViewer .page {
+ margin-bottom: 100%;
+ border: 0;
+}
+
+.pdfViewer .page .annotationHighlight {
+ position: absolute;
+ border: 2px #FFFF99 solid;
+}
+
+.pdfViewer .page .annotText > img {
+ position: absolute;
+ cursor: pointer;
+}
+
+.pdfViewer .page .annotTextContentWrapper {
+ position: absolute;
+ width: 20em;
+}
+
+.pdfViewer .page .annotTextContent {
+ z-index: 200;
+ float: left;
+ max-width: 20em;
+ background-color: #FFFF99;
+ box-shadow: 0px 2px 5px #333;
+ border-radius: 2px;
+ padding: 0.6em;
+ cursor: pointer;
+}
+
+.pdfViewer .page .annotTextContent > h1 {
+ font-size: 1em;
+ border-bottom: 1px solid #000000;
+ padding-bottom: 0.2em;
+}
+
+.pdfViewer .page .annotTextContent > p {
+ padding-top: 0.2em;
+}
+
+.pdfViewer .page .annotLink > a {
+ position: absolute;
+ font-size: 1em;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.pdfViewer .page .annotLink > a /* -ms-a */ {
+ background: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAA\
+ LAAAAAABAAEAAAIBRAA7") 0 0 repeat;
+}
+
* {
padding: 0;
margin: 0;
@@ -35,6 +188,7 @@ input,
button,
select {
font: message-box;
+ outline: none;
}
.hidden {
@@ -47,8 +201,7 @@ select {
#viewerContainer:-webkit-full-screen {
top: 0px;
border-top: 2px solid transparent;
- background-color: #404040;
- background-image: url(images/texture.png);
+ background-color: #000;
width: 100%;
height: 100%;
overflow: hidden;
@@ -58,8 +211,7 @@ select {
#viewerContainer:-moz-full-screen {
top: 0px;
border-top: 2px solid transparent;
- background-color: #404040;
- background-image: url(images/texture.png);
+ background-color: #000;
width: 100%;
height: 100%;
overflow: hidden;
@@ -76,37 +228,19 @@ select {
}
#viewerContainer:-ms-fullscreen::-ms-backdrop {
- background-color: #404040;
- background-image: url(images/texture.png);
+ background-color: #000;
}
#viewerContainer:fullscreen {
top: 0px;
border-top: 2px solid transparent;
- background-color: #404040;
- background-image: url(images/texture.png);
+ background-color: #000;
width: 100%;
height: 100%;
overflow: hidden;
cursor: none;
}
-:-webkit-full-screen .page {
- margin-bottom: 100%;
-}
-
-:-moz-full-screen .page {
- margin-bottom: 100%;
-}
-
-:-ms-fullscreen .page {
- margin-bottom: 100% !important;
-}
-
-:fullscreen .page {
- margin-bottom: 100%;
-}
-
:-webkit-full-screen a:not(.internalLink) {
display: none;
}
@@ -140,6 +274,21 @@ select {
cursor: default;
}
+.imageLayer {
+ position: absolute;
+ left: 0;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ color: #000;
+ font-family: sans-serif;
+ pointer-events: none;
+}
+
+.imageLayer > div {
+ pointer-events: all;
+}
+
/* outer/inner center provides horizontal center */
.outerCenter {
pointer-events: none;
@@ -233,22 +382,23 @@ html[dir='rtl'] #outerContainer.sidebarOpen > #mainContainer {
top: 32px;
bottom: 0;
overflow: auto;
+ -webkit-overflow-scrolling: touch;
position: absolute;
width: 200px;
-
background-color: hsla(0,0%,0%,.1);
- box-shadow: inset -1px 0 0 hsla(0,0%,0%,.25);
}
html[dir='ltr'] #sidebarContent {
left: 0;
+ box-shadow: inset -1px 0 0 hsla(0,0%,0%,.25);
}
html[dir='rtl'] #sidebarContent {
right: 0;
+ box-shadow: inset 1px 0 0 hsla(0,0%,0%,.25);
}
#viewerContainer {
overflow: auto;
- box-shadow: inset 1px 0 0 hsla(0,0%,100%,.05);
+ -webkit-overflow-scrolling: touch;
position: absolute;
top: 32px;
right: 0;
@@ -256,6 +406,12 @@ html[dir='rtl'] #sidebarContent {
left: 0;
outline: none;
}
+html[dir='ltr'] #viewerContainer {
+ box-shadow: inset 1px 0 0 hsla(0,0%,100%,.05);
+}
+html[dir='rtl'] #viewerContainer {
+ box-shadow: inset -1px 0 0 hsla(0,0%,100%,.05);
+}
.toolbar {
position: relative;
@@ -275,12 +431,19 @@ html[dir='rtl'] #sidebarContent {
background-color: #424242; /* fallback */
background-image: url(images/texture.png),
linear-gradient(hsla(0,0%,30%,.99), hsla(0,0%,25%,.95));
+}
+html[dir='ltr'] #toolbarSidebar {
box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.25),
-
inset 0 -1px 0 hsla(0,0%,100%,.05),
0 1px 0 hsla(0,0%,0%,.15),
0 0 1px hsla(0,0%,0%,.1);
}
+html[dir='rtl'] #toolbarSidebar {
+ box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.25),
+ inset 0 1px 0 hsla(0,0%,100%,.05),
+ 0 1px 0 hsla(0,0%,0%,.15),
+ 0 0 1px hsla(0,0%,0%,.1);
+}
#toolbarContainer, .findbar, .secondaryToolbar {
position: relative;
@@ -288,12 +451,21 @@ html[dir='rtl'] #sidebarContent {
background-color: #474747; /* fallback */
background-image: url(images/texture.png),
linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
+}
+html[dir='ltr'] #toolbarContainer, .findbar, .secondaryToolbar {
box-shadow: inset 1px 0 0 hsla(0,0%,100%,.08),
inset 0 1px 1px hsla(0,0%,0%,.15),
inset 0 -1px 0 hsla(0,0%,100%,.05),
0 1px 0 hsla(0,0%,0%,.15),
0 1px 1px hsla(0,0%,0%,.1);
}
+html[dir='rtl'] #toolbarContainer, .findbar, .secondaryToolbar {
+ box-shadow: inset -1px 0 0 hsla(0,0%,100%,.08),
+ inset 0 1px 1px hsla(0,0%,0%,.15),
+ inset 0 -1px 0 hsla(0,0%,100%,.05),
+ 0 1px 0 hsla(0,0%,0%,.15),
+ 0 1px 1px hsla(0,0%,0%,.1);
+}
#toolbarViewer {
height: 32px;
@@ -302,7 +474,7 @@ html[dir='rtl'] #sidebarContent {
#loadingBar {
position: relative;
width: 100%;
- height: 6px;
+ height: 4px;
background-color: #333;
border-bottom: 1px solid #333;
}
@@ -386,6 +558,9 @@ html[dir='rtl'] .findbar {
background-repeat: no-repeat;
background-position: right;
}
+html[dir='rtl'] #findInput[data-status="pending"] {
+ background-position: left;
+}
.secondaryToolbar {
padding: 6px;
@@ -403,6 +578,7 @@ html[dir='rtl'] .secondaryToolbar {
max-width: 200px;
max-height: 400px;
overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
margin-bottom: -4px;
}
@@ -518,9 +694,10 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
}
.toolbarButton,
-.secondaryToolbarButton {
+.secondaryToolbarButton,
+.overlayButton {
border: 0 none;
- background-color: rgba(0, 0, 0, 0);
+ background: none;
width: 32px;
height: 25px;
}
@@ -533,7 +710,8 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
}
.toolbarButton[disabled],
-.secondaryToolbarButton[disabled] {
+.secondaryToolbarButton[disabled],
+.overlayButton[disabled] {
opacity: .5;
}
@@ -568,7 +746,7 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
.splitToolbarButton > .toolbarButton:hover,
.splitToolbarButton > .toolbarButton:focus,
.dropdownToolbarButton:hover,
-.promptButton:hover,
+.overlayButton:hover,
.toolbarButton.textButton:hover,
.toolbarButton.textButton:focus {
background-color: hsla(0,0%,0%,.2);
@@ -577,6 +755,9 @@ html[dir='rtl'] .splitToolbarButton > .toolbarButton {
0 0 1px hsla(0,0%,0%,.05);
z-index: 199;
}
+.splitToolbarButton > .toolbarButton {
+ position: relative;
+}
html[dir='ltr'] .splitToolbarButton > .toolbarButton:first-child,
html[dir='rtl'] .splitToolbarButton > .toolbarButton:last-child {
position: relative;
@@ -625,8 +806,8 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
.toolbarButton,
.dropdownToolbarButton,
-.promptButton,
-.secondaryToolbarButton {
+.secondaryToolbarButton,
+.overlayButton {
min-width: 16px;
padding: 2px 6px 0;
border: 1px solid transparent;
@@ -648,12 +829,12 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
}
html[dir='ltr'] .toolbarButton,
-html[dir='ltr'] .promptButton,
+html[dir='ltr'] .overlayButton,
html[dir='ltr'] .dropdownToolbarButton {
margin: 3px 2px 4px 0;
}
html[dir='rtl'] .toolbarButton,
-html[dir='rtl'] .promptButton,
+html[dir='rtl'] .overlayButton,
html[dir='rtl'] .dropdownToolbarButton {
margin: 3px 0 4px 2px;
}
@@ -661,7 +842,7 @@ html[dir='rtl'] .dropdownToolbarButton {
.toolbarButton:hover,
.toolbarButton:focus,
.dropdownToolbarButton,
-.promptButton,
+.overlayButton,
.secondaryToolbarButton:hover,
.secondaryToolbarButton:focus {
background-color: hsla(0,0%,0%,.12);
@@ -675,7 +856,7 @@ html[dir='rtl'] .dropdownToolbarButton {
}
.toolbarButton:hover:active,
-.promptButton:hover:active,
+.overlayButton:hover:active,
.dropdownToolbarButton:hover:active,
.secondaryToolbarButton:hover:active {
background-color: hsla(0,0%,0%,.2);
@@ -749,12 +930,6 @@ html[dir='rtl'] .dropdownToolbarButton {
background: hsl(0,0%,24%);
}
-.promptButton {
- margin: 3px 2px 4px 5px !important;
- line-height: 16px;
- padding: 2px 6px 3px 6px;
-}
-
#customScaleOption {
display: none;
}
@@ -805,7 +980,6 @@ html[dir='rtl'] #findNext {
.toolbarButton::before,
.secondaryToolbarButton::before {
/* All matching images have a size of 16x16
- * (except for the print button: 18x16)
* All relevant containers have a size of 32x25 */
position: absolute;
display: inline-block;
@@ -878,14 +1052,6 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
.toolbarButton.print::before,
.secondaryToolbarButton.print::before {
content: url(images/toolbarButton-print.png);
- left: 6px;
-}
-
-html[dir="ltr"] .secondaryToolbarButton.print::before {
- left: 3px;
-}
-html[dir="rtl"] .secondaryToolbarButton.print::before {
- right: 3px;
}
.toolbarButton.openFile::before,
@@ -903,6 +1069,7 @@ html[dir="rtl"] .secondaryToolbarButton.print::before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
+ outline: none;
padding-top: 4px;
text-decoration: none;
}
@@ -931,6 +1098,10 @@ html[dir="rtl"] #viewOutline.toolbarButton::before {
content: url(images/toolbarButton-viewOutline-rtl.png);
}
+#viewAttachments.toolbarButton::before {
+ content: url(images/toolbarButton-viewAttachments.png);
+}
+
#viewFind.toolbarButton::before {
content: url(images/toolbarButton-search.png);
}
@@ -987,6 +1158,10 @@ html[dir="rtl"] .secondaryToolbarButton > span {
content: url(images/secondaryToolbarButton-handTool.png);
}
+.secondaryToolbarButton.documentProperties::before {
+ content: url(images/secondaryToolbarButton-documentProperties.png);
+}
+
.verticalToolbarSeparator {
display: block;
padding: 8px 0;
@@ -1003,7 +1178,7 @@ html[dir='rtl'] .verticalToolbarSeparator {
}
.horizontalToolbarSeparator {
- display: block;
+ display: block;
margin: 0 0 4px 0;
height: 1px;
width: 100%;
@@ -1044,6 +1219,12 @@ html[dir='rtl'] .verticalToolbarSeparator {
width: 40px;
}
+.toolbarField.pageNumber.visiblePageIsLoading {
+ background-image: url(images/loading-small.png);
+ background-repeat: no-repeat;
+ background-position: 1px;
+}
+
.toolbarField.pageNumber::-webkit-inner-spin-button,
.toolbarField.pageNumber::-webkit-outer-spin-button {
-webkit-appearance: none;
@@ -1082,6 +1263,7 @@ html[dir='rtl'] .verticalToolbarSeparator {
bottom: 0;
padding: 10px 40px 0;
overflow: auto;
+ -webkit-overflow-scrolling: touch;
}
.thumbnail {
@@ -1143,17 +1325,25 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
color: hsla(0,0%,100%,1);
}
-#outlineView {
+#outlineView,
+#attachmentsView {
position: absolute;
width: 192px;
top: 0;
bottom: 0;
- padding: 4px 4px 0;
overflow: auto;
+ -webkit-overflow-scrolling: touch;
-webkit-user-select: none;
-moz-user-select: none;
}
+#outlineView {
+ padding: 4px 4px 0;
+}
+#attachmentsView {
+ padding: 3px 4px 0;
+}
+
html[dir='ltr'] .outlineItem > .outlineItems {
margin-left: 20px;
}
@@ -1162,7 +1352,8 @@ html[dir='rtl'] .outlineItem > .outlineItems {
margin-right: 20px;
}
-.outlineItem > a {
+.outlineItem > a,
+.attachmentsItem > button {
text-decoration: none;
display: inline-block;
min-width: 95%;
@@ -1176,15 +1367,31 @@ html[dir='rtl'] .outlineItem > .outlineItems {
white-space: normal;
}
+.attachmentsItem > button {
+ border: 0 none;
+ background: none;
+ cursor: pointer;
+ width: 100%;
+}
+
html[dir='ltr'] .outlineItem > a {
padding: 2px 0 5px 10px;
}
+html[dir='ltr'] .attachmentsItem > button {
+ padding: 2px 0 3px 7px;
+ text-align: left;
+}
html[dir='rtl'] .outlineItem > a {
padding: 2px 10px 5px 0;
}
+html[dir='rtl'] .attachmentsItem > button {
+ padding: 2px 7px 3px 0;
+ text-align: right;
+}
-.outlineItem > a:hover {
+.outlineItem > a:hover,
+.attachmentsItem > button:hover {
background-color: hsla(0,0%,100%,.02);
background-image: linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
background-clip: padding-box;
@@ -1211,152 +1418,17 @@ html[dir='rtl'] .outlineItem > a {
cursor: default;
}
-#findScrollView {
- position: absolute;
- top: 10px;
- bottom: 10px;
- left: 10px;
- width: 280px;
-}
-
-#sidebarControls {
- position:absolute;
- width: 180px;
- height: 32px;
- left: 15px;
- bottom: 35px;
-}
-
-.canvasWrapper {
- overflow: hidden;
-}
-
-canvas {
- margin: 0;
- display: block;
-}
-
-.page {
- direction: ltr;
- width: 816px;
- height: 1056px;
- margin: 1px auto -8px auto;
- position: relative;
- overflow: visible;
- border: 9px solid transparent;
- background-clip: content-box;
- border-image: url(images/shadow.png) 9 9 repeat;
- background-color: white;
-}
-
-.page > a,
-.annotationLayer > a {
- display: block;
- position: absolute;
-}
-
-.page > a:hover,
-.annotationLayer > a:hover {
- opacity: 0.2;
- background: #ff0;
- box-shadow: 0px 2px 10px #ff0;
-}
-
-.loadingIcon {
- position: absolute;
- display: block;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- background: url('images/loading-icon.gif') center no-repeat;
-}
-
-.textLayer {
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- color: #000;
- font-family: sans-serif;
- overflow: hidden;
-}
-.imageLayer {
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- color: #000;
- font-family: sans-serif;
- pointer-events: none;
-}
-
-.imageLayer > div {
- pointer-events: all;
-}
-.textLayer > div {
- color: transparent;
- position: absolute;
- line-height: 1;
- white-space: pre;
- cursor: text;
-}
-
-.textLayer .highlight {
- margin: -1px;
- padding: 1px;
-
- background-color: rgba(180, 0, 170, 0.2);
- border-radius: 4px;
-}
-
-.textLayer .highlight.begin {
- border-radius: 4px 0px 0px 4px;
-}
-
-.textLayer .highlight.end {
- border-radius: 0px 4px 4px 0px;
-}
-
-.textLayer .highlight.middle {
- border-radius: 0px;
-}
-
-.textLayer .highlight.selected {
- background-color: rgba(0, 100, 0, 0.2);
-}
/* TODO: file FF bug to support ::-moz-selection:window-inactive
so we can override the opaque grey background when the window is inactive;
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
-::selection { background:rgba(0,0,255,0.3); }
-::-moz-selection { background:rgba(0,0,255,0.3); }
+::selection { background: rgba(0,0,255,0.3); }
+::-moz-selection { background: rgba(0,0,255,0.3); }
-.annotText > div {
- z-index: 200;
- position: absolute;
- padding: 0.6em;
- max-width: 20em;
- background-color: #FFFF99;
- box-shadow: 0px 2px 10px #333;
- border-radius: 7px;
-}
-
-.annotText > img {
- position: absolute;
- opacity: 0.6;
-}
-
-.annotText > img:hover {
- opacity: 1;
-}
-
-.annotText > div > h1 {
- font-size: 1.2em;
- border-bottom: 1px solid #000000;
- margin: 0px;
+.textLayer ::selection { background: rgb(0,0,255); }
+.textLayer ::-moz-selection { background: rgb(0,0,255); }
+.textLayer {
+ opacity: 0.2;
}
#errorWrapper {
@@ -1370,7 +1442,7 @@ canvas {
font-size: 0.8em;
}
.loadingInProgress #errorWrapper {
- top: 39px;
+ top: 37px;
}
#errorMessageLeft {
@@ -1389,32 +1461,38 @@ canvas {
width: 98%;
}
+.overlayButton {
+ width: auto;
+ margin: 3px 4px 2px 4px !important;
+ padding: 2px 6px 3px 6px;
+}
+
#overlayContainer {
display: table;
position: absolute;
width: 100%;
height: 100%;
background-color: hsla(0,0%,0%,.2);
- z-index: 10000;
+ z-index: 40000;
+}
+#overlayContainer > * {
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
}
-#promptContainer {
+#overlayContainer > .container {
display: table-cell;
vertical-align: middle;
text-align: center;
}
-#promptContainer > * {
+#overlayContainer > .container > .dialog {
display: inline-block;
-}
-
-.prompt {
- display: table;
padding: 15px;
border-spacing: 4px;
color: hsl(0,0%,85%);
+ font-size: 12px;
line-height: 14px;
- text-align: center;
background-color: #474747; /* fallback */
background-image: url(images/texture.png),
linear-gradient(hsla(0,0%,32%,.99), hsla(0,0%,27%,.95));
@@ -1423,24 +1501,70 @@ canvas {
inset 0 -1px 0 hsla(0,0%,100%,.05),
0 1px 0 hsla(0,0%,0%,.15),
0 1px 1px hsla(0,0%,0%,.1);
+ border: 1px solid hsla(0,0%,0%,.5);
+ border-radius: 4px;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}
-.prompt > .row {
+.dialog > .row {
display: table-row;
}
-.prompt > .row > * {
+.dialog > .row > * {
display: table-cell;
}
-.prompt .toolbarField {
+.dialog .toolbarField {
margin: 5px 0;
+}
+.dialog .toolbarField:hover,
+.dialog .toolbarField:focus {
+ border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
+}
+
+.dialog .separator {
+ display: block;
+ margin: 4px 0 4px 0;
+ height: 1px;
+ width: 100%;
+ background-color: hsla(0,0%,0%,.5);
+ box-shadow: 0 0 0 1px hsla(0,0%,100%,.08);
+}
+
+.dialog .buttonRow {
+ text-align: center;
+ vertical-align: middle;
+}
+
+#passwordOverlay > .dialog {
+ text-align: center;
+}
+#passwordOverlay .toolbarField {
width: 200px;
}
-.prompt .toolbarField:hover,
-.prompt .toolbarField:focus {
- border-color: hsla(0,0%,0%,.32) hsla(0,0%,0%,.38) hsla(0,0%,0%,.42);
+#documentPropertiesOverlay > .dialog {
+ text-align: left;
+}
+#documentPropertiesOverlay .row > * {
+ min-width: 100px;
+}
+html[dir='ltr'] #documentPropertiesOverlay .row > * {
+ text-align: left;
+}
+html[dir='rtl'] #documentPropertiesOverlay .row > * {
+ text-align: right;
+}
+#documentPropertiesOverlay .row > span {
+ width: 125px;
+ word-wrap: break-word;
+}
+#documentPropertiesOverlay .row > p {
+ max-width: 225px;
+ word-wrap: break-word;
+}
+#documentPropertiesOverlay .buttonRow {
+ margin-top: 10px;
}
.clearBoth {
@@ -1451,6 +1575,10 @@ canvas {
background: white;
color: black;
margin-top: 5px;
+ visibility: hidden;
+ position: fixed;
+ right: 0;
+ top: 0;
}
#PDFBug {
@@ -1473,6 +1601,7 @@ canvas {
bottom: 0;
left: 0;
overflow: auto;
+ -webkit-overflow-scrolling: touch;
position: absolute;
right: 0;
top: 27px;
@@ -1483,11 +1612,9 @@ canvas {
.debuggerShowText {
background: none repeat scroll 0 0 yellow;
color: blue;
- opacity: 0.3;
}
.debuggerHideText:hover {
background: none repeat scroll 0 0 yellow;
- opacity: 0.3;
}
#PDFBug .stats {
font-family: courier;
@@ -1512,30 +1639,31 @@ canvas {
color: black;
}
-.grab-to-pan-grab * {
+.grab-to-pan-grab {
cursor: url("images/grab.cur"), move !important;
cursor: -webkit-grab !important;
cursor: -moz-grab !important;
cursor: grab !important;
}
-.grab-to-pan-grabbing,
-.grab-to-pan-grabbing * {
+.grab-to-pan-grab *:not(input):not(textarea):not(button):not(select):not(:link) {
+ cursor: inherit !important;
+}
+.grab-to-pan-grab:active,
+.grab-to-pan-grabbing {
cursor: url("images/grabbing.cur"), move !important;
cursor: -webkit-grabbing !important;
cursor: -moz-grabbing !important;
cursor: grabbing !important;
-}
-.grab-to-pan-grab input,
-.grab-to-pan-grab textarea,
-.grab-to-pan-grab button,
-.grab-to-pan-grab button *,
-.grab-to-pan-grab select,
-.grab-to-pan-grab option {
- cursor: auto !important;
-}
-.grab-to-pan-grab a[href],
-.grab-to-pan-grab a[href] * {
- cursor: pointer !important;
+
+ position: fixed;
+ background: transparent;
+ display: block;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ overflow: hidden;
+ z-index: 50000; /* should be higher than anything else in PDF.js! */
}
@page {
@@ -1546,6 +1674,162 @@ canvas {
display: none;
}
+@media screen and (min-resolution: 2dppx) {
+ /* Rules for Retina screens */
+ .toolbarButton::before {
+ -webkit-transform: scale(0.5);
+ transform: scale(0.5);
+ top: -5px;
+ }
+
+ .secondaryToolbarButton::before {
+ -webkit-transform: scale(0.5);
+ transform: scale(0.5);
+ top: -4px;
+ }
+
+ html[dir='ltr'] .toolbarButton::before,
+ html[dir='rtl'] .toolbarButton::before {
+ left: -1px;
+ }
+
+ html[dir='ltr'] .secondaryToolbarButton::before {
+ left: -2px;
+ }
+ html[dir='rtl'] .secondaryToolbarButton::before {
+ left: 186px;
+ }
+
+ .toolbarField.pageNumber.visiblePageIsLoading,
+ #findInput[data-status="pending"] {
+ background-image: url(images/loading-small@2x.png);
+ background-size: 16px 17px;
+ }
+
+ .dropdownToolbarButton {
+ background: url(images/toolbarButton-menuArrows@2x.png) no-repeat;
+ background-size: 7px 16px;
+ }
+
+ html[dir='ltr'] .toolbarButton#sidebarToggle::before {
+ content: url(images/toolbarButton-sidebarToggle@2x.png);
+ }
+ html[dir='rtl'] .toolbarButton#sidebarToggle::before {
+ content: url(images/toolbarButton-sidebarToggle-rtl@2x.png);
+ }
+
+ html[dir='ltr'] .toolbarButton#secondaryToolbarToggle::before {
+ content: url(images/toolbarButton-secondaryToolbarToggle@2x.png);
+ }
+ html[dir='rtl'] .toolbarButton#secondaryToolbarToggle::before {
+ content: url(images/toolbarButton-secondaryToolbarToggle-rtl@2x.png);
+ }
+
+ html[dir='ltr'] .toolbarButton.findPrevious::before {
+ content: url(images/findbarButton-previous@2x.png);
+ }
+ html[dir='rtl'] .toolbarButton.findPrevious::before {
+ content: url(images/findbarButton-previous-rtl@2x.png);
+ }
+
+ html[dir='ltr'] .toolbarButton.findNext::before {
+ content: url(images/findbarButton-next@2x.png);
+ }
+ html[dir='rtl'] .toolbarButton.findNext::before {
+ content: url(images/findbarButton-next-rtl@2x.png);
+ }
+
+ html[dir='ltr'] .toolbarButton.pageUp::before {
+ content: url(images/toolbarButton-pageUp@2x.png);
+ }
+ html[dir='rtl'] .toolbarButton.pageUp::before {
+ content: url(images/toolbarButton-pageUp-rtl@2x.png);
+ }
+
+ html[dir='ltr'] .toolbarButton.pageDown::before {
+ content: url(images/toolbarButton-pageDown@2x.png);
+ }
+ html[dir='rtl'] .toolbarButton.pageDown::before {
+ content: url(images/toolbarButton-pageDown-rtl@2x.png);
+ }
+
+ .toolbarButton.zoomIn::before {
+ content: url(images/toolbarButton-zoomIn@2x.png);
+ }
+
+ .toolbarButton.zoomOut::before {
+ content: url(images/toolbarButton-zoomOut@2x.png);
+ }
+
+ .toolbarButton.presentationMode::before,
+ .secondaryToolbarButton.presentationMode::before {
+ content: url(images/toolbarButton-presentationMode@2x.png);
+ }
+
+ .toolbarButton.print::before,
+ .secondaryToolbarButton.print::before {
+ content: url(images/toolbarButton-print@2x.png);
+ }
+
+ .toolbarButton.openFile::before,
+ .secondaryToolbarButton.openFile::before {
+ content: url(images/toolbarButton-openFile@2x.png);
+ }
+
+ .toolbarButton.download::before,
+ .secondaryToolbarButton.download::before {
+ content: url(images/toolbarButton-download@2x.png);
+ }
+
+ .toolbarButton.bookmark::before,
+ .secondaryToolbarButton.bookmark::before {
+ content: url(images/toolbarButton-bookmark@2x.png);
+ }
+
+ #viewThumbnail.toolbarButton::before {
+ content: url(images/toolbarButton-viewThumbnail@2x.png);
+ }
+
+ html[dir="ltr"] #viewOutline.toolbarButton::before {
+ content: url(images/toolbarButton-viewOutline@2x.png);
+ }
+ html[dir="rtl"] #viewOutline.toolbarButton::before {
+ content: url(images/toolbarButton-viewOutline-rtl@2x.png);
+ }
+
+ #viewAttachments.toolbarButton::before {
+ content: url(images/toolbarButton-viewAttachments@2x.png);
+ }
+
+ #viewFind.toolbarButton::before {
+ content: url(images/toolbarButton-search@2x.png);
+ }
+
+ .secondaryToolbarButton.firstPage::before {
+ content: url(images/secondaryToolbarButton-firstPage@2x.png);
+ }
+
+ .secondaryToolbarButton.lastPage::before {
+ content: url(images/secondaryToolbarButton-lastPage@2x.png);
+ }
+
+ .secondaryToolbarButton.rotateCcw::before {
+ content: url(images/secondaryToolbarButton-rotateCcw@2x.png);
+ }
+
+ .secondaryToolbarButton.rotateCw::before {
+ content: url(images/secondaryToolbarButton-rotateCw@2x.png);
+ }
+
+ .secondaryToolbarButton.handTool::before {
+ content: url(images/secondaryToolbarButton-handTool@2x.png);
+ }
+
+ .secondaryToolbarButton.documentProperties::before {
+ content: url(images/secondaryToolbarButton-documentProperties@2x.png);
+ }
+}
+
@media print {
/* General rules for printing. */
body {
@@ -1571,6 +1855,8 @@ canvas {
display: none;
border: none;
box-shadow: none;
+ background-clip: content-box;
+ background-color: white;
}
.page[data-loaded] {
@@ -1592,6 +1878,7 @@ canvas {
position: relative;
top: 0;
left: 0;
+ display: block;
}
}
@@ -1638,7 +1925,7 @@ canvas {
z-index: 100;
}
.loadingInProgress #sidebarContainer {
- top: 39px;
+ top: 37px;
}
#sidebarContent {
top: 32px;
@@ -1716,4 +2003,3 @@ canvas {
display: none;
}
}
-
diff --git a/static/pdf.js/viewer.js b/static/pdf.js/viewer.js
index bb3f54e49..3c4ee96a6 100644
--- a/static/pdf.js/viewer.js
+++ b/static/pdf.js/viewer.js
@@ -14,51 +14,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, PDFFindBar, CustomStyle,
- PDFFindController, ProgressBar, TextLayerBuilder, DownloadManager,
- getFileName, scrollIntoView, getPDFFileNameFromURL, PDFHistory,
- Preferences, ViewHistory, PageView, ThumbnailView,
- noContextMenuHandler, SecondaryToolbar, PasswordPrompt,
- PresentationMode, HandTool, Promise */
+/* globals PDFJS, PDFBug, FirefoxCom, Stats, Cache, ProgressBar,
+ DownloadManager, getFileName, scrollIntoView, getPDFFileNameFromURL,
+ PDFHistory, Preferences, SidebarView, ViewHistory, PageView,
+ PDFThumbnailViewer, URL, noContextMenuHandler, SecondaryToolbar,
+ PasswordPrompt, PresentationMode, HandTool, Promise,
+ DocumentProperties, DocumentOutlineView, DocumentAttachmentsView,
+ OverlayManager, PDFFindController, PDFFindBar, getVisibleElements,
+ watchScroll, PDFViewer, PDFRenderingQueue, PresentationModeState,
+ RenderingStates, DEFAULT_SCALE, UNKNOWN_SCALE,
+ IGNORE_CURRENT_POSITION_ON_ZOOM: true */
'use strict';
-var DEFAULT_SCALE = 'auto';
var DEFAULT_SCALE_DELTA = 1.1;
-var UNKNOWN_SCALE = 0;
-var CACHE_SIZE = 20;
-var CSS_UNITS = 96.0 / 72.0;
-var SCROLLBAR_PADDING = 40;
-var VERTICAL_PADDING = 5;
-var MAX_AUTO_SCALE = 1.25;
var MIN_SCALE = 0.25;
-var MAX_SCALE = 4.0;
+var MAX_SCALE = 10.0;
var VIEW_HISTORY_MEMORY = 20;
var IMAGE_DIR = '/static/pdf.js/images/';
var SCALE_SELECT_CONTAINER_PADDING = 8;
var SCALE_SELECT_PADDING = 22;
-var THUMBNAIL_SCROLL_MARGIN = -19;
-var USE_ONLY_CSS_ZOOM = false;
-var CLEANUP_TIMEOUT = 30000;
-var RenderingStates = {
- INITIAL: 0,
- RUNNING: 1,
- PAUSED: 2,
- FINISHED: 3
-};
-var FindStates = {
- FIND_FOUND: 0,
- FIND_NOTFOUND: 1,
- FIND_WRAPPED: 2,
- FIND_PENDING: 3
-};
+var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
PDFJS.imageResourcesPath = './images/';
PDFJS.workerSrc = '/static/pdf.js/pdf.worker.js';
+ PDFJS.cMapUrl = '/static/pdf.js/cmaps/';
+ PDFJS.cMapPacked = true;
var mozL10n = document.mozL10n || document.webL10n;
+var CSS_UNITS = 96.0 / 72.0;
+var DEFAULT_SCALE = 'auto';
+var UNKNOWN_SCALE = 0;
+var MAX_AUTO_SCALE = 1.25;
+var SCROLLBAR_PADDING = 40;
+var VERTICAL_PADDING = 5;
+var DEFAULT_CACHE_SIZE = 10;
+
// optimised CSS custom property getter/setter
var CustomStyle = (function CustomStyleClosure() {
@@ -67,14 +60,13 @@ var CustomStyle = (function CustomStyleClosure() {
// in some versions of IE9 it is critical that ms appear in this list
// before Moz
var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
- var _cache = { };
+ var _cache = {};
- function CustomStyle() {
- }
+ function CustomStyle() {}
CustomStyle.getProp = function get(propName, element) {
// check cache only when no element is given
- if (arguments.length == 1 && typeof _cache[propName] == 'string') {
+ if (arguments.length === 1 && typeof _cache[propName] === 'string') {
return _cache[propName];
}
@@ -82,7 +74,7 @@ var CustomStyle = (function CustomStyleClosure() {
var style = element.style, prefixed, uPropName;
// test standard property first
- if (typeof style[propName] == 'string') {
+ if (typeof style[propName] === 'string') {
return (_cache[propName] = propName);
}
@@ -92,7 +84,7 @@ var CustomStyle = (function CustomStyleClosure() {
// test vendor specific properties
for (var i = 0, l = prefixes.length; i < l; i++) {
prefixed = prefixes[i] + uPropName;
- if (typeof style[prefixed] == 'string') {
+ if (typeof style[prefixed] === 'string') {
return (_cache[propName] = prefixed);
}
}
@@ -103,8 +95,9 @@ var CustomStyle = (function CustomStyleClosure() {
CustomStyle.setProp = function set(propName, element, str) {
var prop = this.getProp(propName);
- if (prop != 'undefined')
+ if (prop !== 'undefined') {
element.style[prop] = str;
+ }
};
return CustomStyle;
@@ -136,7 +129,7 @@ function getOutputScale(ctx) {
return {
sx: pixelRatio,
sy: pixelRatio,
- scaled: pixelRatio != 1
+ scaled: pixelRatio !== 1
};
}
@@ -181,6 +174,91 @@ function scrollIntoView(element, spot) {
parent.scrollTop = offsetY;
}
+/**
+ * Helper function to start monitoring the scroll event and converting them into
+ * PDF.js friendly one: with scroll debounce and scroll direction.
+ */
+function watchScroll(viewAreaElement, callback) {
+ var debounceScroll = function debounceScroll(evt) {
+ if (rAF) {
+ return;
+ }
+ // schedule an invocation of scroll for next animation frame.
+ rAF = window.requestAnimationFrame(function viewAreaElementScrolled() {
+ rAF = null;
+
+ var currentY = viewAreaElement.scrollTop;
+ var lastY = state.lastY;
+ if (currentY > lastY) {
+ state.down = true;
+ } else if (currentY < lastY) {
+ state.down = false;
+ }
+ state.lastY = currentY;
+ // else do nothing and use previous value
+ callback(state);
+ });
+ };
+
+ var state = {
+ down: true,
+ lastY: viewAreaElement.scrollTop,
+ _eventHandler: debounceScroll
+ };
+
+ var rAF = null;
+ viewAreaElement.addEventListener('scroll', debounceScroll, true);
+ return state;
+}
+
+/**
+ * Generic helper to find out what elements are visible within a scroll pane.
+ */
+function getVisibleElements(scrollEl, views, sortByVisibility) {
+ var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
+ var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
+
+ var visible = [], view;
+ var currentHeight, viewHeight, hiddenHeight, percentHeight;
+ var currentWidth, viewWidth;
+ for (var i = 0, ii = views.length; i < ii; ++i) {
+ view = views[i];
+ currentHeight = view.el.offsetTop + view.el.clientTop;
+ viewHeight = view.el.clientHeight;
+ if ((currentHeight + viewHeight) < top) {
+ continue;
+ }
+ if (currentHeight > bottom) {
+ break;
+ }
+ currentWidth = view.el.offsetLeft + view.el.clientLeft;
+ viewWidth = view.el.clientWidth;
+ if ((currentWidth + viewWidth) < left || currentWidth > right) {
+ continue;
+ }
+ hiddenHeight = Math.max(0, top - currentHeight) +
+ Math.max(0, currentHeight + viewHeight - bottom);
+ percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
+
+ visible.push({ id: view.id, x: currentWidth, y: currentHeight,
+ view: view, percent: percentHeight });
+ }
+
+ var first = visible[0];
+ var last = visible[visible.length - 1];
+
+ if (sortByVisibility) {
+ visible.sort(function(a, b) {
+ var pc = a.percent - b.percent;
+ if (Math.abs(pc) > 0.001) {
+ return -pc;
+ }
+ return a.id - b.id; // ensure stability
+ });
+ }
+ return {first: first, last: last, views: visible};
+}
+
/**
* Event handler to suppress context menu.
*/
@@ -204,7 +282,7 @@ function getPDFFileNameFromURL(url) {
reFilename.exec(splitURI[3]);
if (suggestedFilename) {
suggestedFilename = suggestedFilename[0];
- if (suggestedFilename.indexOf('%') != -1) {
+ if (suggestedFilename.indexOf('%') !== -1) {
// URL-encoded %2Fpath%2Fto%2Ffile.pdf should be file.pdf
try {
suggestedFilename =
@@ -290,75 +368,134 @@ var Cache = function cacheCache(size) {
var data = [];
this.push = function cachePush(view) {
var i = data.indexOf(view);
- if (i >= 0)
- data.splice(i);
+ if (i >= 0) {
+ data.splice(i, 1);
+ }
data.push(view);
- if (data.length > size)
+ if (data.length > size) {
data.shift().destroy();
+ }
+ };
+ this.resize = function (newSize) {
+ size = newSize;
+ while (data.length > size) {
+ data.shift().destroy();
+ }
};
};
-var isLocalStorageEnabled = (function isLocalStorageEnabledClosure() {
- // Feature test as per http://diveintohtml5.info/storage.html
- // The additional localStorage call is to get around a FF quirk, see
- // bug #495747 in bugzilla
- try {
- return ('localStorage' in window && window['localStorage'] !== null &&
- localStorage);
- } catch (e) {
- return false;
- }
-})();
-
-var EXPORTED_SYMBOLS = ['DEFAULT_PREFERENCES'];
-
var DEFAULT_PREFERENCES = {
showPreviousViewOnLoad: true,
defaultZoomValue: '',
- ifAvailableShowOutlineOnLoad: false
+ sidebarViewOnLoad: 0,
+ enableHandToolOnLoad: false,
+ enableWebGL: false,
+ pdfBugEnabled: false,
+ disableRange: false,
+ disableStream: false,
+ disableAutoFetch: false,
+ disableFontFace: false,
+ disableTextLayer: false,
+ useOnlyCssZoom: false
};
-var Preferences = (function PreferencesClosure() {
- function Preferences() {
- this.prefs = {};
- this.isInitializedPromiseResolved = false;
- this.initializedPromise = this.readFromStorage().then(function(prefObj) {
+var SidebarView = {
+ NONE: 0,
+ THUMBS: 1,
+ OUTLINE: 2,
+ ATTACHMENTS: 3
+};
+
+/**
+ * Preferences - Utility for storing persistent settings.
+ * Used for settings that should be applied to all opened documents,
+ * or every time the viewer is loaded.
+ */
+var Preferences = {
+ prefs: Object.create(DEFAULT_PREFERENCES),
+ isInitializedPromiseResolved: false,
+ initializedPromise: null,
+
+ /**
+ * Initialize and fetch the current preference values from storage.
+ * @return {Promise} A promise that is resolved when the preferences
+ * have been initialized.
+ */
+ initialize: function preferencesInitialize() {
+ return this.initializedPromise =
+ this._readFromStorage(DEFAULT_PREFERENCES).then(function(prefObj) {
this.isInitializedPromiseResolved = true;
if (prefObj) {
this.prefs = prefObj;
}
}.bind(this));
- }
+ },
- Preferences.prototype = {
- writeToStorage: function Preferences_writeToStorage(prefObj) {
- return;
- },
+ /**
+ * Stub function for writing preferences to storage.
+ * NOTE: This should be overridden by a build-specific function defined below.
+ * @param {Object} prefObj The preferences that should be written to storage.
+ * @return {Promise} A promise that is resolved when the preference values
+ * have been written.
+ */
+ _writeToStorage: function preferences_writeToStorage(prefObj) {
+ return Promise.resolve();
+ },
- readFromStorage: function Preferences_readFromStorage() {
- var readFromStoragePromise = Promise.resolve();
- return readFromStoragePromise;
- },
+ /**
+ * Stub function for reading preferences from storage.
+ * NOTE: This should be overridden by a build-specific function defined below.
+ * @param {Object} prefObj The preferences that should be read from storage.
+ * @return {Promise} A promise that is resolved with an {Object} containing
+ * the preferences that have been read.
+ */
+ _readFromStorage: function preferences_readFromStorage(prefObj) {
+ return Promise.resolve();
+ },
- reset: function Preferences_reset() {
- if (this.isInitializedPromiseResolved) {
- this.prefs = {};
- this.writeToStorage(this.prefs);
- }
- },
+ /**
+ * Reset the preferences to their default values and update storage.
+ * @return {Promise} A promise that is resolved when the preference values
+ * have been reset.
+ */
+ reset: function preferencesReset() {
+ return this.initializedPromise.then(function() {
+ this.prefs = Object.create(DEFAULT_PREFERENCES);
+ return this._writeToStorage(DEFAULT_PREFERENCES);
+ }.bind(this));
+ },
- set: function Preferences_set(name, value) {
- if (!this.isInitializedPromiseResolved) {
- return;
- } else if (DEFAULT_PREFERENCES[name] === undefined) {
- console.error('Preferences_set: \'' + name + '\' is undefined.');
- return;
+ /**
+ * Replace the current preference values with the ones from storage.
+ * @return {Promise} A promise that is resolved when the preference values
+ * have been updated.
+ */
+ reload: function preferencesReload() {
+ return this.initializedPromise.then(function () {
+ this._readFromStorage(DEFAULT_PREFERENCES).then(function(prefObj) {
+ if (prefObj) {
+ this.prefs = prefObj;
+ }
+ }.bind(this));
+ }.bind(this));
+ },
+
+ /**
+ * Set the value of a preference.
+ * @param {string} name The name of the preference that should be changed.
+ * @param {boolean|number|string} value The new value of the preference.
+ * @return {Promise} A promise that is resolved when the value has been set,
+ * provided that the preference exists and the types match.
+ */
+ set: function preferencesSet(name, value) {
+ return this.initializedPromise.then(function () {
+ if (DEFAULT_PREFERENCES[name] === undefined) {
+ throw new Error('preferencesSet: \'' + name + '\' is undefined.');
} else if (value === undefined) {
- console.error('Preferences_set: no value is specified.');
- return;
+ throw new Error('preferencesSet: no value is specified.');
}
var valueType = typeof value;
var defaultType = typeof DEFAULT_PREFERENCES[name];
@@ -367,50 +504,58 @@ var Preferences = (function PreferencesClosure() {
if (valueType === 'number' && defaultType === 'string') {
value = value.toString();
} else {
- console.error('Preferences_set: \'' + value + '\' is a \"' +
- valueType + '\", expected a \"' + defaultType + '\".');
- return;
+ throw new Error('Preferences_set: \'' + value + '\' is a \"' +
+ valueType + '\", expected \"' + defaultType + '\".');
+ }
+ } else {
+ if (valueType === 'number' && (value | 0) !== value) {
+ throw new Error('Preferences_set: \'' + value +
+ '\' must be an \"integer\".');
}
}
this.prefs[name] = value;
- this.writeToStorage(this.prefs);
- },
+ return this._writeToStorage(this.prefs);
+ }.bind(this));
+ },
- get: function Preferences_get(name) {
- var defaultPref = DEFAULT_PREFERENCES[name];
+ /**
+ * Get the value of a preference.
+ * @param {string} name The name of the preference whose value is requested.
+ * @return {Promise} A promise that is resolved with a {boolean|number|string}
+ * containing the value of the preference.
+ */
+ get: function preferencesGet(name) {
+ return this.initializedPromise.then(function () {
+ var defaultValue = DEFAULT_PREFERENCES[name];
- if (defaultPref === undefined) {
- console.error('Preferences_get: \'' + name + '\' is undefined.');
- return;
- } else if (this.isInitializedPromiseResolved) {
- var pref = this.prefs[name];
+ if (defaultValue === undefined) {
+ throw new Error('preferencesGet: \'' + name + '\' is undefined.');
+ } else {
+ var prefValue = this.prefs[name];
- if (pref !== undefined) {
- return pref;
+ if (prefValue !== undefined) {
+ return prefValue;
}
}
- return defaultPref;
- }
- };
-
- return Preferences;
-})();
-
-
-Preferences.prototype.writeToStorage = function(prefObj) {
- if (isLocalStorageEnabled) {
- localStorage.setItem('preferences', JSON.stringify(prefObj));
+ return defaultValue;
+ }.bind(this));
}
};
-Preferences.prototype.readFromStorage = function() {
- var readFromStoragePromise = new Promise(function (resolve) {
- if (isLocalStorageEnabled) {
- var readPrefs = JSON.parse(localStorage.getItem('preferences'));
- resolve(readPrefs);
- }
+
+
+Preferences._writeToStorage = function (prefObj) {
+ return new Promise(function (resolve) {
+ localStorage.setItem('pdfjs.preferences', JSON.stringify(prefObj));
+ resolve();
+ });
+};
+
+Preferences._readFromStorage = function (prefObj) {
+ return new Promise(function (resolve) {
+ var readPrefs = JSON.parse(localStorage.getItem('pdfjs.preferences'));
+ resolve(readPrefs);
});
- return readFromStoragePromise;
};
@@ -495,7 +640,10 @@ Preferences.prototype.readFromStorage = function() {
var hasAttachEvent = !!document.attachEvent;
window.addEventListener('keydown', function(event) {
- if (event.keyCode === 80/*P*/ && (event.ctrlKey || event.metaKey)) {
+ // Intercept Cmd/Ctrl + P in all browsers.
+ // Also intercept Cmd/Ctrl + Shift + P in Chrome and Opera
+ if (event.keyCode === 80/*P*/ && (event.ctrlKey || event.metaKey) &&
+ !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
window.print();
if (hasAttachEvent) {
// Only attachEvent can cancel Ctrl + P dialog in IE <=10
@@ -588,6 +736,17 @@ var DownloadManager = (function DownloadManagerClosure() {
download(url + '#pdfjs.action=download', filename);
},
+ downloadData: function DownloadManager_downloadData(data, filename,
+ contentType) {
+ if (navigator.msSaveBlob) { // IE10 and above
+ return navigator.msSaveBlob(new Blob([data], { type: contentType }),
+ filename);
+ }
+
+ var blobUrl = PDFJS.createObjectURL(data, contentType);
+ download(blobUrl, filename);
+ },
+
download: function DownloadManager_download(blob, url, filename) {
if (!URL) {
// URL.createObjectURL is not supported
@@ -613,8 +772,6 @@ var DownloadManager = (function DownloadManagerClosure() {
-var cache = new Cache(CACHE_SIZE);
-var currentPageNumber = 1;
/**
@@ -623,35 +780,19 @@ var currentPageNumber = 1;
*
* The way that the view parameters are stored depends on how PDF.js is built,
* for 'node make ' the following cases exist:
- * - FIREFOX or MOZCENTRAL - uses about:config.
+ * - FIREFOX or MOZCENTRAL - uses sessionStorage.
* - B2G - uses asyncStorage.
* - GENERIC or CHROME - uses localStorage, if it is available.
*/
var ViewHistory = (function ViewHistoryClosure() {
function ViewHistory(fingerprint) {
this.fingerprint = fingerprint;
- var initializedPromiseResolve;
this.isInitializedPromiseResolved = false;
- this.initializedPromise = new Promise(function (resolve) {
- initializedPromiseResolve = resolve;
- });
-
- var resolvePromise = (function ViewHistoryResolvePromise(db) {
+ this.initializedPromise =
+ this._readFromStorage().then(function (databaseStr) {
this.isInitializedPromiseResolved = true;
- this.initialize(db || '{}');
- initializedPromiseResolve();
- }).bind(this);
-
-
- if (isLocalStorageEnabled) {
- resolvePromise(localStorage.getItem('database'));
- }
- }
-
- ViewHistory.prototype = {
- initialize: function ViewHistory_initialize(database) {
- database = JSON.parse(database);
+ var database = JSON.parse(databaseStr || '{}');
if (!('files' in database)) {
database.files = [];
}
@@ -671,21 +812,45 @@ var ViewHistory = (function ViewHistoryClosure() {
}
this.file = database.files[index];
this.database = database;
+ }.bind(this));
+ }
+
+ ViewHistory.prototype = {
+ _writeToStorage: function ViewHistory_writeToStorage() {
+ return new Promise(function (resolve) {
+ var databaseStr = JSON.stringify(this.database);
+
+
+
+ localStorage.setItem('database', databaseStr);
+ resolve();
+ }.bind(this));
+ },
+
+ _readFromStorage: function ViewHistory_readFromStorage() {
+ return new Promise(function (resolve) {
+
+
+ resolve(localStorage.getItem('database'));
+ });
},
set: function ViewHistory_set(name, val) {
if (!this.isInitializedPromiseResolved) {
return;
}
- var file = this.file;
- file[name] = val;
- var database = JSON.stringify(this.database);
+ this.file[name] = val;
+ return this._writeToStorage();
+ },
-
-
- if (isLocalStorageEnabled) {
- localStorage.setItem('database', database);
+ setMultiple: function ViewHistory_setMultiple(properties) {
+ if (!this.isInitializedPromiseResolved) {
+ return;
}
+ for (var name in properties) {
+ this.file[name] = properties[name];
+ }
+ return this._writeToStorage();
},
get: function ViewHistory_get(name, defaultValue) {
@@ -700,44 +865,32 @@ var ViewHistory = (function ViewHistoryClosure() {
})();
-/* globals PDFFindController, FindStates, mozL10n */
-
/**
- * Creates a "search bar" given set of DOM elements
- * that act as controls for searching, or for setting
- * search preferences in the UI. This object also sets
- * up the appropriate events for the controls. Actual
- * searching is done by PDFFindController
+ * Creates a "search bar" given a set of DOM elements that act as controls
+ * for searching or for setting search preferences in the UI. This object
+ * also sets up the appropriate events for the controls. Actual searching
+ * is done by PDFFindController.
*/
-var PDFFindBar = {
+var PDFFindBar = (function PDFFindBarClosure() {
+ function PDFFindBar(options) {
+ this.opened = false;
+ this.bar = options.bar || null;
+ this.toggleButton = options.toggleButton || null;
+ this.findField = options.findField || null;
+ this.highlightAll = options.highlightAllCheckbox || null;
+ this.caseSensitive = options.caseSensitiveCheckbox || null;
+ this.findMsg = options.findMsg || null;
+ this.findStatusIcon = options.findStatusIcon || null;
+ this.findPreviousButton = options.findPreviousButton || null;
+ this.findNextButton = options.findNextButton || null;
+ this.findController = options.findController || null;
- opened: false,
- bar: null,
- toggleButton: null,
- findField: null,
- highlightAll: null,
- caseSensitive: null,
- findMsg: null,
- findStatusIcon: null,
- findPreviousButton: null,
- findNextButton: null,
-
- initialize: function(options) {
- if(typeof PDFFindController === 'undefined' || PDFFindController === null) {
- throw 'PDFFindBar cannot be initialized ' +
- 'without a PDFFindController instance.';
+ if (this.findController === null) {
+ throw new Error('PDFFindBar cannot be used without a ' +
+ 'PDFFindController instance.');
}
- this.bar = options.bar;
- this.toggleButton = options.toggleButton;
- this.findField = options.findField;
- this.highlightAll = options.highlightAllCheckbox;
- this.caseSensitive = options.caseSensitiveCheckbox;
- this.findMsg = options.findMsg;
- this.findStatusIcon = options.findStatusIcon;
- this.findPreviousButton = options.findPreviousButton;
- this.findNextButton = options.findNextButton;
-
+ // Add event listeners to the DOM elements.
var self = this;
this.toggleButton.addEventListener('click', function() {
self.toggle();
@@ -760,9 +913,9 @@ var PDFFindBar = {
}
});
- this.findPreviousButton.addEventListener('click',
- function() { self.dispatchEvent('again', true); }
- );
+ this.findPreviousButton.addEventListener('click', function() {
+ self.dispatchEvent('again', true);
+ });
this.findNextButton.addEventListener('click', function() {
self.dispatchEvent('again', false);
@@ -775,146 +928,144 @@ var PDFFindBar = {
this.caseSensitive.addEventListener('click', function() {
self.dispatchEvent('casesensitivitychange');
});
- },
-
- dispatchEvent: function(aType, aFindPrevious) {
- var event = document.createEvent('CustomEvent');
- event.initCustomEvent('find' + aType, true, true, {
- query: this.findField.value,
- caseSensitive: this.caseSensitive.checked,
- highlightAll: this.highlightAll.checked,
- findPrevious: aFindPrevious
- });
- return window.dispatchEvent(event);
- },
-
- updateUIState: function(state, previous) {
- var notFound = false;
- var findMsg = '';
- var status = '';
-
- switch (state) {
- case FindStates.FIND_FOUND:
- break;
-
- case FindStates.FIND_PENDING:
- status = 'pending';
- break;
-
- case FindStates.FIND_NOTFOUND:
- findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
- notFound = true;
- break;
-
- case FindStates.FIND_WRAPPED:
- if (previous) {
- findMsg = mozL10n.get('find_reached_top', null,
- 'Reached top of document, continued from bottom');
- } else {
- findMsg = mozL10n.get('find_reached_bottom', null,
- 'Reached end of document, continued from top');
- }
- break;
- }
-
- if (notFound) {
- this.findField.classList.add('notFound');
- } else {
- this.findField.classList.remove('notFound');
- }
-
- this.findField.setAttribute('data-status', status);
- this.findMsg.textContent = findMsg;
- },
-
- open: function() {
- if (!this.opened) {
- this.opened = true;
- this.toggleButton.classList.add('toggled');
- this.bar.classList.remove('hidden');
- }
-
- this.findField.select();
- this.findField.focus();
- },
-
- close: function() {
- if (!this.opened) return;
-
- this.opened = false;
- this.toggleButton.classList.remove('toggled');
- this.bar.classList.add('hidden');
-
- PDFFindController.active = false;
- },
-
- toggle: function() {
- if (this.opened) {
- this.close();
- } else {
- this.open();
- }
}
+
+ PDFFindBar.prototype = {
+ dispatchEvent: function PDFFindBar_dispatchEvent(type, findPrev) {
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('find' + type, true, true, {
+ query: this.findField.value,
+ caseSensitive: this.caseSensitive.checked,
+ highlightAll: this.highlightAll.checked,
+ findPrevious: findPrev
+ });
+ return window.dispatchEvent(event);
+ },
+
+ updateUIState: function PDFFindBar_updateUIState(state, previous) {
+ var notFound = false;
+ var findMsg = '';
+ var status = '';
+
+ switch (state) {
+ case FindStates.FIND_FOUND:
+ break;
+
+ case FindStates.FIND_PENDING:
+ status = 'pending';
+ break;
+
+ case FindStates.FIND_NOTFOUND:
+ findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
+ notFound = true;
+ break;
+
+ case FindStates.FIND_WRAPPED:
+ if (previous) {
+ findMsg = mozL10n.get('find_reached_top', null,
+ 'Reached top of document, continued from bottom');
+ } else {
+ findMsg = mozL10n.get('find_reached_bottom', null,
+ 'Reached end of document, continued from top');
+ }
+ break;
+ }
+
+ if (notFound) {
+ this.findField.classList.add('notFound');
+ } else {
+ this.findField.classList.remove('notFound');
+ }
+
+ this.findField.setAttribute('data-status', status);
+ this.findMsg.textContent = findMsg;
+ },
+
+ open: function PDFFindBar_open() {
+ if (!this.opened) {
+ this.opened = true;
+ this.toggleButton.classList.add('toggled');
+ this.bar.classList.remove('hidden');
+ }
+ this.findField.select();
+ this.findField.focus();
+ },
+
+ close: function PDFFindBar_close() {
+ if (!this.opened) {
+ return;
+ }
+ this.opened = false;
+ this.toggleButton.classList.remove('toggled');
+ this.bar.classList.add('hidden');
+ this.findController.active = false;
+ },
+
+ toggle: function PDFFindBar_toggle() {
+ if (this.opened) {
+ this.close();
+ } else {
+ this.open();
+ }
+ }
+ };
+ return PDFFindBar;
+})();
+
+
+
+var FindStates = {
+ FIND_FOUND: 0,
+ FIND_NOTFOUND: 1,
+ FIND_WRAPPED: 2,
+ FIND_PENDING: 3
};
-
-
-/* globals PDFFindBar, PDFJS, FindStates, FirefoxCom, Promise */
-
/**
- * Provides a "search" or "find" functionality for the PDF.
+ * Provides "search" or "find" functionality for the PDF.
* This object actually performs the search for a given string.
*/
+var PDFFindController = (function PDFFindControllerClosure() {
+ function PDFFindController(options) {
+ this.startedTextExtraction = false;
+ this.extractTextPromises = [];
+ this.pendingFindMatches = {};
+ this.active = false; // If active, find results will be highlighted.
+ this.pageContents = []; // Stores the text for each page.
+ this.pageMatches = [];
+ this.selected = { // Currently selected match.
+ pageIdx: -1,
+ matchIdx: -1
+ };
+ this.offset = { // Where the find algorithm currently is in the document.
+ pageIdx: null,
+ matchIdx: null
+ };
+ this.pagesToSearch = null;
+ this.resumePageIdx = null;
+ this.state = null;
+ this.dirtyMatch = false;
+ this.findTimeout = null;
+ this.pdfViewer = options.pdfViewer || null;
+ this.integratedFind = options.integratedFind || false;
+ this.charactersToNormalize = {
+ '\u2018': '\'', // Left single quotation mark
+ '\u2019': '\'', // Right single quotation mark
+ '\u201A': '\'', // Single low-9 quotation mark
+ '\u201B': '\'', // Single high-reversed-9 quotation mark
+ '\u201C': '"', // Left double quotation mark
+ '\u201D': '"', // Right double quotation mark
+ '\u201E': '"', // Double low-9 quotation mark
+ '\u201F': '"', // Double high-reversed-9 quotation mark
+ '\u00BC': '1/4', // Vulgar fraction one quarter
+ '\u00BD': '1/2', // Vulgar fraction one half
+ '\u00BE': '3/4' // Vulgar fraction three quarters
+ };
+ this.findBar = options.findBar || null;
-var PDFFindController = {
- startedTextExtraction: false,
-
- extractTextPromises: [],
-
- pendingFindMatches: {},
-
- // If active, find results will be highlighted.
- active: false,
-
- // Stores the text for each page.
- pageContents: [],
-
- pageMatches: [],
-
- // Currently selected match.
- selected: {
- pageIdx: -1,
- matchIdx: -1
- },
-
- // Where find algorithm currently is in the document.
- offset: {
- pageIdx: null,
- matchIdx: null
- },
-
- resumePageIdx: null,
-
- resumeCallback: null,
-
- state: null,
-
- dirtyMatch: false,
-
- findTimeout: null,
-
- pdfPageSource: null,
-
- integratedFind: false,
-
- initialize: function(options) {
- if(typeof PDFFindBar === 'undefined' || PDFFindBar === null) {
- throw 'PDFFindController cannot be initialized ' +
- 'without a PDFFindController instance';
- }
-
- this.pdfPageSource = options.pdfPageSource;
- this.integratedFind = options.integratedFind;
+ // Compile the regular expression for text normalization once
+ var replace = Object.keys(this.charactersToNormalize).join('');
+ this.normalizationRegex = new RegExp('[' + replace + ']', 'g');
var events = [
'find',
@@ -928,279 +1079,300 @@ var PDFFindController = {
}.bind(this));
this.handleEvent = this.handleEvent.bind(this);
- for (var i = 0; i < events.length; i++) {
+ for (var i = 0, len = events.length; i < len; i++) {
window.addEventListener(events[i], this.handleEvent);
}
- },
+ }
- reset: function pdfFindControllerReset() {
- this.startedTextExtraction = false;
- this.extractTextPromises = [];
- this.active = false;
- },
+ PDFFindController.prototype = {
+ setFindBar: function PDFFindController_setFindBar(findBar) {
+ this.findBar = findBar;
+ },
- calcFindMatch: function(pageIndex) {
- var pageContent = this.pageContents[pageIndex];
- var query = this.state.query;
- var caseSensitive = this.state.caseSensitive;
- var queryLen = query.length;
+ reset: function PDFFindController_reset() {
+ this.startedTextExtraction = false;
+ this.extractTextPromises = [];
+ this.active = false;
+ },
- if (queryLen === 0) {
- // Do nothing the matches should be wiped out already.
- return;
- }
-
- if (!caseSensitive) {
- pageContent = pageContent.toLowerCase();
- query = query.toLowerCase();
- }
-
- var matches = [];
-
- var matchIdx = -queryLen;
- while (true) {
- matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
- if (matchIdx === -1) {
- break;
- }
-
- matches.push(matchIdx);
- }
- this.pageMatches[pageIndex] = matches;
- this.updatePage(pageIndex);
- if (this.resumePageIdx === pageIndex) {
- var callback = this.resumeCallback;
- this.resumePageIdx = null;
- this.resumeCallback = null;
- callback();
- }
- },
-
- extractText: function() {
- if (this.startedTextExtraction) {
- return;
- }
- this.startedTextExtraction = true;
-
- this.pageContents = [];
- var extractTextPromisesResolves = [];
- for (var i = 0, ii = this.pdfPageSource.pdfDocument.numPages; i < ii; i++) {
- this.extractTextPromises.push(new Promise(function (resolve) {
- extractTextPromisesResolves.push(resolve);
- }));
- }
-
- var self = this;
- function extractPageText(pageIndex) {
- self.pdfPageSource.pages[pageIndex].getTextContent().then(
- function textContentResolved(data) {
- // Build the find string.
- var bidiTexts = data.bidiTexts;
- var str = '';
-
- for (var i = 0; i < bidiTexts.length; i++) {
- str += bidiTexts[i].str;
- }
-
- // Store the pageContent as a string.
- self.pageContents.push(str);
-
- extractTextPromisesResolves[pageIndex](pageIndex);
- if ((pageIndex + 1) < self.pdfPageSource.pages.length)
- extractPageText(pageIndex + 1);
- }
- );
- }
- extractPageText(0);
- },
-
- handleEvent: function(e) {
- if (this.state === null || e.type !== 'findagain') {
- this.dirtyMatch = true;
- }
- this.state = e.detail;
- this.updateUIState(FindStates.FIND_PENDING);
-
- this.firstPagePromise.then(function() {
- this.extractText();
-
- clearTimeout(this.findTimeout);
- if (e.type === 'find') {
- // Only trigger the find action after 250ms of silence.
- this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
- } else {
- this.nextMatch();
- }
- }.bind(this));
- },
-
- updatePage: function(idx) {
- var page = this.pdfPageSource.pages[idx];
-
- if (this.selected.pageIdx === idx) {
- // If the page is selected, scroll the page into view, which triggers
- // rendering the page, which adds the textLayer. Once the textLayer is
- // build, it will scroll onto the selected match.
- page.scrollIntoView();
- }
-
- if (page.textLayer) {
- page.textLayer.updateMatches();
- }
- },
-
- nextMatch: function() {
- var previous = this.state.findPrevious;
- var currentPageIndex = this.pdfPageSource.page - 1;
- var numPages = this.pdfPageSource.pages.length;
-
- this.active = true;
-
- if (this.dirtyMatch) {
- // Need to recalculate the matches, reset everything.
- this.dirtyMatch = false;
- this.selected.pageIdx = this.selected.matchIdx = -1;
- this.offset.pageIdx = currentPageIndex;
- this.offset.matchIdx = null;
- this.hadMatch = false;
- this.resumeCallback = null;
- this.resumePageIdx = null;
- this.pageMatches = [];
+ normalize: function PDFFindController_normalize(text) {
var self = this;
+ return text.replace(this.normalizationRegex, function (ch) {
+ return self.charactersToNormalize[ch];
+ });
+ },
- for (var i = 0; i < numPages; i++) {
- // Wipe out any previous highlighted matches.
- this.updatePage(i);
+ calcFindMatch: function PDFFindController_calcFindMatch(pageIndex) {
+ var pageContent = this.normalize(this.pageContents[pageIndex]);
+ var query = this.normalize(this.state.query);
+ var caseSensitive = this.state.caseSensitive;
+ var queryLen = query.length;
- // As soon as the text is extracted start finding the matches.
- if (!(i in this.pendingFindMatches)) {
- this.pendingFindMatches[i] = true;
- this.extractTextPromises[i].then(function(pageIdx) {
- delete self.pendingFindMatches[pageIdx];
- self.calcFindMatch(pageIdx);
- });
- }
+ if (queryLen === 0) {
+ return; // Do nothing: the matches should be wiped out already.
}
- }
- // If there's no query there's no point in searching.
- if (this.state.query === '') {
- this.updateUIState(FindStates.FIND_FOUND);
- return;
- }
+ if (!caseSensitive) {
+ pageContent = pageContent.toLowerCase();
+ query = query.toLowerCase();
+ }
- // If we're waiting on a page, we return since we can't do anything else.
- if (this.resumeCallback) {
- return;
- }
+ var matches = [];
+ var matchIdx = -queryLen;
+ while (true) {
+ matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
+ if (matchIdx === -1) {
+ break;
+ }
+ matches.push(matchIdx);
+ }
+ this.pageMatches[pageIndex] = matches;
+ this.updatePage(pageIndex);
+ if (this.resumePageIdx === pageIndex) {
+ this.resumePageIdx = null;
+ this.nextPageMatch();
+ }
+ },
- var offset = this.offset;
- // If there's already a matchIdx that means we are iterating through a
- // page's matches.
- if (offset.matchIdx !== null) {
- var numPageMatches = this.pageMatches[offset.pageIdx].length;
- if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
- (previous && offset.matchIdx > 0)) {
- // The simple case, we just have advance the matchIdx to select the next
- // match on the page.
- this.hadMatch = true;
- offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1;
- this.updateMatch(true);
+ extractText: function PDFFindController_extractText() {
+ if (this.startedTextExtraction) {
return;
}
- // We went beyond the current page's matches, so we advance to the next
- // page.
- this.advanceOffsetPage(previous);
- }
- // Start searching through the page.
- this.nextPageMatch();
- },
+ this.startedTextExtraction = true;
- nextPageMatch: function() {
- if (this.resumePageIdx !== null)
- console.error('There can only be one pending page.');
+ this.pageContents = [];
+ var extractTextPromisesResolves = [];
+ var numPages = this.pdfViewer.pagesCount;
+ for (var i = 0; i < numPages; i++) {
+ this.extractTextPromises.push(new Promise(function (resolve) {
+ extractTextPromisesResolves.push(resolve);
+ }));
+ }
- var matchesReady = function(matches) {
+ var self = this;
+ function extractPageText(pageIndex) {
+ self.pdfViewer.getPageTextContent(pageIndex).then(
+ function textContentResolved(textContent) {
+ var textItems = textContent.items;
+ var str = [];
+
+ for (var i = 0, len = textItems.length; i < len; i++) {
+ str.push(textItems[i].str);
+ }
+
+ // Store the pageContent as a string.
+ self.pageContents.push(str.join(''));
+
+ extractTextPromisesResolves[pageIndex](pageIndex);
+ if ((pageIndex + 1) < self.pdfViewer.pagesCount) {
+ extractPageText(pageIndex + 1);
+ }
+ }
+ );
+ }
+ extractPageText(0);
+ },
+
+ handleEvent: function PDFFindController_handleEvent(e) {
+ if (this.state === null || e.type !== 'findagain') {
+ this.dirtyMatch = true;
+ }
+ this.state = e.detail;
+ this.updateUIState(FindStates.FIND_PENDING);
+
+ this.firstPagePromise.then(function() {
+ this.extractText();
+
+ clearTimeout(this.findTimeout);
+ if (e.type === 'find') {
+ // Only trigger the find action after 250ms of silence.
+ this.findTimeout = setTimeout(this.nextMatch.bind(this), 250);
+ } else {
+ this.nextMatch();
+ }
+ }.bind(this));
+ },
+
+ updatePage: function PDFFindController_updatePage(index) {
+ var page = this.pdfViewer.getPageView(index);
+
+ if (this.selected.pageIdx === index) {
+ // If the page is selected, scroll the page into view, which triggers
+ // rendering the page, which adds the textLayer. Once the textLayer is
+ // build, it will scroll onto the selected match.
+ this.pdfViewer.scrollPageIntoView(index + 1);
+ }
+
+ if (page.textLayer) {
+ page.textLayer.updateMatches();
+ }
+ },
+
+ nextMatch: function PDFFindController_nextMatch() {
+ var previous = this.state.findPrevious;
+ var currentPageIndex = this.pdfViewer.currentPageNumber - 1;
+ var numPages = this.pdfViewer.pagesCount;
+
+ this.active = true;
+
+ if (this.dirtyMatch) {
+ // Need to recalculate the matches, reset everything.
+ this.dirtyMatch = false;
+ this.selected.pageIdx = this.selected.matchIdx = -1;
+ this.offset.pageIdx = currentPageIndex;
+ this.offset.matchIdx = null;
+ this.hadMatch = false;
+ this.resumePageIdx = null;
+ this.pageMatches = [];
+ var self = this;
+
+ for (var i = 0; i < numPages; i++) {
+ // Wipe out any previous highlighted matches.
+ this.updatePage(i);
+
+ // As soon as the text is extracted start finding the matches.
+ if (!(i in this.pendingFindMatches)) {
+ this.pendingFindMatches[i] = true;
+ this.extractTextPromises[i].then(function(pageIdx) {
+ delete self.pendingFindMatches[pageIdx];
+ self.calcFindMatch(pageIdx);
+ });
+ }
+ }
+ }
+
+ // If there's no query there's no point in searching.
+ if (this.state.query === '') {
+ this.updateUIState(FindStates.FIND_FOUND);
+ return;
+ }
+
+ // If we're waiting on a page, we return since we can't do anything else.
+ if (this.resumePageIdx) {
+ return;
+ }
+
+ var offset = this.offset;
+ // Keep track of how many pages we should maximally iterate through.
+ this.pagesToSearch = numPages;
+ // If there's already a matchIdx that means we are iterating through a
+ // page's matches.
+ if (offset.matchIdx !== null) {
+ var numPageMatches = this.pageMatches[offset.pageIdx].length;
+ if ((!previous && offset.matchIdx + 1 < numPageMatches) ||
+ (previous && offset.matchIdx > 0)) {
+ // The simple case; we just have advance the matchIdx to select
+ // the next match on the page.
+ this.hadMatch = true;
+ offset.matchIdx = (previous ? offset.matchIdx - 1 :
+ offset.matchIdx + 1);
+ this.updateMatch(true);
+ return;
+ }
+ // We went beyond the current page's matches, so we advance to
+ // the next page.
+ this.advanceOffsetPage(previous);
+ }
+ // Start searching through the page.
+ this.nextPageMatch();
+ },
+
+ matchesReady: function PDFFindController_matchesReady(matches) {
var offset = this.offset;
var numMatches = matches.length;
var previous = this.state.findPrevious;
+
if (numMatches) {
// There were matches for the page, so initialize the matchIdx.
this.hadMatch = true;
- offset.matchIdx = previous ? numMatches - 1 : 0;
+ offset.matchIdx = (previous ? numMatches - 1 : 0);
this.updateMatch(true);
+ return true;
} else {
- // No matches attempt to search the next page.
+ // No matches, so attempt to search the next page.
this.advanceOffsetPage(previous);
if (offset.wrapped) {
offset.matchIdx = null;
- if (!this.hadMatch) {
- // No point in wrapping there were no matches.
+ if (this.pagesToSearch < 0) {
+ // No point in wrapping again, there were no matches.
this.updateMatch(false);
- return;
+ // while matches were not found, searching for a page
+ // with matches should nevertheless halt.
+ return true;
}
}
- // Search the next page.
- this.nextPageMatch();
+ // Matches were not found (and searching is not done).
+ return false;
}
- }.bind(this);
+ },
- var pageIdx = this.offset.pageIdx;
- var pageMatches = this.pageMatches;
- if (!pageMatches[pageIdx]) {
- // The matches aren't ready setup a callback so we can be notified,
- // when they are ready.
- this.resumeCallback = function() {
- matchesReady(pageMatches[pageIdx]);
- };
- this.resumePageIdx = pageIdx;
- return;
- }
- // The matches are finished already.
- matchesReady(pageMatches[pageIdx]);
- },
-
- advanceOffsetPage: function(previous) {
- var offset = this.offset;
- var numPages = this.extractTextPromises.length;
- offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1;
- offset.matchIdx = null;
- if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
- offset.pageIdx = previous ? numPages - 1 : 0;
- offset.wrapped = true;
- return;
- }
- },
-
- updateMatch: function(found) {
- var state = FindStates.FIND_NOTFOUND;
- var wrapped = this.offset.wrapped;
- this.offset.wrapped = false;
- if (found) {
- var previousPage = this.selected.pageIdx;
- this.selected.pageIdx = this.offset.pageIdx;
- this.selected.matchIdx = this.offset.matchIdx;
- state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND;
- // Update the currently selected page to wipe out any selected matches.
- if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
- this.updatePage(previousPage);
+ nextPageMatch: function PDFFindController_nextPageMatch() {
+ if (this.resumePageIdx !== null) {
+ console.error('There can only be one pending page.');
}
- }
- this.updateUIState(state, this.state.findPrevious);
- if (this.selected.pageIdx !== -1) {
- this.updatePage(this.selected.pageIdx, true);
- }
- },
+ do {
+ var pageIdx = this.offset.pageIdx;
+ var matches = this.pageMatches[pageIdx];
+ if (!matches) {
+ // The matches don't exist yet for processing by "matchesReady",
+ // so set a resume point for when they do exist.
+ this.resumePageIdx = pageIdx;
+ break;
+ }
+ } while (!this.matchesReady(matches));
+ },
- updateUIState: function(state, previous) {
- if (this.integratedFind) {
- FirefoxCom.request('updateFindControlState',
- {result: state, findPrevious: previous});
- return;
+ advanceOffsetPage: function PDFFindController_advanceOffsetPage(previous) {
+ var offset = this.offset;
+ var numPages = this.extractTextPromises.length;
+ offset.pageIdx = (previous ? offset.pageIdx - 1 : offset.pageIdx + 1);
+ offset.matchIdx = null;
+
+ this.pagesToSearch--;
+
+ if (offset.pageIdx >= numPages || offset.pageIdx < 0) {
+ offset.pageIdx = (previous ? numPages - 1 : 0);
+ offset.wrapped = true;
+ }
+ },
+
+ updateMatch: function PDFFindController_updateMatch(found) {
+ var state = FindStates.FIND_NOTFOUND;
+ var wrapped = this.offset.wrapped;
+ this.offset.wrapped = false;
+
+ if (found) {
+ var previousPage = this.selected.pageIdx;
+ this.selected.pageIdx = this.offset.pageIdx;
+ this.selected.matchIdx = this.offset.matchIdx;
+ state = (wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND);
+ // Update the currently selected page to wipe out any selected matches.
+ if (previousPage !== -1 && previousPage !== this.selected.pageIdx) {
+ this.updatePage(previousPage);
+ }
+ }
+
+ this.updateUIState(state, this.state.findPrevious);
+ if (this.selected.pageIdx !== -1) {
+ this.updatePage(this.selected.pageIdx);
+ }
+ },
+
+ updateUIState: function PDFFindController_updateUIState(state, previous) {
+ if (this.integratedFind) {
+ FirefoxCom.request('updateFindControlState',
+ { result: state, findPrevious: previous });
+ return;
+ }
+ if (this.findBar === null) {
+ throw new Error('PDFFindController is not initialized with a ' +
+ 'PDFFindBar instance.');
+ }
+ this.findBar.updateUIState(state, previous);
}
- PDFFindBar.updateUIState(state, previous);
- }
-};
+ };
+ return PDFFindController;
+})();
@@ -1208,12 +1380,11 @@ var PDFHistory = {
initialized: false,
initialDestination: null,
- initialize: function pdfHistoryInitialize(fingerprint) {
- if (PDFJS.disableHistory || PDFView.isViewerEmbedded) {
- // The browsing history is only enabled when the viewer is standalone,
- // i.e. not when it is embedded in a web page.
- return;
- }
+ /**
+ * @param {string} fingerprint
+ * @param {IPDFLinkService} linkService
+ */
+ initialize: function pdfHistoryInitialize(fingerprint, linkService) {
this.initialized = true;
this.reInitialized = false;
this.allowHashChange = true;
@@ -1228,6 +1399,7 @@ var PDFHistory = {
this.nextHashParam = '';
this.fingerprint = fingerprint;
+ this.linkService = linkService;
this.currentUid = this.uid = 0;
this.current = {};
@@ -1238,7 +1410,7 @@ var PDFHistory = {
if (state.target.dest) {
this.initialDestination = state.target.dest;
} else {
- PDFView.initialBookmark = state.target.hash;
+ linkService.setHash(state.target.hash);
}
this.currentUid = state.uid;
this.uid = state.uid + 1;
@@ -1376,7 +1548,7 @@ var PDFHistory = {
params.hash = (this.current.hash && this.current.dest &&
this.current.dest === params.dest) ?
this.current.hash :
- PDFView.getDestinationHash(params.dest).split('#')[1];
+ this.linkService.getDestinationHash(params.dest).split('#')[1];
}
if (params.page) {
params.page |= 0;
@@ -1385,7 +1557,7 @@ var PDFHistory = {
var target = window.history.state.target;
if (!target) {
// Invoked when the user specifies an initial bookmark,
- // thus setting PDFView.initialBookmark, when the document is loaded.
+ // thus setting initialBookmark, when the document is loaded.
this._pushToHistory(params, false);
this.previousHash = window.location.hash.substring(1);
}
@@ -1510,9 +1682,9 @@ var PDFHistory = {
this.historyUnlocked = false;
if (state.target.dest) {
- PDFView.navigateTo(state.target.dest);
+ this.linkService.navigateTo(state.target.dest);
} else {
- PDFView.setHash(state.target.hash);
+ this.linkService.setHash(state.target.hash);
}
this.currentUid = state.uid;
if (state.uid > this.uid) {
@@ -1559,6 +1731,7 @@ var SecondaryToolbar = {
initialize: function secondaryToolbarInitialize(options) {
this.toolbar = options.toolbar;
this.presentationMode = options.presentationMode;
+ this.documentProperties = options.documentProperties;
this.buttonContainer = this.toolbar.firstElementChild;
// Define the toolbar buttons.
@@ -1567,10 +1740,12 @@ var SecondaryToolbar = {
this.openFile = options.openFile;
this.print = options.print;
this.download = options.download;
+ this.viewBookmark = options.viewBookmark;
this.firstPage = options.firstPage;
this.lastPage = options.lastPage;
this.pageRotateCw = options.pageRotateCw;
this.pageRotateCcw = options.pageRotateCcw;
+ this.documentPropertiesButton = options.documentPropertiesButton;
// Attach the event listeners.
var elements = [
@@ -1583,10 +1758,13 @@ var SecondaryToolbar = {
{ element: this.openFile, handler: this.openFileClick },
{ element: this.print, handler: this.printClick },
{ element: this.download, handler: this.downloadClick },
+ { element: this.viewBookmark, handler: this.viewBookmarkClick },
{ element: this.firstPage, handler: this.firstPageClick },
{ element: this.lastPage, handler: this.lastPageClick },
{ element: this.pageRotateCw, handler: this.pageRotateCwClick },
- { element: this.pageRotateCcw, handler: this.pageRotateCcwClick }
+ { element: this.pageRotateCcw, handler: this.pageRotateCcwClick },
+ { element: this.documentPropertiesButton,
+ handler: this.documentPropertiesClick }
];
for (var item in elements) {
@@ -1605,33 +1783,46 @@ var SecondaryToolbar = {
openFileClick: function secondaryToolbarOpenFileClick(evt) {
document.getElementById('fileInput').click();
- this.close(evt.target);
+ this.close();
},
printClick: function secondaryToolbarPrintClick(evt) {
window.print();
- this.close(evt.target);
+ this.close();
},
downloadClick: function secondaryToolbarDownloadClick(evt) {
- PDFView.download();
- this.close(evt.target);
+ PDFViewerApplication.download();
+ this.close();
+ },
+
+ viewBookmarkClick: function secondaryToolbarViewBookmarkClick(evt) {
+ this.close();
},
firstPageClick: function secondaryToolbarFirstPageClick(evt) {
- PDFView.page = 1;
+ PDFViewerApplication.page = 1;
+ this.close();
},
lastPageClick: function secondaryToolbarLastPageClick(evt) {
- PDFView.page = PDFView.pdfDocument.numPages;
+ if (PDFViewerApplication.pdfDocument) {
+ PDFViewerApplication.page = PDFViewerApplication.pagesCount;
+ }
+ this.close();
},
pageRotateCwClick: function secondaryToolbarPageRotateCwClick(evt) {
- PDFView.rotatePages(90);
+ PDFViewerApplication.rotatePages(90);
},
pageRotateCcwClick: function secondaryToolbarPageRotateCcwClick(evt) {
- PDFView.rotatePages(-90);
+ PDFViewerApplication.rotatePages(-90);
+ },
+
+ documentPropertiesClick: function secondaryToolbarDocumentPropsClick(evt) {
+ this.documentProperties.open();
+ this.close();
},
// Misc. functions for interacting with the toolbar.
@@ -1678,84 +1869,9 @@ var SecondaryToolbar = {
};
-var PasswordPrompt = {
- visible: false,
- updatePassword: null,
- reason: null,
- overlayContainer: null,
- passwordField: null,
- passwordText: null,
- passwordSubmit: null,
- passwordCancel: null,
-
- initialize: function secondaryToolbarInitialize(options) {
- this.overlayContainer = options.overlayContainer;
- this.passwordField = options.passwordField;
- this.passwordText = options.passwordText;
- this.passwordSubmit = options.passwordSubmit;
- this.passwordCancel = options.passwordCancel;
-
- // Attach the event listeners.
- this.passwordSubmit.addEventListener('click',
- this.verifyPassword.bind(this));
-
- this.passwordCancel.addEventListener('click', this.hide.bind(this));
-
- this.passwordField.addEventListener('keydown',
- function (e) {
- if (e.keyCode === 13) { // Enter key
- this.verifyPassword();
- }
- }.bind(this));
-
- this.overlayContainer.addEventListener('keydown',
- function (e) {
- if (e.keyCode === 27) { // Esc key
- this.hide();
- }
- }.bind(this));
- },
-
- show: function passwordPromptShow() {
- if (this.visible) {
- return;
- }
- this.visible = true;
- this.overlayContainer.classList.remove('hidden');
- this.passwordField.focus();
-
- var promptString = mozL10n.get('password_label', null,
- 'Enter the password to open this PDF file.');
-
- if (this.reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
- promptString = mozL10n.get('password_invalid', null,
- 'Invalid password. Please try again.');
- }
-
- this.passwordText.textContent = promptString;
- },
-
- hide: function passwordPromptClose() {
- if (!this.visible) {
- return;
- }
- this.visible = false;
- this.passwordField.value = '';
- this.overlayContainer.classList.add('hidden');
- },
-
- verifyPassword: function passwordPromptVerifyPassword() {
- var password = this.passwordField.value;
- if (password && password.length > 0) {
- this.hide();
- return this.updatePassword(password);
- }
- }
-};
-
-
var DELAY_BEFORE_HIDING_CONTROLS = 3000; // in ms
var SELECTOR = 'presentationControls';
+var DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS = 1000; // in ms
var PresentationMode = {
active: false,
@@ -1800,11 +1916,38 @@ var PresentationMode = {
document.msFullscreenElement);
},
+ /**
+ * Initialize a timeout that is used to specify switchInProgress when the
+ * browser transitions to fullscreen mode. Since resize events are triggered
+ * multiple times during the switch to fullscreen mode, this is necessary in
+ * order to prevent the page from being scrolled partially, or completely,
+ * out of view when Presentation Mode is enabled.
+ * Note: This is only an issue at certain zoom levels, e.g. 'page-width'.
+ */
+ _setSwitchInProgress: function presentationMode_setSwitchInProgress() {
+ if (this.switchInProgress) {
+ clearTimeout(this.switchInProgress);
+ }
+ this.switchInProgress = setTimeout(function switchInProgressTimeout() {
+ delete this.switchInProgress;
+ this._notifyStateChange();
+ }.bind(this), DELAY_BEFORE_RESETTING_SWITCH_IN_PROGRESS);
+ },
+
+ _resetSwitchInProgress: function presentationMode_resetSwitchInProgress() {
+ if (this.switchInProgress) {
+ clearTimeout(this.switchInProgress);
+ delete this.switchInProgress;
+ }
+ },
+
request: function presentationModeRequest() {
- if (!PDFView.supportsFullscreen || this.isFullscreen ||
+ if (!PDFViewerApplication.supportsFullscreen || this.isFullscreen ||
!this.viewer.hasChildNodes()) {
return false;
}
+ this._setSwitchInProgress();
+ this._notifyStateChange();
if (this.container.requestFullscreen) {
this.container.requestFullscreen();
@@ -1819,18 +1962,34 @@ var PresentationMode = {
}
this.args = {
- page: PDFView.page,
- previousScale: PDFView.currentScaleValue
+ page: PDFViewerApplication.page,
+ previousScale: PDFViewerApplication.currentScaleValue
};
return true;
},
+ _notifyStateChange: function presentationModeNotifyStateChange() {
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('presentationmodechanged', true, true, {
+ active: PresentationMode.active,
+ switchInProgress: !!PresentationMode.switchInProgress
+ });
+ window.dispatchEvent(event);
+ },
+
enter: function presentationModeEnter() {
this.active = true;
+ this._resetSwitchInProgress();
+ this._notifyStateChange();
- PDFView.page = this.args.page;
- PDFView.setScale('page-fit', true);
+ // Ensure that the correct page is scrolled into view when entering
+ // Presentation Mode, by waiting until fullscreen mode in enabled.
+ // Note: This is only necessary in non-Mozilla browsers.
+ setTimeout(function enterPresentationModeTimeout() {
+ PDFViewerApplication.page = this.args.page;
+ PDFViewerApplication.setScale('page-fit', true);
+ }.bind(this), 0);
window.addEventListener('mousemove', this.mouseMove, false);
window.addEventListener('mousedown', this.mouseDown, false);
@@ -1843,19 +2002,26 @@ var PresentationMode = {
},
exit: function presentationModeExit() {
- this.active = false;
+ var page = PDFViewerApplication.page;
- var page = PDFView.page;
- PDFView.setScale(this.args.previousScale);
- PDFView.page = page;
+ // Ensure that the correct page is scrolled into view when exiting
+ // Presentation Mode, by waiting until fullscreen mode is disabled.
+ // Note: This is only necessary in non-Mozilla browsers.
+ setTimeout(function exitPresentationModeTimeout() {
+ this.active = false;
+ this._notifyStateChange();
+
+ PDFViewerApplication.setScale(this.args.previousScale, true);
+ PDFViewerApplication.page = page;
+ this.args = null;
+ }.bind(this), 0);
window.removeEventListener('mousemove', this.mouseMove, false);
window.removeEventListener('mousedown', this.mouseDown, false);
window.removeEventListener('contextmenu', this.contextMenu, false);
this.hideControls();
- this.args = null;
- PDFView.clearMouseScrollState();
+ PDFViewerApplication.clearMouseScrollState();
HandTool.exitPresentationMode();
this.container.removeAttribute('contextmenu');
this.contextMenuOpen = false;
@@ -1917,7 +2083,7 @@ var PresentationMode = {
if (!isInternalLink) {
// Unless an internal link was clicked, advance one page.
evt.preventDefault();
- PDFView.page += (evt.shiftKey ? -1 : 1);
+ PDFViewerApplication.page += (evt.shiftKey ? -1 : 1);
}
}
},
@@ -1987,16 +2153,17 @@ var GrabToPan = (function GrabToPanClosure() {
this._onmousedown = this._onmousedown.bind(this);
this._onmousemove = this._onmousemove.bind(this);
this._endPan = this._endPan.bind(this);
+
+ // This overlay will be inserted in the document when the mouse moves during
+ // a grab operation, to ensure that the cursor has the desired appearance.
+ var overlay = this.overlay = document.createElement('div');
+ overlay.className = 'grab-to-pan-grabbing';
}
GrabToPan.prototype = {
/**
* Class name of element which can be grabbed
*/
CSS_CLASS_GRAB: 'grab-to-pan-grab',
- /**
- * Class name of element which is being dragged & panned
- */
- CSS_CLASS_GRABBING: 'grab-to-pan-grabbing',
/**
* Bind a mousedown event to the element to enable grab-detection.
@@ -2079,8 +2246,12 @@ var GrabToPan = (function GrabToPanClosure() {
this.element.addEventListener('scroll', this._endPan, true);
event.preventDefault();
event.stopPropagation();
- this.element.classList.remove(this.CSS_CLASS_GRAB);
this.document.documentElement.classList.add(this.CSS_CLASS_GRABBING);
+
+ var focusedElement = document.activeElement;
+ if (focusedElement && !focusedElement.contains(event.target)) {
+ focusedElement.blur();
+ }
},
/**
@@ -2089,13 +2260,16 @@ var GrabToPan = (function GrabToPanClosure() {
_onmousemove: function GrabToPan__onmousemove(event) {
this.element.removeEventListener('scroll', this._endPan, true);
if (isLeftMouseReleased(event)) {
- this.document.removeEventListener('mousemove', this._onmousemove, true);
+ this._endPan();
return;
}
var xDiff = event.clientX - this.clientXStart;
var yDiff = event.clientY - this.clientYStart;
this.element.scrollTop = this.scrollTopStart - yDiff;
this.element.scrollLeft = this.scrollLeftStart - xDiff;
+ if (!this.overlay.parentNode) {
+ document.body.appendChild(this.overlay);
+ }
},
/**
@@ -2105,8 +2279,9 @@ var GrabToPan = (function GrabToPanClosure() {
this.element.removeEventListener('scroll', this._endPan, true);
this.document.removeEventListener('mousemove', this._onmousemove, true);
this.document.removeEventListener('mouseup', this._endPan, true);
- this.document.documentElement.classList.remove(this.CSS_CLASS_GRABBING);
- this.element.classList.add(this.CSS_CLASS_GRAB);
+ if (this.overlay.parentNode) {
+ this.overlay.parentNode.removeChild(this.overlay);
+ }
}
};
@@ -2180,13 +2355,21 @@ var HandTool = {
}
});
if (toggleHandTool) {
- toggleHandTool.addEventListener('click', this.handTool.toggle, false);
+ toggleHandTool.addEventListener('click', this.toggle.bind(this), false);
+
+ window.addEventListener('localized', function (evt) {
+ Preferences.get('enableHandToolOnLoad').then(function resolved(value) {
+ if (value) {
+ this.handTool.activate();
+ }
+ }.bind(this), function rejected(reason) {});
+ }.bind(this));
}
- // TODO: Read global prefs and call this.handTool.activate() if needed.
},
toggle: function handToolToggle() {
this.handTool.toggle();
+ SecondaryToolbar.close();
},
enterPresentationMode: function handToolEnterPresentationMode() {
@@ -2205,42 +2388,2269 @@ var HandTool = {
};
-var PDFView = {
- pages: [],
- thumbnails: [],
- currentScale: UNKNOWN_SCALE,
- currentScaleValue: null,
+var OverlayManager = {
+ overlays: {},
+ active: null,
+
+ /**
+ * @param {string} name The name of the overlay that is registered. This must
+ * be equal to the ID of the overlay's DOM element.
+ * @param {function} callerCloseMethod (optional) The method that, if present,
+ * will call OverlayManager.close from the Object
+ * registering the overlay. Access to this method is
+ * necessary in order to run cleanup code when e.g.
+ * the overlay is force closed. The default is null.
+ * @param {boolean} canForceClose (optional) Indicates if opening the overlay
+ * will close an active overlay. The default is false.
+ * @returns {Promise} A promise that is resolved when the overlay has been
+ * registered.
+ */
+ register: function overlayManagerRegister(name,
+ callerCloseMethod, canForceClose) {
+ return new Promise(function (resolve) {
+ var element, container;
+ if (!name || !(element = document.getElementById(name)) ||
+ !(container = element.parentNode)) {
+ throw new Error('Not enough parameters.');
+ } else if (this.overlays[name]) {
+ throw new Error('The overlay is already registered.');
+ }
+ this.overlays[name] = { element: element,
+ container: container,
+ callerCloseMethod: (callerCloseMethod || null),
+ canForceClose: (canForceClose || false) };
+ resolve();
+ }.bind(this));
+ },
+
+ /**
+ * @param {string} name The name of the overlay that is unregistered.
+ * @returns {Promise} A promise that is resolved when the overlay has been
+ * unregistered.
+ */
+ unregister: function overlayManagerUnregister(name) {
+ return new Promise(function (resolve) {
+ if (!this.overlays[name]) {
+ throw new Error('The overlay does not exist.');
+ } else if (this.active === name) {
+ throw new Error('The overlay cannot be removed while it is active.');
+ }
+ delete this.overlays[name];
+
+ resolve();
+ }.bind(this));
+ },
+
+ /**
+ * @param {string} name The name of the overlay that should be opened.
+ * @returns {Promise} A promise that is resolved when the overlay has been
+ * opened.
+ */
+ open: function overlayManagerOpen(name) {
+ return new Promise(function (resolve) {
+ if (!this.overlays[name]) {
+ throw new Error('The overlay does not exist.');
+ } else if (this.active) {
+ if (this.overlays[name].canForceClose) {
+ this._closeThroughCaller();
+ } else if (this.active === name) {
+ throw new Error('The overlay is already active.');
+ } else {
+ throw new Error('Another overlay is currently active.');
+ }
+ }
+ this.active = name;
+ this.overlays[this.active].element.classList.remove('hidden');
+ this.overlays[this.active].container.classList.remove('hidden');
+
+ window.addEventListener('keydown', this._keyDown);
+ resolve();
+ }.bind(this));
+ },
+
+ /**
+ * @param {string} name The name of the overlay that should be closed.
+ * @returns {Promise} A promise that is resolved when the overlay has been
+ * closed.
+ */
+ close: function overlayManagerClose(name) {
+ return new Promise(function (resolve) {
+ if (!this.overlays[name]) {
+ throw new Error('The overlay does not exist.');
+ } else if (!this.active) {
+ throw new Error('The overlay is currently not active.');
+ } else if (this.active !== name) {
+ throw new Error('Another overlay is currently active.');
+ }
+ this.overlays[this.active].container.classList.add('hidden');
+ this.overlays[this.active].element.classList.add('hidden');
+ this.active = null;
+
+ window.removeEventListener('keydown', this._keyDown);
+ resolve();
+ }.bind(this));
+ },
+
+ /**
+ * @private
+ */
+ _keyDown: function overlayManager_keyDown(evt) {
+ var self = OverlayManager;
+ if (self.active && evt.keyCode === 27) { // Esc key.
+ self._closeThroughCaller();
+ evt.preventDefault();
+ }
+ },
+
+ /**
+ * @private
+ */
+ _closeThroughCaller: function overlayManager_closeThroughCaller() {
+ if (this.overlays[this.active].callerCloseMethod) {
+ this.overlays[this.active].callerCloseMethod();
+ }
+ if (this.active) {
+ this.close(this.active);
+ }
+ }
+};
+
+
+var PasswordPrompt = {
+ overlayName: null,
+ updatePassword: null,
+ reason: null,
+ passwordField: null,
+ passwordText: null,
+ passwordSubmit: null,
+ passwordCancel: null,
+
+ initialize: function secondaryToolbarInitialize(options) {
+ this.overlayName = options.overlayName;
+ this.passwordField = options.passwordField;
+ this.passwordText = options.passwordText;
+ this.passwordSubmit = options.passwordSubmit;
+ this.passwordCancel = options.passwordCancel;
+
+ // Attach the event listeners.
+ this.passwordSubmit.addEventListener('click',
+ this.verifyPassword.bind(this));
+
+ this.passwordCancel.addEventListener('click', this.close.bind(this));
+
+ this.passwordField.addEventListener('keydown', function (e) {
+ if (e.keyCode === 13) { // Enter key
+ this.verifyPassword();
+ }
+ }.bind(this));
+
+ OverlayManager.register(this.overlayName, this.close.bind(this), true);
+ },
+
+ open: function passwordPromptOpen() {
+ OverlayManager.open(this.overlayName).then(function () {
+ this.passwordField.focus();
+
+ var promptString = mozL10n.get('password_label', null,
+ 'Enter the password to open this PDF file.');
+
+ if (this.reason === PDFJS.PasswordResponses.INCORRECT_PASSWORD) {
+ promptString = mozL10n.get('password_invalid', null,
+ 'Invalid password. Please try again.');
+ }
+
+ this.passwordText.textContent = promptString;
+ }.bind(this));
+ },
+
+ close: function passwordPromptClose() {
+ OverlayManager.close(this.overlayName).then(function () {
+ this.passwordField.value = '';
+ }.bind(this));
+ },
+
+ verifyPassword: function passwordPromptVerifyPassword() {
+ var password = this.passwordField.value;
+ if (password && password.length > 0) {
+ this.close();
+ return this.updatePassword(password);
+ }
+ }
+};
+
+
+var DocumentProperties = {
+ overlayName: null,
+ rawFileSize: 0,
+
+ // Document property fields (in the viewer).
+ fileNameField: null,
+ fileSizeField: null,
+ titleField: null,
+ authorField: null,
+ subjectField: null,
+ keywordsField: null,
+ creationDateField: null,
+ modificationDateField: null,
+ creatorField: null,
+ producerField: null,
+ versionField: null,
+ pageCountField: null,
+ url: null,
+ pdfDocument: null,
+
+ initialize: function documentPropertiesInitialize(options) {
+ this.overlayName = options.overlayName;
+
+ // Set the document property fields.
+ this.fileNameField = options.fileNameField;
+ this.fileSizeField = options.fileSizeField;
+ this.titleField = options.titleField;
+ this.authorField = options.authorField;
+ this.subjectField = options.subjectField;
+ this.keywordsField = options.keywordsField;
+ this.creationDateField = options.creationDateField;
+ this.modificationDateField = options.modificationDateField;
+ this.creatorField = options.creatorField;
+ this.producerField = options.producerField;
+ this.versionField = options.versionField;
+ this.pageCountField = options.pageCountField;
+
+ // Bind the event listener for the Close button.
+ if (options.closeButton) {
+ options.closeButton.addEventListener('click', this.close.bind(this));
+ }
+
+ this.dataAvailablePromise = new Promise(function (resolve) {
+ this.resolveDataAvailable = resolve;
+ }.bind(this));
+
+ OverlayManager.register(this.overlayName, this.close.bind(this));
+ },
+
+ getProperties: function documentPropertiesGetProperties() {
+ if (!OverlayManager.active) {
+ // If the dialog was closed before dataAvailablePromise was resolved,
+ // don't bother updating the properties.
+ return;
+ }
+ // Get the file size (if it hasn't already been set).
+ this.pdfDocument.getDownloadInfo().then(function(data) {
+ if (data.length === this.rawFileSize) {
+ return;
+ }
+ this.setFileSize(data.length);
+ this.updateUI(this.fileSizeField, this.parseFileSize());
+ }.bind(this));
+
+ // Get the document properties.
+ this.pdfDocument.getMetadata().then(function(data) {
+ var fields = [
+ { field: this.fileNameField,
+ content: getPDFFileNameFromURL(this.url) },
+ { field: this.fileSizeField, content: this.parseFileSize() },
+ { field: this.titleField, content: data.info.Title },
+ { field: this.authorField, content: data.info.Author },
+ { field: this.subjectField, content: data.info.Subject },
+ { field: this.keywordsField, content: data.info.Keywords },
+ { field: this.creationDateField,
+ content: this.parseDate(data.info.CreationDate) },
+ { field: this.modificationDateField,
+ content: this.parseDate(data.info.ModDate) },
+ { field: this.creatorField, content: data.info.Creator },
+ { field: this.producerField, content: data.info.Producer },
+ { field: this.versionField, content: data.info.PDFFormatVersion },
+ { field: this.pageCountField, content: this.pdfDocument.numPages }
+ ];
+
+ // Show the properties in the dialog.
+ for (var item in fields) {
+ var element = fields[item];
+ this.updateUI(element.field, element.content);
+ }
+ }.bind(this));
+ },
+
+ updateUI: function documentPropertiesUpdateUI(field, content) {
+ if (field && content !== undefined && content !== '') {
+ field.textContent = content;
+ }
+ },
+
+ setFileSize: function documentPropertiesSetFileSize(fileSize) {
+ if (fileSize > 0) {
+ this.rawFileSize = fileSize;
+ }
+ },
+
+ parseFileSize: function documentPropertiesParseFileSize() {
+ var fileSize = this.rawFileSize, kb = fileSize / 1024;
+ if (!kb) {
+ return;
+ } else if (kb < 1024) {
+ return mozL10n.get('document_properties_kb', {
+ size_kb: (+kb.toPrecision(3)).toLocaleString(),
+ size_b: fileSize.toLocaleString()
+ }, '{{size_kb}} KB ({{size_b}} bytes)');
+ } else {
+ return mozL10n.get('document_properties_mb', {
+ size_mb: (+(kb / 1024).toPrecision(3)).toLocaleString(),
+ size_b: fileSize.toLocaleString()
+ }, '{{size_mb}} MB ({{size_b}} bytes)');
+ }
+ },
+
+ open: function documentPropertiesOpen() {
+ Promise.all([OverlayManager.open(this.overlayName),
+ this.dataAvailablePromise]).then(function () {
+ this.getProperties();
+ }.bind(this));
+ },
+
+ close: function documentPropertiesClose() {
+ OverlayManager.close(this.overlayName);
+ },
+
+ parseDate: function documentPropertiesParseDate(inputDate) {
+ // This is implemented according to the PDF specification (see
+ // http://www.gnupdf.org/Date for an overview), but note that
+ // Adobe Reader doesn't handle changing the date to universal time
+ // and doesn't use the user's time zone (they're effectively ignoring
+ // the HH' and mm' parts of the date string).
+ var dateToParse = inputDate;
+ if (dateToParse === undefined) {
+ return '';
+ }
+
+ // Remove the D: prefix if it is available.
+ if (dateToParse.substring(0,2) === 'D:') {
+ dateToParse = dateToParse.substring(2);
+ }
+
+ // Get all elements from the PDF date string.
+ // JavaScript's Date object expects the month to be between
+ // 0 and 11 instead of 1 and 12, so we're correcting for this.
+ var year = parseInt(dateToParse.substring(0,4), 10);
+ var month = parseInt(dateToParse.substring(4,6), 10) - 1;
+ var day = parseInt(dateToParse.substring(6,8), 10);
+ var hours = parseInt(dateToParse.substring(8,10), 10);
+ var minutes = parseInt(dateToParse.substring(10,12), 10);
+ var seconds = parseInt(dateToParse.substring(12,14), 10);
+ var utRel = dateToParse.substring(14,15);
+ var offsetHours = parseInt(dateToParse.substring(15,17), 10);
+ var offsetMinutes = parseInt(dateToParse.substring(18,20), 10);
+
+ // As per spec, utRel = 'Z' means equal to universal time.
+ // The other cases ('-' and '+') have to be handled here.
+ if (utRel === '-') {
+ hours += offsetHours;
+ minutes += offsetMinutes;
+ } else if (utRel === '+') {
+ hours -= offsetHours;
+ minutes -= offsetMinutes;
+ }
+
+ // Return the new date format from the user's locale.
+ var date = new Date(Date.UTC(year, month, day, hours, minutes, seconds));
+ var dateString = date.toLocaleDateString();
+ var timeString = date.toLocaleTimeString();
+ return mozL10n.get('document_properties_date_string',
+ {date: dateString, time: timeString},
+ '{{date}}, {{time}}');
+ }
+};
+
+
+var PresentationModeState = {
+ UNKNOWN: 0,
+ NORMAL: 1,
+ CHANGING: 2,
+ FULLSCREEN: 3,
+};
+
+var IGNORE_CURRENT_POSITION_ON_ZOOM = false;
+
+
+var CLEANUP_TIMEOUT = 30000;
+
+var RenderingStates = {
+ INITIAL: 0,
+ RUNNING: 1,
+ PAUSED: 2,
+ FINISHED: 3
+};
+
+/**
+ * Controls rendering of the views for pages and thumbnails.
+ * @class
+ */
+var PDFRenderingQueue = (function PDFRenderingQueueClosure() {
+ /**
+ * @constructs
+ */
+ function PDFRenderingQueue() {
+ this.pdfViewer = null;
+ this.pdfThumbnailViewer = null;
+ this.onIdle = null;
+
+ this.highestPriorityPage = null;
+ this.idleTimeout = null;
+ this.printing = false;
+ this.isThumbnailViewEnabled = false;
+ }
+
+ PDFRenderingQueue.prototype = /** @lends PDFRenderingQueue.prototype */ {
+ /**
+ * @param {PDFViewer} pdfViewer
+ */
+ setViewer: function PDFRenderingQueue_setViewer(pdfViewer) {
+ this.pdfViewer = pdfViewer;
+ },
+
+ /**
+ * @param {PDFThumbnailViewer} pdfThumbnailViewer
+ */
+ setThumbnailViewer:
+ function PDFRenderingQueue_setThumbnailViewer(pdfThumbnailViewer) {
+ this.pdfThumbnailViewer = pdfThumbnailViewer;
+ },
+
+ /**
+ * @param {IRenderableView} view
+ * @returns {boolean}
+ */
+ isHighestPriority: function PDFRenderingQueue_isHighestPriority(view) {
+ return this.highestPriorityPage === view.renderingId;
+ },
+
+ renderHighestPriority: function
+ PDFRenderingQueue_renderHighestPriority(currentlyVisiblePages) {
+ if (this.idleTimeout) {
+ clearTimeout(this.idleTimeout);
+ this.idleTimeout = null;
+ }
+
+ // Pages have a higher priority than thumbnails, so check them first.
+ if (this.pdfViewer.forceRendering(currentlyVisiblePages)) {
+ return;
+ }
+ // No pages needed rendering so check thumbnails.
+ if (this.pdfThumbnailViewer && this.isThumbnailViewEnabled) {
+ if (this.pdfThumbnailViewer.forceRendering()) {
+ return;
+ }
+ }
+
+ if (this.printing) {
+ // If printing is currently ongoing do not reschedule cleanup.
+ return;
+ }
+
+ if (this.onIdle) {
+ this.idleTimeout = setTimeout(this.onIdle.bind(this), CLEANUP_TIMEOUT);
+ }
+ },
+
+ getHighestPriority: function
+ PDFRenderingQueue_getHighestPriority(visible, views, scrolledDown) {
+ // The state has changed figure out which page has the highest priority to
+ // render next (if any).
+ // Priority:
+ // 1 visible pages
+ // 2 if last scrolled down page after the visible pages
+ // 2 if last scrolled up page before the visible pages
+ var visibleViews = visible.views;
+
+ var numVisible = visibleViews.length;
+ if (numVisible === 0) {
+ return false;
+ }
+ for (var i = 0; i < numVisible; ++i) {
+ var view = visibleViews[i].view;
+ if (!this.isViewFinished(view)) {
+ return view;
+ }
+ }
+
+ // All the visible views have rendered, try to render next/previous pages.
+ if (scrolledDown) {
+ var nextPageIndex = visible.last.id;
+ // ID's start at 1 so no need to add 1.
+ if (views[nextPageIndex] &&
+ !this.isViewFinished(views[nextPageIndex])) {
+ return views[nextPageIndex];
+ }
+ } else {
+ var previousPageIndex = visible.first.id - 2;
+ if (views[previousPageIndex] &&
+ !this.isViewFinished(views[previousPageIndex])) {
+ return views[previousPageIndex];
+ }
+ }
+ // Everything that needs to be rendered has been.
+ return null;
+ },
+
+ /**
+ * @param {IRenderableView} view
+ * @returns {boolean}
+ */
+ isViewFinished: function PDFRenderingQueue_isViewFinished(view) {
+ return view.renderingState === RenderingStates.FINISHED;
+ },
+
+ /**
+ * Render a page or thumbnail view. This calls the appropriate function
+ * based on the views state. If the view is already rendered it will return
+ * false.
+ * @param {IRenderableView} view
+ */
+ renderView: function PDFRenderingQueue_renderView(view) {
+ var state = view.renderingState;
+ switch (state) {
+ case RenderingStates.FINISHED:
+ return false;
+ case RenderingStates.PAUSED:
+ this.highestPriorityPage = view.renderingId;
+ view.resume();
+ break;
+ case RenderingStates.RUNNING:
+ this.highestPriorityPage = view.renderingId;
+ break;
+ case RenderingStates.INITIAL:
+ this.highestPriorityPage = view.renderingId;
+ view.draw(this.renderHighestPriority.bind(this));
+ break;
+ }
+ return true;
+ },
+ };
+
+ return PDFRenderingQueue;
+})();
+
+
+/**
+ * @constructor
+ * @param {HTMLDivElement} container - The viewer element.
+ * @param {number} id - The page unique ID (normally its number).
+ * @param {number} scale - The page scale display.
+ * @param {PageViewport} defaultViewport - The page viewport.
+ * @param {IPDFLinkService} linkService - The navigation/linking service.
+ * @param {PDFRenderingQueue} renderingQueue - The rendering queue object.
+ * @param {Cache} cache - The page cache.
+ * @param {PDFPageSource} pageSource
+ * @param {PDFViewer} viewer
+ *
+ * @implements {IRenderableView}
+ */
+var PageView = function pageView(container, id, scale, defaultViewport,
+ linkService, renderingQueue, cache,
+ pageSource, viewer) {
+ this.id = id;
+ this.renderingId = 'page' + id;
+
+ this.rotation = 0;
+ this.scale = scale || 1.0;
+ this.viewport = defaultViewport;
+ this.pdfPageRotate = defaultViewport.rotation;
+ this.hasRestrictedScaling = false;
+
+ this.linkService = linkService;
+ this.renderingQueue = renderingQueue;
+ this.cache = cache;
+ this.pageSource = pageSource;
+ this.viewer = viewer;
+
+ this.renderingState = RenderingStates.INITIAL;
+ this.resume = null;
+
+ this.textLayer = null;
+
+ this.zoomLayer = null;
+
+ this.annotationLayer = null;
+
+ var anchor = document.createElement('a');
+ anchor.name = '' + this.id;
+
+ var div = this.el = document.createElement('div');
+ div.id = 'pageContainer' + this.id;
+ div.className = 'page';
+ div.style.width = Math.floor(this.viewport.width) + 'px';
+ div.style.height = Math.floor(this.viewport.height) + 'px';
+
+ container.appendChild(anchor);
+ container.appendChild(div);
+
+ this.setPdfPage = function pageViewSetPdfPage(pdfPage) {
+ this.pdfPage = pdfPage;
+ this.pdfPageRotate = pdfPage.rotate;
+ var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = pdfPage.getViewport(this.scale * CSS_UNITS, totalRotation);
+ this.stats = pdfPage.stats;
+ this.reset();
+ };
+
+ this.destroy = function pageViewDestroy() {
+ this.zoomLayer = null;
+ this.reset();
+ if (this.pdfPage) {
+ this.pdfPage.destroy();
+ }
+ };
+
+ this.reset = function pageViewReset(keepAnnotations) {
+ if (this.renderTask) {
+ this.renderTask.cancel();
+ }
+ this.resume = null;
+ this.renderingState = RenderingStates.INITIAL;
+
+ div.style.width = Math.floor(this.viewport.width) + 'px';
+ div.style.height = Math.floor(this.viewport.height) + 'px';
+
+ var childNodes = div.childNodes;
+ for (var i = div.childNodes.length - 1; i >= 0; i--) {
+ var node = childNodes[i];
+ if ((this.zoomLayer && this.zoomLayer === node) ||
+ (keepAnnotations && this.annotationLayer === node)) {
+ continue;
+ }
+ div.removeChild(node);
+ }
+ div.removeAttribute('data-loaded');
+
+ if (keepAnnotations) {
+ if (this.annotationLayer) {
+ // Hide annotationLayer until all elements are resized
+ // so they are not displayed on the already-resized page
+ this.annotationLayer.setAttribute('hidden', 'true');
+ }
+ } else {
+ this.annotationLayer = null;
+ }
+
+ if (this.canvas) {
+ // Zeroing the width and height causes Firefox to release graphics
+ // resources immediately, which can greatly reduce memory consumption.
+ this.canvas.width = 0;
+ this.canvas.height = 0;
+ delete this.canvas;
+ }
+
+ this.loadingIconDiv = document.createElement('div');
+ this.loadingIconDiv.className = 'loadingIcon';
+ div.appendChild(this.loadingIconDiv);
+ };
+
+ this.update = function pageViewUpdate(scale, rotation) {
+ this.scale = scale || this.scale;
+
+ if (typeof rotation !== 'undefined') {
+ this.rotation = rotation;
+ }
+
+ var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
+ this.viewport = this.viewport.clone({
+ scale: this.scale * CSS_UNITS,
+ rotation: totalRotation
+ });
+
+ var isScalingRestricted = false;
+ if (this.canvas && PDFJS.maxCanvasPixels > 0) {
+ var ctx = this.canvas.getContext('2d');
+ var outputScale = getOutputScale(ctx);
+ var pixelsInViewport = this.viewport.width * this.viewport.height;
+ var maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);
+ if (((Math.floor(this.viewport.width) * outputScale.sx) | 0) *
+ ((Math.floor(this.viewport.height) * outputScale.sy) | 0) >
+ PDFJS.maxCanvasPixels) {
+ isScalingRestricted = true;
+ }
+ }
+
+ if (this.canvas &&
+ (PDFJS.useOnlyCssZoom ||
+ (this.hasRestrictedScaling && isScalingRestricted))) {
+ this.cssTransform(this.canvas, true);
+ return;
+ } else if (this.canvas && !this.zoomLayer) {
+ this.zoomLayer = this.canvas.parentNode;
+ this.zoomLayer.style.position = 'absolute';
+ }
+ if (this.zoomLayer) {
+ this.cssTransform(this.zoomLayer.firstChild);
+ }
+ this.reset(true);
+ };
+
+ this.cssTransform = function pageCssTransform(canvas, redrawAnnotations) {
+ // Scale canvas, canvas wrapper, and page container.
+ var width = this.viewport.width;
+ var height = this.viewport.height;
+ canvas.style.width = canvas.parentNode.style.width = div.style.width =
+ Math.floor(width) + 'px';
+ canvas.style.height = canvas.parentNode.style.height = div.style.height =
+ Math.floor(height) + 'px';
+ // The canvas may have been originally rotated, so rotate relative to that.
+ var relativeRotation = this.viewport.rotation - canvas._viewport.rotation;
+ var absRotation = Math.abs(relativeRotation);
+ var scaleX = 1, scaleY = 1;
+ if (absRotation === 90 || absRotation === 270) {
+ // Scale x and y because of the rotation.
+ scaleX = height / width;
+ scaleY = width / height;
+ }
+ var cssTransform = 'rotate(' + relativeRotation + 'deg) ' +
+ 'scale(' + scaleX + ',' + scaleY + ')';
+ CustomStyle.setProp('transform', canvas, cssTransform);
+
+ if (this.textLayer) {
+ // Rotating the text layer is more complicated since the divs inside the
+ // the text layer are rotated.
+ // TODO: This could probably be simplified by drawing the text layer in
+ // one orientation then rotating overall.
+ var textLayerViewport = this.textLayer.viewport;
+ var textRelativeRotation = this.viewport.rotation -
+ textLayerViewport.rotation;
+ var textAbsRotation = Math.abs(textRelativeRotation);
+ var scale = width / textLayerViewport.width;
+ if (textAbsRotation === 90 || textAbsRotation === 270) {
+ scale = width / textLayerViewport.height;
+ }
+ var textLayerDiv = this.textLayer.textLayerDiv;
+ var transX, transY;
+ switch (textAbsRotation) {
+ case 0:
+ transX = transY = 0;
+ break;
+ case 90:
+ transX = 0;
+ transY = '-' + textLayerDiv.style.height;
+ break;
+ case 180:
+ transX = '-' + textLayerDiv.style.width;
+ transY = '-' + textLayerDiv.style.height;
+ break;
+ case 270:
+ transX = '-' + textLayerDiv.style.width;
+ transY = 0;
+ break;
+ default:
+ console.error('Bad rotation value.');
+ break;
+ }
+ CustomStyle.setProp('transform', textLayerDiv,
+ 'rotate(' + textAbsRotation + 'deg) ' +
+ 'scale(' + scale + ', ' + scale + ') ' +
+ 'translate(' + transX + ', ' + transY + ')');
+ CustomStyle.setProp('transformOrigin', textLayerDiv, '0% 0%');
+ }
+
+ if (redrawAnnotations && this.annotationLayer) {
+ setupAnnotations(div, this.pdfPage, this.viewport);
+ }
+ };
+
+ Object.defineProperty(this, 'width', {
+ get: function PageView_getWidth() {
+ return this.viewport.width;
+ },
+ enumerable: true
+ });
+
+ Object.defineProperty(this, 'height', {
+ get: function PageView_getHeight() {
+ return this.viewport.height;
+ },
+ enumerable: true
+ });
+
+ var self = this;
+
+ function setupAnnotations(pageDiv, pdfPage, viewport) {
+
+ function bindLink(link, dest) {
+ link.href = linkService.getDestinationHash(dest);
+ link.onclick = function pageViewSetupLinksOnclick() {
+ if (dest) {
+ linkService.navigateTo(dest);
+ }
+ return false;
+ };
+ if (dest) {
+ link.className = 'internalLink';
+ }
+ }
+
+ function bindNamedAction(link, action) {
+ link.href = linkService.getAnchorUrl('');
+ link.onclick = function pageViewSetupNamedActionOnClick() {
+ linkService.executeNamedAction(action);
+ return false;
+ };
+ link.className = 'internalLink';
+ }
+
+ pdfPage.getAnnotations().then(function(annotationsData) {
+ viewport = viewport.clone({ dontFlip: true });
+ var transform = viewport.transform;
+ var transformStr = 'matrix(' + transform.join(',') + ')';
+ var data, element, i, ii;
+
+ if (self.annotationLayer) {
+ // If an annotationLayer already exists, refresh its children's
+ // transformation matrices
+ for (i = 0, ii = annotationsData.length; i < ii; i++) {
+ data = annotationsData[i];
+ element = self.annotationLayer.querySelector(
+ '[data-annotation-id="' + data.id + '"]');
+ if (element) {
+ CustomStyle.setProp('transform', element, transformStr);
+ }
+ }
+ // See this.reset()
+ self.annotationLayer.removeAttribute('hidden');
+ } else {
+ for (i = 0, ii = annotationsData.length; i < ii; i++) {
+ data = annotationsData[i];
+ if (!data || !data.hasHtml) {
+ continue;
+ }
+
+ element = PDFJS.AnnotationUtils.getHtmlElement(data,
+ pdfPage.commonObjs);
+ element.setAttribute('data-annotation-id', data.id);
+ mozL10n.translate(element);
+
+ var rect = data.rect;
+ var view = pdfPage.view;
+ rect = PDFJS.Util.normalizeRect([
+ rect[0],
+ view[3] - rect[1] + view[1],
+ rect[2],
+ view[3] - rect[3] + view[1]
+ ]);
+ element.style.left = rect[0] + 'px';
+ element.style.top = rect[1] + 'px';
+ element.style.position = 'absolute';
+
+ CustomStyle.setProp('transform', element, transformStr);
+ var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
+ CustomStyle.setProp('transformOrigin', element, transformOriginStr);
+
+ if (data.subtype === 'Link' && !data.url) {
+ var link = element.getElementsByTagName('a')[0];
+ if (link) {
+ if (data.action) {
+ bindNamedAction(link, data.action);
+ } else {
+ bindLink(link, ('dest' in data) ? data.dest : null);
+ }
+ }
+ }
+
+ if (!self.annotationLayer) {
+ var annotationLayerDiv = document.createElement('div');
+ annotationLayerDiv.className = 'annotationLayer';
+ pageDiv.appendChild(annotationLayerDiv);
+ self.annotationLayer = annotationLayerDiv;
+ }
+
+ self.annotationLayer.appendChild(element);
+ }
+ }
+ });
+ }
+
+ this.getPagePoint = function pageViewGetPagePoint(x, y) {
+ return this.viewport.convertToPdfPoint(x, y);
+ };
+
+ this.draw = function pageviewDraw(callback) {
+ var pdfPage = this.pdfPage;
+
+ if (this.pagePdfPromise) {
+ return;
+ }
+ if (!pdfPage) {
+ var promise = this.pageSource.getPage();
+ promise.then(function(pdfPage) {
+ delete this.pagePdfPromise;
+ this.setPdfPage(pdfPage);
+ this.draw(callback);
+ }.bind(this));
+ this.pagePdfPromise = promise;
+ return;
+ }
+
+ if (this.renderingState !== RenderingStates.INITIAL) {
+ console.error('Must be in new state before drawing');
+ }
+
+ this.renderingState = RenderingStates.RUNNING;
+
+ var viewport = this.viewport;
+ // Wrap the canvas so if it has a css transform for highdpi the overflow
+ // will be hidden in FF.
+ var canvasWrapper = document.createElement('div');
+ canvasWrapper.style.width = div.style.width;
+ canvasWrapper.style.height = div.style.height;
+ canvasWrapper.classList.add('canvasWrapper');
+
+ var canvas = document.createElement('canvas');
+ canvas.id = 'page' + this.id;
+ canvasWrapper.appendChild(canvas);
+ if (this.annotationLayer) {
+ // annotationLayer needs to stay on top
+ div.insertBefore(canvasWrapper, this.annotationLayer);
+ } else {
+ div.appendChild(canvasWrapper);
+ }
+ this.canvas = canvas;
+
+ var ctx = canvas.getContext('2d');
+ var outputScale = getOutputScale(ctx);
+
+ if (PDFJS.useOnlyCssZoom) {
+ var actualSizeViewport = viewport.clone({ scale: CSS_UNITS });
+ // Use a scale that will make the canvas be the original intended size
+ // of the page.
+ outputScale.sx *= actualSizeViewport.width / viewport.width;
+ outputScale.sy *= actualSizeViewport.height / viewport.height;
+ outputScale.scaled = true;
+ }
+
+ if (PDFJS.maxCanvasPixels > 0) {
+ var pixelsInViewport = viewport.width * viewport.height;
+ var maxScale = Math.sqrt(PDFJS.maxCanvasPixels / pixelsInViewport);
+ if (outputScale.sx > maxScale || outputScale.sy > maxScale) {
+ outputScale.sx = maxScale;
+ outputScale.sy = maxScale;
+ outputScale.scaled = true;
+ this.hasRestrictedScaling = true;
+ } else {
+ this.hasRestrictedScaling = false;
+ }
+ }
+
+ canvas.width = (Math.floor(viewport.width) * outputScale.sx) | 0;
+ canvas.height = (Math.floor(viewport.height) * outputScale.sy) | 0;
+ canvas.style.width = Math.floor(viewport.width) + 'px';
+ canvas.style.height = Math.floor(viewport.height) + 'px';
+ // Add the viewport so it's known what it was originally drawn with.
+ canvas._viewport = viewport;
+
+ var textLayerDiv = null;
+ var textLayer = null;
+ if (!PDFJS.disableTextLayer) {
+ textLayerDiv = document.createElement('div');
+ textLayerDiv.className = 'textLayer';
+ textLayerDiv.style.width = canvas.style.width;
+ textLayerDiv.style.height = canvas.style.height;
+ if (this.annotationLayer) {
+ // annotationLayer needs to stay on top
+ div.insertBefore(textLayerDiv, this.annotationLayer);
+ } else {
+ div.appendChild(textLayerDiv);
+ }
+
+ textLayer = this.viewer.createTextLayerBuilder(textLayerDiv, this.id - 1,
+ this.viewport);
+ }
+ this.textLayer = textLayer;
+
+ var imageLayerDiv = document.createElement('div');
+ imageLayerDiv.className = 'imageLayer';
+ div.appendChild(imageLayerDiv);
+
+ var imageLayer = getVideoOverlay(this.id);
+ if(imageLayer) {
+ imageLayer.div = imageLayerDiv;
+ }
+
+ // TODO(mack): use data attributes to store these
+ ctx._scaleX = outputScale.sx;
+ ctx._scaleY = outputScale.sy;
+ if (outputScale.scaled) {
+ ctx.scale(outputScale.sx, outputScale.sy);
+ }
+
+ // Rendering area
+
+ var self = this;
+ function pageViewDrawCallback(error) {
+ // The renderTask may have been replaced by a new one, so only remove the
+ // reference to the renderTask if it matches the one that is triggering
+ // this callback.
+ if (renderTask === self.renderTask) {
+ self.renderTask = null;
+ }
+
+ if (error === 'cancelled') {
+ return;
+ }
+
+ self.renderingState = RenderingStates.FINISHED;
+
+ if (self.loadingIconDiv) {
+ div.removeChild(self.loadingIconDiv);
+ delete self.loadingIconDiv;
+ }
+
+ if (self.zoomLayer) {
+ div.removeChild(self.zoomLayer);
+ self.zoomLayer = null;
+ }
+
+ self.error = error;
+ self.stats = pdfPage.stats;
+ self.updateStats();
+ if (self.onAfterDraw) {
+ self.onAfterDraw();
+ }
+
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('pagerender', true, true, {
+ pageNumber: pdfPage.pageNumber
+ });
+ div.dispatchEvent(event);
+
+ callback();
+ }
+
+ var renderContext = {
+ canvasContext: ctx,
+ viewport: this.viewport,
+ imageLayer: imageLayer,
+ // intent: 'default', // === 'display'
+ continueCallback: function pdfViewcContinueCallback(cont) {
+ if (!self.renderingQueue.isHighestPriority(self)) {
+ self.renderingState = RenderingStates.PAUSED;
+ self.resume = function resumeCallback() {
+ self.renderingState = RenderingStates.RUNNING;
+ cont();
+ };
+ return;
+ }
+ cont();
+ }
+ };
+ var renderTask = this.renderTask = this.pdfPage.render(renderContext);
+
+ this.renderTask.promise.then(
+ function pdfPageRenderCallback() {
+ pageViewDrawCallback(null);
+ if (textLayer) {
+ self.pdfPage.getTextContent().then(
+ function textContentResolved(textContent) {
+ textLayer.setTextContent(textContent);
+ }
+ );
+ }
+ },
+ function pdfPageRenderError(error) {
+ pageViewDrawCallback(error);
+ }
+ );
+
+ setupAnnotations(div, pdfPage, this.viewport);
+ div.setAttribute('data-loaded', true);
+
+ // Add the page to the cache at the start of drawing. That way it can be
+ // evicted from the cache and destroyed even if we pause its rendering.
+ cache.push(this);
+ };
+
+ this.beforePrint = function pageViewBeforePrint() {
+ var pdfPage = this.pdfPage;
+
+ var viewport = pdfPage.getViewport(1);
+ // Use the same hack we use for high dpi displays for printing to get better
+ // output until bug 811002 is fixed in FF.
+ var PRINT_OUTPUT_SCALE = 2;
+ var canvas = document.createElement('canvas');
+ canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE;
+ canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE;
+ canvas.style.width = (PRINT_OUTPUT_SCALE * viewport.width) + 'pt';
+ canvas.style.height = (PRINT_OUTPUT_SCALE * viewport.height) + 'pt';
+ var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' +
+ (1 / PRINT_OUTPUT_SCALE) + ')';
+ CustomStyle.setProp('transform' , canvas, cssScale);
+ CustomStyle.setProp('transformOrigin' , canvas, '0% 0%');
+
+ var printContainer = document.getElementById('printContainer');
+ var canvasWrapper = document.createElement('div');
+ canvasWrapper.style.width = viewport.width + 'pt';
+ canvasWrapper.style.height = viewport.height + 'pt';
+ canvasWrapper.appendChild(canvas);
+ printContainer.appendChild(canvasWrapper);
+
+ canvas.mozPrintCallback = function(obj) {
+ var ctx = obj.context;
+
+ ctx.save();
+ ctx.fillStyle = 'rgb(255, 255, 255)';
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+ ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE);
+
+ var renderContext = {
+ canvasContext: ctx,
+ viewport: viewport,
+ intent: 'print'
+ };
+
+ pdfPage.render(renderContext).promise.then(function() {
+ // Tell the printEngine that rendering this canvas/page has finished.
+ obj.done();
+ }, function(error) {
+ console.error(error);
+ // Tell the printEngine that rendering this canvas/page has failed.
+ // This will make the print proces stop.
+ if ('abort' in obj) {
+ obj.abort();
+ } else {
+ obj.done();
+ }
+ });
+ };
+ };
+
+ this.updateStats = function pageViewUpdateStats() {
+ if (!this.stats) {
+ return;
+ }
+
+ if (PDFJS.pdfBug && Stats.enabled) {
+ var stats = this.stats;
+ Stats.add(this.id, stats);
+ }
+ };
+};
+
+
+var FIND_SCROLL_OFFSET_TOP = -50;
+var FIND_SCROLL_OFFSET_LEFT = -400;
+var MAX_TEXT_DIVS_TO_RENDER = 100000;
+var RENDER_DELAY = 200; // ms
+
+var NonWhitespaceRegexp = /\S/;
+
+function isAllWhitespace(str) {
+ return !NonWhitespaceRegexp.test(str);
+}
+
+/**
+ * @typedef {Object} TextLayerBuilderOptions
+ * @property {HTMLDivElement} textLayerDiv - The text layer container.
+ * @property {number} pageIndex - The page index.
+ * @property {PageViewport} viewport - The viewport of the text layer.
+ * @property {ILastScrollSource} lastScrollSource - The object that records when
+ * last time scroll happened.
+ * @property {boolean} isViewerInPresentationMode
+ * @property {PDFFindController} findController
+ */
+
+/**
+ * TextLayerBuilder provides text-selection functionality for the PDF.
+ * It does this by creating overlay divs over the PDF text. These divs
+ * contain text that matches the PDF text they are overlaying. This object
+ * also provides a way to highlight text that is being searched for.
+ * @class
+ */
+var TextLayerBuilder = (function TextLayerBuilderClosure() {
+ function TextLayerBuilder(options) {
+ this.textLayerDiv = options.textLayerDiv;
+ this.layoutDone = false;
+ this.divContentDone = false;
+ this.pageIdx = options.pageIndex;
+ this.matches = [];
+ this.lastScrollSource = options.lastScrollSource || null;
+ this.viewport = options.viewport;
+ this.isViewerInPresentationMode = options.isViewerInPresentationMode;
+ this.textDivs = [];
+ this.findController = options.findController || null;
+ }
+
+ TextLayerBuilder.prototype = {
+ renderLayer: function TextLayerBuilder_renderLayer() {
+ var textLayerFrag = document.createDocumentFragment();
+ var textDivs = this.textDivs;
+ var textDivsLength = textDivs.length;
+ var canvas = document.createElement('canvas');
+ var ctx = canvas.getContext('2d');
+
+ // No point in rendering many divs as it would make the browser
+ // unusable even after the divs are rendered.
+ if (textDivsLength > MAX_TEXT_DIVS_TO_RENDER) {
+ return;
+ }
+
+ var lastFontSize;
+ var lastFontFamily;
+ for (var i = 0; i < textDivsLength; i++) {
+ var textDiv = textDivs[i];
+ if (textDiv.dataset.isWhitespace !== undefined) {
+ continue;
+ }
+
+ var fontSize = textDiv.style.fontSize;
+ var fontFamily = textDiv.style.fontFamily;
+
+ // Only build font string and set to context if different from last.
+ if (fontSize !== lastFontSize || fontFamily !== lastFontFamily) {
+ ctx.font = fontSize + ' ' + fontFamily;
+ lastFontSize = fontSize;
+ lastFontFamily = fontFamily;
+ }
+
+ var width = ctx.measureText(textDiv.textContent).width;
+ if (width > 0) {
+ textLayerFrag.appendChild(textDiv);
+ var transform;
+ if (textDiv.dataset.canvasWidth !== undefined) {
+ // Dataset values come of type string.
+ var textScale = textDiv.dataset.canvasWidth / width;
+ transform = 'scaleX(' + textScale + ')';
+ } else {
+ transform = '';
+ }
+ var rotation = textDiv.dataset.angle;
+ if (rotation) {
+ transform = 'rotate(' + rotation + 'deg) ' + transform;
+ }
+ if (transform) {
+ CustomStyle.setProp('transform' , textDiv, transform);
+ }
+ }
+ }
+
+ this.textLayerDiv.appendChild(textLayerFrag);
+ this.renderingDone = true;
+ this.updateMatches();
+ },
+
+ setupRenderLayoutTimer:
+ function TextLayerBuilder_setupRenderLayoutTimer() {
+ // Schedule renderLayout() if the user has been scrolling,
+ // otherwise run it right away.
+ var self = this;
+ var lastScroll = (this.lastScrollSource === null ?
+ 0 : this.lastScrollSource.lastScroll);
+
+ if (Date.now() - lastScroll > RENDER_DELAY) { // Render right away
+ this.renderLayer();
+ } else { // Schedule
+ if (this.renderTimer) {
+ clearTimeout(this.renderTimer);
+ }
+ this.renderTimer = setTimeout(function() {
+ self.setupRenderLayoutTimer();
+ }, RENDER_DELAY);
+ }
+ },
+
+ appendText: function TextLayerBuilder_appendText(geom, styles) {
+ var style = styles[geom.fontName];
+ var textDiv = document.createElement('div');
+ this.textDivs.push(textDiv);
+ if (isAllWhitespace(geom.str)) {
+ textDiv.dataset.isWhitespace = true;
+ return;
+ }
+ var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
+ var angle = Math.atan2(tx[1], tx[0]);
+ if (style.vertical) {
+ angle += Math.PI / 2;
+ }
+ var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
+ var fontAscent = fontHeight;
+ if (style.ascent) {
+ fontAscent = style.ascent * fontAscent;
+ } else if (style.descent) {
+ fontAscent = (1 + style.descent) * fontAscent;
+ }
+
+ var left;
+ var top;
+ if (angle === 0) {
+ left = tx[4];
+ top = tx[5] - fontAscent;
+ } else {
+ left = tx[4] + (fontAscent * Math.sin(angle));
+ top = tx[5] - (fontAscent * Math.cos(angle));
+ }
+ textDiv.style.left = left + 'px';
+ textDiv.style.top = top + 'px';
+ textDiv.style.fontSize = fontHeight + 'px';
+ textDiv.style.fontFamily = style.fontFamily;
+
+ textDiv.textContent = geom.str;
+ // |fontName| is only used by the Font Inspector. This test will succeed
+ // when e.g. the Font Inspector is off but the Stepper is on, but it's
+ // not worth the effort to do a more accurate test.
+ if (PDFJS.pdfBug) {
+ textDiv.dataset.fontName = geom.fontName;
+ }
+ // Storing into dataset will convert number into string.
+ if (angle !== 0) {
+ textDiv.dataset.angle = angle * (180 / Math.PI);
+ }
+ // We don't bother scaling single-char text divs, because it has very
+ // little effect on text highlighting. This makes scrolling on docs with
+ // lots of such divs a lot faster.
+ if (textDiv.textContent.length > 1) {
+ if (style.vertical) {
+ textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
+ } else {
+ textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
+ }
+ }
+ },
+
+ setTextContent: function TextLayerBuilder_setTextContent(textContent) {
+ this.textContent = textContent;
+
+ var textItems = textContent.items;
+ for (var i = 0, len = textItems.length; i < len; i++) {
+ this.appendText(textItems[i], textContent.styles);
+ }
+ this.divContentDone = true;
+ this.setupRenderLayoutTimer();
+ },
+
+ convertMatches: function TextLayerBuilder_convertMatches(matches) {
+ var i = 0;
+ var iIndex = 0;
+ var bidiTexts = this.textContent.items;
+ var end = bidiTexts.length - 1;
+ var queryLen = (this.findController === null ?
+ 0 : this.findController.state.query.length);
+ var ret = [];
+
+ for (var m = 0, len = matches.length; m < len; m++) {
+ // Calculate the start position.
+ var matchIdx = matches[m];
+
+ // Loop over the divIdxs.
+ while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
+ iIndex += bidiTexts[i].str.length;
+ i++;
+ }
+
+ if (i === bidiTexts.length) {
+ console.error('Could not find a matching mapping');
+ }
+
+ var match = {
+ begin: {
+ divIdx: i,
+ offset: matchIdx - iIndex
+ }
+ };
+
+ // Calculate the end position.
+ matchIdx += queryLen;
+
+ // Somewhat the same array as above, but use > instead of >= to get
+ // the end position right.
+ while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
+ iIndex += bidiTexts[i].str.length;
+ i++;
+ }
+
+ match.end = {
+ divIdx: i,
+ offset: matchIdx - iIndex
+ };
+ ret.push(match);
+ }
+
+ return ret;
+ },
+
+ renderMatches: function TextLayerBuilder_renderMatches(matches) {
+ // Early exit if there is nothing to render.
+ if (matches.length === 0) {
+ return;
+ }
+
+ var bidiTexts = this.textContent.items;
+ var textDivs = this.textDivs;
+ var prevEnd = null;
+ var isSelectedPage = (this.findController === null ?
+ false : (this.pageIdx === this.findController.selected.pageIdx));
+ var selectedMatchIdx = (this.findController === null ?
+ -1 : this.findController.selected.matchIdx);
+ var highlightAll = (this.findController === null ?
+ false : this.findController.state.highlightAll);
+ var infinity = {
+ divIdx: -1,
+ offset: undefined
+ };
+
+ function beginText(begin, className) {
+ var divIdx = begin.divIdx;
+ textDivs[divIdx].textContent = '';
+ appendTextToDiv(divIdx, 0, begin.offset, className);
+ }
+
+ function appendTextToDiv(divIdx, fromOffset, toOffset, className) {
+ var div = textDivs[divIdx];
+ var content = bidiTexts[divIdx].str.substring(fromOffset, toOffset);
+ var node = document.createTextNode(content);
+ if (className) {
+ var span = document.createElement('span');
+ span.className = className;
+ span.appendChild(node);
+ div.appendChild(span);
+ return;
+ }
+ div.appendChild(node);
+ }
+
+ var i0 = selectedMatchIdx, i1 = i0 + 1;
+ if (highlightAll) {
+ i0 = 0;
+ i1 = matches.length;
+ } else if (!isSelectedPage) {
+ // Not highlighting all and this isn't the selected page, so do nothing.
+ return;
+ }
+
+ for (var i = i0; i < i1; i++) {
+ var match = matches[i];
+ var begin = match.begin;
+ var end = match.end;
+ var isSelected = (isSelectedPage && i === selectedMatchIdx);
+ var highlightSuffix = (isSelected ? ' selected' : '');
+
+ if (isSelected && !this.isViewerInPresentationMode) {
+ scrollIntoView(textDivs[begin.divIdx],
+ { top: FIND_SCROLL_OFFSET_TOP,
+ left: FIND_SCROLL_OFFSET_LEFT });
+ }
+
+ // Match inside new div.
+ if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
+ // If there was a previous div, then add the text at the end.
+ if (prevEnd !== null) {
+ appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
+ }
+ // Clear the divs and set the content until the starting point.
+ beginText(begin);
+ } else {
+ appendTextToDiv(prevEnd.divIdx, prevEnd.offset, begin.offset);
+ }
+
+ if (begin.divIdx === end.divIdx) {
+ appendTextToDiv(begin.divIdx, begin.offset, end.offset,
+ 'highlight' + highlightSuffix);
+ } else {
+ appendTextToDiv(begin.divIdx, begin.offset, infinity.offset,
+ 'highlight begin' + highlightSuffix);
+ for (var n0 = begin.divIdx + 1, n1 = end.divIdx; n0 < n1; n0++) {
+ textDivs[n0].className = 'highlight middle' + highlightSuffix;
+ }
+ beginText(end, 'highlight end' + highlightSuffix);
+ }
+ prevEnd = end;
+ }
+
+ if (prevEnd) {
+ appendTextToDiv(prevEnd.divIdx, prevEnd.offset, infinity.offset);
+ }
+ },
+
+ updateMatches: function TextLayerBuilder_updateMatches() {
+ // Only show matches when all rendering is done.
+ if (!this.renderingDone) {
+ return;
+ }
+
+ // Clear all matches.
+ var matches = this.matches;
+ var textDivs = this.textDivs;
+ var bidiTexts = this.textContent.items;
+ var clearedUntilDivIdx = -1;
+
+ // Clear all current matches.
+ for (var i = 0, len = matches.length; i < len; i++) {
+ var match = matches[i];
+ var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
+ for (var n = begin, end = match.end.divIdx; n <= end; n++) {
+ var div = textDivs[n];
+ div.textContent = bidiTexts[n].str;
+ div.className = '';
+ }
+ clearedUntilDivIdx = match.end.divIdx + 1;
+ }
+
+ if (this.findController === null || !this.findController.active) {
+ return;
+ }
+
+ // Convert the matches on the page controller into the match format
+ // used for the textLayer.
+ this.matches = this.convertMatches(this.findController === null ?
+ [] : (this.findController.pageMatches[this.pageIdx] || []));
+ this.renderMatches(this.matches);
+ }
+ };
+ return TextLayerBuilder;
+})();
+
+
+/**
+ * @typedef {Object} PDFViewerOptions
+ * @property {HTMLDivElement} container - The container for the viewer element.
+ * @property {HTMLDivElement} viewer - (optional) The viewer element.
+ * @property {IPDFLinkService} linkService - The navigation/linking service.
+ * @property {PDFRenderingQueue} renderingQueue - (optional) The rendering
+ * queue object.
+ */
+
+/**
+ * Simple viewer control to display PDF content/pages.
+ * @class
+ * @implements {ILastScrollSource}
+ * @implements {IRenderableView}
+ */
+var PDFViewer = (function pdfViewer() {
+ /**
+ * @constructs PDFViewer
+ * @param {PDFViewerOptions} options
+ */
+ function PDFViewer(options) {
+ this.container = options.container;
+ this.viewer = options.viewer || options.container.firstElementChild;
+ this.linkService = options.linkService || new SimpleLinkService(this);
+
+ this.defaultRenderingQueue = !options.renderingQueue;
+ if (this.defaultRenderingQueue) {
+ // Custom rendering queue is not specified, using default one
+ this.renderingQueue = new PDFRenderingQueue();
+ this.renderingQueue.setViewer(this);
+ } else {
+ this.renderingQueue = options.renderingQueue;
+ }
+
+ this.scroll = watchScroll(this.container, this._scrollUpdate.bind(this));
+ this.lastScroll = 0;
+ this.updateInProgress = false;
+ this.presentationModeState = PresentationModeState.UNKNOWN;
+ this._resetView();
+ }
+
+ PDFViewer.prototype = /** @lends PDFViewer.prototype */{
+ get pagesCount() {
+ return this.pages.length;
+ },
+
+ getPageView: function (index) {
+ return this.pages[index];
+ },
+
+ get currentPageNumber() {
+ return this._currentPageNumber;
+ },
+
+ set currentPageNumber(val) {
+ if (!this.pdfDocument) {
+ this._currentPageNumber = val;
+ return;
+ }
+
+ var event = document.createEvent('UIEvents');
+ event.initUIEvent('pagechange', true, true, window, 0);
+ event.updateInProgress = this.updateInProgress;
+
+ if (!(0 < val && val <= this.pagesCount)) {
+ event.pageNumber = this._currentPageNumber;
+ event.previousPageNumber = val;
+ this.container.dispatchEvent(event);
+ return;
+ }
+
+ this.pages[val - 1].updateStats();
+ event.previousPageNumber = this._currentPageNumber;
+ this._currentPageNumber = val;
+ event.pageNumber = val;
+ this.container.dispatchEvent(event);
+ },
+
+ /**
+ * @returns {number}
+ */
+ get currentScale() {
+ return this._currentScale;
+ },
+
+ /**
+ * @param {number} val - Scale of the pages in percents.
+ */
+ set currentScale(val) {
+ if (isNaN(val)) {
+ throw new Error('Invalid numeric scale');
+ }
+ if (!this.pdfDocument) {
+ this._currentScale = val;
+ this._currentScaleValue = val.toString();
+ return;
+ }
+ this._setScale(val, false);
+ },
+
+ /**
+ * @returns {string}
+ */
+ get currentScaleValue() {
+ return this._currentScaleValue;
+ },
+
+ /**
+ * @param val - The scale of the pages (in percent or predefined value).
+ */
+ set currentScaleValue(val) {
+ if (!this.pdfDocument) {
+ this._currentScale = isNaN(val) ? UNKNOWN_SCALE : val;
+ this._currentScaleValue = val;
+ return;
+ }
+ this._setScale(val, false);
+ },
+
+ /**
+ * @returns {number}
+ */
+ get pagesRotation() {
+ return this._pagesRotation;
+ },
+
+ /**
+ * @param {number} rotation - The rotation of the pages (0, 90, 180, 270).
+ */
+ set pagesRotation(rotation) {
+ this._pagesRotation = rotation;
+
+ for (var i = 0, l = this.pages.length; i < l; i++) {
+ var page = this.pages[i];
+ page.update(page.scale, rotation);
+ }
+
+ this._setScale(this._currentScaleValue, true);
+ },
+
+ /**
+ * @param pdfDocument {PDFDocument}
+ */
+ setDocument: function (pdfDocument) {
+ if (this.pdfDocument) {
+ this._resetView();
+ }
+
+ this.pdfDocument = pdfDocument;
+ if (!pdfDocument) {
+ return;
+ }
+
+ var pagesCount = pdfDocument.numPages;
+ var pagesRefMap = this.pagesRefMap = {};
+ var self = this;
+
+ var resolvePagesPromise;
+ var pagesPromise = new Promise(function (resolve) {
+ resolvePagesPromise = resolve;
+ });
+ this.pagesPromise = pagesPromise;
+ pagesPromise.then(function () {
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('pagesloaded', true, true, {
+ pagesCount: pagesCount
+ });
+ self.container.dispatchEvent(event);
+ });
+
+ var isOnePageRenderedResolved = false;
+ var resolveOnePageRendered = null;
+ var onePageRendered = new Promise(function (resolve) {
+ resolveOnePageRendered = resolve;
+ });
+ this.onePageRendered = onePageRendered;
+
+ var bindOnAfterDraw = function (pageView) {
+ // when page is painted, using the image as thumbnail base
+ pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() {
+ if (!isOnePageRenderedResolved) {
+ isOnePageRenderedResolved = true;
+ resolveOnePageRendered();
+ }
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('pagerendered', true, true, {
+ pageNumber: pageView.id
+ });
+ self.container.dispatchEvent(event);
+ };
+ };
+
+ var firstPagePromise = pdfDocument.getPage(1);
+ this.firstPagePromise = firstPagePromise;
+
+ // Fetch a single page so we can get a viewport that will be the default
+ // viewport for all pages
+ return firstPagePromise.then(function(pdfPage) {
+ var scale = this._currentScale || 1.0;
+ var viewport = pdfPage.getViewport(scale * CSS_UNITS);
+ for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ var pageSource = new PDFPageSource(pdfDocument, pageNum);
+ var pageView = new PageView(this.viewer, pageNum, scale,
+ viewport.clone(), this.linkService,
+ this.renderingQueue, this.cache,
+ pageSource, this);
+ bindOnAfterDraw(pageView);
+ this.pages.push(pageView);
+ }
+
+ // Fetch all the pages since the viewport is needed before printing
+ // starts to create the correct size canvas. Wait until one page is
+ // rendered so we don't tie up too many resources early on.
+ onePageRendered.then(function () {
+ if (!PDFJS.disableAutoFetch) {
+ var getPagesLeft = pagesCount;
+ for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
+ pdfDocument.getPage(pageNum).then(function (pageNum, pdfPage) {
+ var pageView = self.pages[pageNum - 1];
+ if (!pageView.pdfPage) {
+ pageView.setPdfPage(pdfPage);
+ }
+ var refStr = pdfPage.ref.num + ' ' + pdfPage.ref.gen + ' R';
+ pagesRefMap[refStr] = pageNum;
+ getPagesLeft--;
+ if (!getPagesLeft) {
+ resolvePagesPromise();
+ }
+ }.bind(null, pageNum));
+ }
+ } else {
+ // XXX: Printing is semi-broken with auto fetch disabled.
+ resolvePagesPromise();
+ }
+ });
+
+ var event = document.createEvent('CustomEvent');
+ event.initCustomEvent('pagesinit', true, true, null);
+ self.container.dispatchEvent(event);
+
+ if (this.defaultRenderingQueue) {
+ this.update();
+ }
+ }.bind(this));
+ },
+
+ _resetView: function () {
+ this.cache = new Cache(DEFAULT_CACHE_SIZE);
+ this.pages = [];
+ this._currentPageNumber = 1;
+ this._currentScale = UNKNOWN_SCALE;
+ this._currentScaleValue = null;
+ this.location = null;
+ this._pagesRotation = 0;
+
+ var container = this.viewer;
+ while (container.hasChildNodes()) {
+ container.removeChild(container.lastChild);
+ }
+ },
+
+ _scrollUpdate: function () {
+ this.lastScroll = Date.now();
+
+ if (this.pagesCount === 0) {
+ return;
+ }
+ this.update();
+ },
+
+ _setScaleUpdatePages: function pdfViewer_setScaleUpdatePages(
+ newScale, newValue, noScroll, preset) {
+ this._currentScaleValue = newValue;
+ if (newScale === this._currentScale) {
+ return;
+ }
+ for (var i = 0, ii = this.pages.length; i < ii; i++) {
+ this.pages[i].update(newScale);
+ }
+ this._currentScale = newScale;
+
+ if (!noScroll) {
+ var page = this._currentPageNumber, dest;
+ var inPresentationMode =
+ this.presentationModeState === PresentationModeState.CHANGING ||
+ this.presentationModeState === PresentationModeState.FULLSCREEN;
+ if (this.location && !inPresentationMode &&
+ !IGNORE_CURRENT_POSITION_ON_ZOOM) {
+ page = this.location.pageNumber;
+ dest = [null, { name: 'XYZ' }, this.location.left,
+ this.location.top, null];
+ }
+ this.scrollPageIntoView(page, dest);
+ }
+
+ var event = document.createEvent('UIEvents');
+ event.initUIEvent('scalechange', true, true, window, 0);
+ event.scale = newScale;
+ if (preset) {
+ event.presetValue = newValue;
+ }
+ this.container.dispatchEvent(event);
+ },
+
+ _setScale: function pdfViewer_setScale(value, noScroll) {
+ if (value === 'custom') {
+ return;
+ }
+ var scale = parseFloat(value);
+
+ if (scale > 0) {
+ this._setScaleUpdatePages(scale, value, noScroll, false);
+ } else {
+ var currentPage = this.pages[this._currentPageNumber - 1];
+ if (!currentPage) {
+ return;
+ }
+ var inPresentationMode =
+ this.presentationModeState === PresentationModeState.FULLSCREEN;
+ var hPadding = inPresentationMode ? 0 : SCROLLBAR_PADDING;
+ var vPadding = inPresentationMode ? 0 : VERTICAL_PADDING;
+ var pageWidthScale = (this.container.clientWidth - hPadding) /
+ currentPage.width * currentPage.scale;
+ var pageHeightScale = (this.container.clientHeight - vPadding) /
+ currentPage.height * currentPage.scale;
+ switch (value) {
+ case 'page-actual':
+ scale = 1;
+ break;
+ case 'page-width':
+ scale = pageWidthScale;
+ break;
+ case 'page-height':
+ scale = pageHeightScale;
+ break;
+ case 'page-fit':
+ scale = Math.min(pageWidthScale, pageHeightScale);
+ break;
+ case 'auto':
+ var isLandscape = (currentPage.width > currentPage.height);
+ // For pages in landscape mode, fit the page height to the viewer
+ // *unless* the page would thus become too wide to fit horizontally.
+ var horizontalScale = isLandscape ?
+ Math.min(pageHeightScale, pageWidthScale) : pageWidthScale;
+ scale = Math.min(MAX_AUTO_SCALE, horizontalScale);
+ break;
+ default:
+ console.error('pdfViewSetScale: \'' + value +
+ '\' is an unknown zoom value.');
+ return;
+ }
+ this._setScaleUpdatePages(scale, value, noScroll, true);
+ }
+ },
+
+ /**
+ * Scrolls page into view.
+ * @param {number} pageNumber
+ * @param {Array} dest - (optional) original PDF destination array:
+ *
+ */
+ scrollPageIntoView: function PDFViewer_scrollPageIntoView(pageNumber,
+ dest) {
+ var pageView = this.pages[pageNumber - 1];
+ var pageViewDiv = pageView.el;
+
+ if (this.presentationModeState ===
+ PresentationModeState.FULLSCREEN) {
+ if (this.linkService.page !== pageView.id) {
+ // Avoid breaking getVisiblePages in presentation mode.
+ this.linkService.page = pageView.id;
+ return;
+ }
+ dest = null;
+ // Fixes the case when PDF has different page sizes.
+ this._setScale(this.currentScaleValue, true);
+ }
+ if (!dest) {
+ scrollIntoView(pageViewDiv);
+ return;
+ }
+
+ var x = 0, y = 0;
+ var width = 0, height = 0, widthScale, heightScale;
+ var changeOrientation = (pageView.rotation % 180 === 0 ? false : true);
+ var pageWidth = (changeOrientation ? pageView.height : pageView.width) /
+ pageView.scale / CSS_UNITS;
+ var pageHeight = (changeOrientation ? pageView.width : pageView.height) /
+ pageView.scale / CSS_UNITS;
+ var scale = 0;
+ switch (dest[1].name) {
+ case 'XYZ':
+ x = dest[2];
+ y = dest[3];
+ scale = dest[4];
+ // If x and/or y coordinates are not supplied, default to
+ // _top_ left of the page (not the obvious bottom left,
+ // since aligning the bottom of the intended page with the
+ // top of the window is rarely helpful).
+ x = x !== null ? x : 0;
+ y = y !== null ? y : pageHeight;
+ break;
+ case 'Fit':
+ case 'FitB':
+ scale = 'page-fit';
+ break;
+ case 'FitH':
+ case 'FitBH':
+ y = dest[2];
+ scale = 'page-width';
+ break;
+ case 'FitV':
+ case 'FitBV':
+ x = dest[2];
+ width = pageWidth;
+ height = pageHeight;
+ scale = 'page-height';
+ break;
+ case 'FitR':
+ x = dest[2];
+ y = dest[3];
+ width = dest[4] - x;
+ height = dest[5] - y;
+ var viewerContainer = this.container;
+ widthScale = (viewerContainer.clientWidth - SCROLLBAR_PADDING) /
+ width / CSS_UNITS;
+ heightScale = (viewerContainer.clientHeight - SCROLLBAR_PADDING) /
+ height / CSS_UNITS;
+ scale = Math.min(Math.abs(widthScale), Math.abs(heightScale));
+ break;
+ default:
+ return;
+ }
+
+ if (scale && scale !== this.currentScale) {
+ this.currentScaleValue = scale;
+ } else if (this.currentScale === UNKNOWN_SCALE) {
+ this.currentScaleValue = DEFAULT_SCALE;
+ }
+
+ if (scale === 'page-fit' && !dest[4]) {
+ scrollIntoView(pageViewDiv);
+ return;
+ }
+
+ var boundingRect = [
+ pageView.viewport.convertToViewportPoint(x, y),
+ pageView.viewport.convertToViewportPoint(x + width, y + height)
+ ];
+ var left = Math.min(boundingRect[0][0], boundingRect[1][0]);
+ var top = Math.min(boundingRect[0][1], boundingRect[1][1]);
+
+ scrollIntoView(pageViewDiv, { left: left, top: top });
+ },
+
+ _updateLocation: function (firstPage) {
+ var currentScale = this._currentScale;
+ var currentScaleValue = this._currentScaleValue;
+ var normalizedScaleValue =
+ parseFloat(currentScaleValue) === currentScale ?
+ Math.round(currentScale * 10000) / 100 : currentScaleValue;
+
+ var pageNumber = firstPage.id;
+ var pdfOpenParams = '#page=' + pageNumber;
+ pdfOpenParams += '&zoom=' + normalizedScaleValue;
+ var currentPageView = this.pages[pageNumber - 1];
+ var container = this.container;
+ var topLeft = currentPageView.getPagePoint(
+ (container.scrollLeft - firstPage.x),
+ (container.scrollTop - firstPage.y));
+ var intLeft = Math.round(topLeft[0]);
+ var intTop = Math.round(topLeft[1]);
+ pdfOpenParams += ',' + intLeft + ',' + intTop;
+
+ this.location = {
+ pageNumber: pageNumber,
+ scale: normalizedScaleValue,
+ top: intTop,
+ left: intLeft,
+ pdfOpenParams: pdfOpenParams
+ };
+ },
+
+ update: function () {
+ var visible = this._getVisiblePages();
+ var visiblePages = visible.views;
+ if (visiblePages.length === 0) {
+ return;
+ }
+
+ this.updateInProgress = true;
+
+ var suggestedCacheSize = Math.max(DEFAULT_CACHE_SIZE,
+ 2 * visiblePages.length + 1);
+ this.cache.resize(suggestedCacheSize);
+
+ this.renderingQueue.renderHighestPriority(visible);
+
+ var currentId = this.currentPageNumber;
+ var firstPage = visible.first;
+
+ for (var i = 0, ii = visiblePages.length, stillFullyVisible = false;
+ i < ii; ++i) {
+ var page = visiblePages[i];
+
+ if (page.percent < 100) {
+ break;
+ }
+ if (page.id === currentId) {
+ stillFullyVisible = true;
+ break;
+ }
+ }
+
+ if (!stillFullyVisible) {
+ currentId = visiblePages[0].id;
+ }
+
+ if (this.presentationModeState !== PresentationModeState.FULLSCREEN) {
+ this.currentPageNumber = currentId;
+ }
+
+ this._updateLocation(firstPage);
+
+ this.updateInProgress = false;
+
+ var event = document.createEvent('UIEvents');
+ event.initUIEvent('updateviewarea', true, true, window, 0);
+ this.container.dispatchEvent(event);
+ },
+
+ containsElement: function (element) {
+ return this.container.contains(element);
+ },
+
+ focus: function () {
+ this.container.focus();
+ },
+
+ blur: function () {
+ this.container.blur();
+ },
+
+ get isHorizontalScrollbarEnabled() {
+ return (this.presentationModeState === PresentationModeState.FULLSCREEN ?
+ false : (this.container.scrollWidth > this.container.clientWidth));
+ },
+
+ _getVisiblePages: function () {
+ if (this.presentationModeState !== PresentationModeState.FULLSCREEN) {
+ return getVisibleElements(this.container, this.pages, true);
+ } else {
+ // The algorithm in getVisibleElements doesn't work in all browsers and
+ // configurations when presentation mode is active.
+ var visible = [];
+ var currentPage = this.pages[this._currentPageNumber - 1];
+ visible.push({ id: currentPage.id, view: currentPage });
+ return { first: currentPage, last: currentPage, views: visible };
+ }
+ },
+
+ cleanup: function () {
+ for (var i = 0, ii = this.pages.length; i < ii; i++) {
+ if (this.pages[i] &&
+ this.pages[i].renderingState !== RenderingStates.FINISHED) {
+ this.pages[i].reset();
+ }
+ }
+ },
+
+ forceRendering: function (currentlyVisiblePages) {
+ var visiblePages = currentlyVisiblePages || this._getVisiblePages();
+ var pageView = this.renderingQueue.getHighestPriority(visiblePages,
+ this.pages,
+ this.scroll.down);
+ if (pageView) {
+ this.renderingQueue.renderView(pageView);
+ return true;
+ }
+ return false;
+ },
+
+ getPageTextContent: function (pageIndex) {
+ return this.pdfDocument.getPage(pageIndex + 1).then(function (page) {
+ return page.getTextContent();
+ });
+ },
+
+ /**
+ * @param textLayerDiv {HTMLDivElement}
+ * @param pageIndex {number}
+ * @param viewport {PageViewport}
+ * @returns {TextLayerBuilder}
+ */
+ createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
+ var isViewerInPresentationMode =
+ this.presentationModeState === PresentationModeState.FULLSCREEN;
+ return new TextLayerBuilder({
+ textLayerDiv: textLayerDiv,
+ pageIndex: pageIndex,
+ viewport: viewport,
+ lastScrollSource: this,
+ isViewerInPresentationMode: isViewerInPresentationMode,
+ findController: this.findController
+ });
+ },
+
+ setFindController: function (findController) {
+ this.findController = findController;
+ },
+ };
+
+ return PDFViewer;
+})();
+
+var SimpleLinkService = (function SimpleLinkServiceClosure() {
+ function SimpleLinkService(pdfViewer) {
+ this.pdfViewer = pdfViewer;
+ }
+ SimpleLinkService.prototype = {
+ /**
+ * @returns {number}
+ */
+ get page() {
+ return this.pdfViewer.currentPageNumber;
+ },
+ /**
+ * @param {number} value
+ */
+ set page(value) {
+ this.pdfViewer.currentPageNumber = value;
+ },
+ /**
+ * @param dest - The PDF destination object.
+ */
+ navigateTo: function (dest) {},
+ /**
+ * @param dest - The PDF destination object.
+ * @returns {string} The hyperlink to the PDF object.
+ */
+ getDestinationHash: function (dest) {
+ return '#';
+ },
+ /**
+ * @param hash - The PDF parameters/hash.
+ * @returns {string} The hyperlink to the PDF object.
+ */
+ getAnchorUrl: function (hash) {
+ return '#';
+ },
+ /**
+ * @param {string} hash
+ */
+ setHash: function (hash) {},
+ /**
+ * @param {string} action
+ */
+ executeNamedAction: function (action) {},
+ };
+ return SimpleLinkService;
+})();
+
+/**
+ * PDFPage object source.
+ * @class
+ */
+var PDFPageSource = (function PDFPageSourceClosure() {
+ /**
+ * @constructs
+ * @param {PDFDocument} pdfDocument
+ * @param {number} pageNumber
+ * @constructor
+ */
+ function PDFPageSource(pdfDocument, pageNumber) {
+ this.pdfDocument = pdfDocument;
+ this.pageNumber = pageNumber;
+ }
+
+ PDFPageSource.prototype = /** @lends PDFPageSource.prototype */ {
+ /**
+ * @returns {Promise}
+ */
+ getPage: function () {
+ return this.pdfDocument.getPage(this.pageNumber);
+ }
+ };
+
+ return PDFPageSource;
+})();
+
+
+var PDFViewerApplication = {
initialBookmark: document.location.hash.substring(1),
- container: null,
- thumbnailContainer: null,
initialized: false,
fellback: false,
pdfDocument: null,
sidebarOpen: false,
- pageViewScroll: null,
- thumbnailViewScroll: null,
+ printing: false,
+ /** @type {PDFViewer} */
+ pdfViewer: null,
+ /** @type {PDFThumbnailViewer} */
+ pdfThumbnailViewer: null,
+ /** @type {PDFRenderingQueue} */
+ pdfRenderingQueue: null,
pageRotation: 0,
+ updateScaleControls: true,
+ isInitialViewSet: false,
+ animationStartedPromise: null,
mouseScrollTimeStamp: 0,
mouseScrollDelta: 0,
- lastScroll: 0,
- previousPageNumber: 1,
+ preferenceSidebarViewOnLoad: SidebarView.NONE,
+ preferencePdfBugEnabled: false,
isViewerEmbedded: (window.parent !== window),
- idleTimeout: null,
+ url: '',
// called once when the document is loaded
initialize: function pdfViewInitialize() {
- var self = this;
- var container = this.container = document.getElementById('viewerContainer');
- this.pageViewScroll = {};
- this.watchScroll(container, this.pageViewScroll, updateViewarea);
+ var pdfRenderingQueue = new PDFRenderingQueue();
+ pdfRenderingQueue.onIdle = this.cleanup.bind(this);
+ this.pdfRenderingQueue = pdfRenderingQueue;
- var thumbnailContainer = this.thumbnailContainer =
- document.getElementById('thumbnailView');
- this.thumbnailViewScroll = {};
- this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
- this.renderHighestPriority.bind(this));
+ var container = document.getElementById('viewerContainer');
+ var viewer = document.getElementById('viewer');
+ this.pdfViewer = new PDFViewer({
+ container: container,
+ viewer: viewer,
+ renderingQueue: pdfRenderingQueue,
+ linkService: this
+ });
+ pdfRenderingQueue.setViewer(this.pdfViewer);
- PDFFindBar.initialize({
+ var thumbnailContainer = document.getElementById('thumbnailView');
+ this.pdfThumbnailViewer = new PDFThumbnailViewer({
+ container: thumbnailContainer,
+ renderingQueue: pdfRenderingQueue,
+ linkService: this
+ });
+ pdfRenderingQueue.setThumbnailViewer(this.pdfThumbnailViewer);
+
+ Preferences.initialize();
+
+ this.findController = new PDFFindController({
+ pdfViewer: this.pdfViewer,
+ integratedFind: this.supportsIntegratedFind
+ });
+ this.pdfViewer.setFindController(this.findController);
+
+ this.findBar = new PDFFindBar({
bar: document.getElementById('findbar'),
toggleButton: document.getElementById('viewFind'),
findField: document.getElementById('findInput'),
@@ -2249,13 +4659,11 @@ var PDFView = {
findMsg: document.getElementById('findMsg'),
findStatusIcon: document.getElementById('findStatusIcon'),
findPreviousButton: document.getElementById('findPrevious'),
- findNextButton: document.getElementById('findNext')
+ findNextButton: document.getElementById('findNext'),
+ findController: this.findController
});
- PDFFindController.initialize({
- pdfPageSource: this,
- integratedFind: this.supportsIntegratedFind
- });
+ this.findController.setFindBar(this.findBar);
HandTool.initialize({
container: container,
@@ -2271,18 +4679,13 @@ var PDFView = {
openFile: document.getElementById('secondaryOpenFile'),
print: document.getElementById('secondaryPrint'),
download: document.getElementById('secondaryDownload'),
+ viewBookmark: document.getElementById('secondaryViewBookmark'),
firstPage: document.getElementById('firstPage'),
lastPage: document.getElementById('lastPage'),
pageRotateCw: document.getElementById('pageRotateCw'),
- pageRotateCcw: document.getElementById('pageRotateCcw')
- });
-
- PasswordPrompt.initialize({
- overlayContainer: document.getElementById('overlayContainer'),
- passwordField: document.getElementById('password'),
- passwordText: document.getElementById('passwordText'),
- passwordSubmit: document.getElementById('passwordSubmit'),
- passwordCancel: document.getElementById('passwordCancel')
+ pageRotateCcw: document.getElementById('pageRotateCcw'),
+ documentProperties: DocumentProperties,
+ documentPropertiesButton: document.getElementById('documentProperties')
});
PresentationMode.initialize({
@@ -2294,101 +4697,76 @@ var PDFView = {
pageRotateCcw: document.getElementById('contextPageRotateCcw')
});
- this.initialized = true;
- container.addEventListener('scroll', function() {
- self.lastScroll = Date.now();
- }, false);
- },
+ PasswordPrompt.initialize({
+ overlayName: 'passwordOverlay',
+ passwordField: document.getElementById('password'),
+ passwordText: document.getElementById('passwordText'),
+ passwordSubmit: document.getElementById('passwordSubmit'),
+ passwordCancel: document.getElementById('passwordCancel')
+ });
- getPage: function pdfViewGetPage(n) {
- return this.pdfDocument.getPage(n);
- },
+ DocumentProperties.initialize({
+ overlayName: 'documentPropertiesOverlay',
+ closeButton: document.getElementById('documentPropertiesClose'),
+ fileNameField: document.getElementById('fileNameField'),
+ fileSizeField: document.getElementById('fileSizeField'),
+ titleField: document.getElementById('titleField'),
+ authorField: document.getElementById('authorField'),
+ subjectField: document.getElementById('subjectField'),
+ keywordsField: document.getElementById('keywordsField'),
+ creationDateField: document.getElementById('creationDateField'),
+ modificationDateField: document.getElementById('modificationDateField'),
+ creatorField: document.getElementById('creatorField'),
+ producerField: document.getElementById('producerField'),
+ versionField: document.getElementById('versionField'),
+ pageCountField: document.getElementById('pageCountField')
+ });
- // Helper function to keep track whether a div was scrolled up or down and
- // then call a callback.
- watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) {
- state.down = true;
- state.lastY = viewAreaElement.scrollTop;
- viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) {
- var currentY = viewAreaElement.scrollTop;
- var lastY = state.lastY;
- if (currentY > lastY)
- state.down = true;
- else if (currentY < lastY)
- state.down = false;
- // else do nothing and use previous value
- state.lastY = currentY;
- callback();
- }, true);
- },
-
- _setScaleUpdatePages: function pdfView_setScaleUpdatePages(
- newScale, newValue, resetAutoSettings, noScroll) {
- this.currentScaleValue = newValue;
- if (newScale === this.currentScale) {
- return;
- }
- for (var i = 0, ii = this.pages.length; i < ii; i++) {
- this.pages[i].update(newScale);
- }
- this.currentScale = newScale;
-
- if (!noScroll) {
- this.pages[this.page - 1].scrollIntoView();
- }
- var event = document.createEvent('UIEvents');
- event.initUIEvent('scalechange', false, false, window, 0);
- event.scale = newScale;
- event.resetAutoSettings = resetAutoSettings;
- window.dispatchEvent(event);
- },
-
- setScale: function pdfViewSetScale(value, resetAutoSettings, noScroll) {
- if (value === 'custom') {
- return;
- }
- var scale = parseFloat(value);
-
- if (scale > 0) {
- this._setScaleUpdatePages(scale, value, true, noScroll);
- } else {
- var currentPage = this.pages[this.page - 1];
- if (!currentPage) {
- return;
- }
- var pageWidthScale = (this.container.clientWidth - SCROLLBAR_PADDING) /
- currentPage.width * currentPage.scale;
- var pageHeightScale = (this.container.clientHeight - VERTICAL_PADDING) /
- currentPage.height * currentPage.scale;
- switch (value) {
- case 'page-actual':
- scale = 1;
- break;
- case 'page-width':
- scale = pageWidthScale;
- break;
- case 'page-height':
- scale = pageHeightScale;
- break;
- case 'page-fit':
- scale = Math.min(pageWidthScale, pageHeightScale);
- break;
- case 'auto':
- scale = Math.min(MAX_AUTO_SCALE, pageWidthScale);
- break;
- default:
- console.error('pdfViewSetScale: \'' + value +
- '\' is an unknown zoom value.');
+ var self = this;
+ var initializedPromise = Promise.all([
+ Preferences.get('enableWebGL').then(function resolved(value) {
+ PDFJS.disableWebGL = !value;
+ }),
+ Preferences.get('sidebarViewOnLoad').then(function resolved(value) {
+ self.preferenceSidebarViewOnLoad = value;
+ }),
+ Preferences.get('pdfBugEnabled').then(function resolved(value) {
+ self.preferencePdfBugEnabled = value;
+ }),
+ Preferences.get('disableTextLayer').then(function resolved(value) {
+ if (PDFJS.disableTextLayer === true) {
return;
- }
- this._setScaleUpdatePages(scale, value, resetAutoSettings, noScroll);
+ }
+ PDFJS.disableTextLayer = value;
+ }),
+ Preferences.get('disableRange').then(function resolved(value) {
+ if (PDFJS.disableRange === true) {
+ return;
+ }
+ PDFJS.disableRange = value;
+ }),
+ Preferences.get('disableAutoFetch').then(function resolved(value) {
+ PDFJS.disableAutoFetch = value;
+ }),
+ Preferences.get('disableFontFace').then(function resolved(value) {
+ if (PDFJS.disableFontFace === true) {
+ return;
+ }
+ PDFJS.disableFontFace = value;
+ }),
+ Preferences.get('useOnlyCssZoom').then(function resolved(value) {
+ PDFJS.useOnlyCssZoom = value;
+ })
+ // TODO move more preferences and other async stuff here
+ ]).catch(function (reason) { });
- selectScaleOption(value);
- }
+ return initializedPromise.then(function () {
+ PDFViewerApplication.initialized = true;
+ });
},
zoomIn: function pdfViewZoomIn(ticks) {
- var newScale = this.currentScale;
+ var newScale = this.pdfViewer.currentScale;
do {
newScale = (newScale * DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Math.ceil(newScale * 10) / 10;
@@ -2398,7 +4776,7 @@ var PDFView = {
},
zoomOut: function pdfViewZoomOut(ticks) {
- var newScale = this.currentScale;
+ var newScale = this.pdfViewer.currentScale;
do {
newScale = (newScale / DEFAULT_SCALE_DELTA).toFixed(2);
newScale = Math.floor(newScale * 10) / 10;
@@ -2407,38 +4785,20 @@ var PDFView = {
this.setScale(newScale, true);
},
+ get currentScaleValue() {
+ return this.pdfViewer.currentScaleValue;
+ },
+
+ get pagesCount() {
+ return this.pdfDocument.numPages;
+ },
+
set page(val) {
- var pages = this.pages;
- var event = document.createEvent('UIEvents');
- event.initUIEvent('pagechange', false, false, window, 0);
-
- if (!(0 < val && val <= pages.length)) {
- this.previousPageNumber = val;
- event.pageNumber = this.page;
- window.dispatchEvent(event);
- return;
- }
-
- pages[val - 1].updateStats();
- this.previousPageNumber = currentPageNumber;
- currentPageNumber = val;
- event.pageNumber = val;
- window.dispatchEvent(event);
-
- // checking if the this.page was called from the updateViewarea function:
- // avoiding the creation of two "set page" method (internal and public)
- if (updateViewarea.inProgress) {
- return;
- }
- // Avoid scrolling the first page during loading
- if (this.loading && val === 1) {
- return;
- }
- pages[val - 1].scrollIntoView();
+ this.pdfViewer.currentPageNumber = val;
},
get page() {
- return currentPageNumber;
+ return this.pdfViewer.currentPageNumber;
},
get supportsPrinting() {
@@ -2462,10 +4822,6 @@ var PDFView = {
document.webkitFullscreenEnabled === false ||
document.msFullscreenEnabled === false) {
support = false;
- } else if (this.isViewerEmbedded) {
- // Need to check if the viewer is embedded as well, to prevent issues with
- // presentation mode when the viewer is embedded in '
-
@@ -352,3 +413,4 @@ limitations under the License.
+
diff --git a/static/pdf.js/l10n.js b/static/pdf.js/l10n.js
index f13c8d60b..37f3950c5 100644
--- a/static/pdf.js/l10n.js
+++ b/static/pdf.js/l10n.js
@@ -26,7 +26,7 @@
- Removes window._ assignment.
*/
-/*jshint browser: true, devel: true, es5: true, globalstrict: true */
+/*jshint browser: true, devel: true, globalstrict: true */
'use strict';
document.webL10n = (function(window, document, undefined) {
diff --git a/static/pdf.js/locale/ach/viewer.properties b/static/pdf.js/locale/ach/viewer.properties
new file mode 100644
index 000000000..829adbd15
--- /dev/null
+++ b/static/pdf.js/locale/ach/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Pot buk mukato
+previous_label=Mukato
+next.title=Pot buk malubo
+next_label=Malubo
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pot buk:
+page_of=pi {{pageCount}}
+
+zoom_out.title=Jwik Matidi
+zoom_out_label=Jwik Matidi
+zoom_in.title=Kwot Madit
+zoom_in_label=Kwot Madit
+zoom.title=Kwoti
+presentation_mode.title=Lokke i kit me tyer
+presentation_mode_label=Kit me tyer
+open_file.title=Yab Pwail
+open_file_label=Yab
+print.title=Go
+print_label=Go
+download.title=Gam
+download_label=Gam
+bookmark.title=Neno ma kombedi (lok onyo yab i dirica manyen)
+bookmark_label=Neno ma kombedi
+
+# Secondary toolbar and context menu
+tools.title=Gintic
+tools_label=Gintic
+first_page.title=Cit i pot buk mukwongo
+first_page.label=Cit i pot buk mukwongo
+first_page_label=Cit i pot buk mukwongo
+last_page.title=Cit i pot buk magiko
+last_page.label=Cit i pot buk magiko
+last_page_label=Cit i pot buk magiko
+page_rotate_cw.title=Wire i tung lacuc
+page_rotate_cw.label=Wire i tung lacuc
+page_rotate_cw_label=Wire i tung lacuc
+page_rotate_ccw.title=Wire i tung lacam
+page_rotate_ccw.label=Wire i tung lacam
+page_rotate_ccw_label=Wire i tung lacam
+
+hand_tool_enable.title=Ye gintic me cing
+hand_tool_enable_label=Ye gintic me cing
+hand_tool_disable.title=Juk gintic me cing
+hand_tool_disable_label=Juk gintic me cing
+
+# Document properties dialog box
+document_properties.title=Jami me gin acoya…
+document_properties_label=Jami me gin acoya…
+document_properties_file_name=Nying pwail:
+document_properties_file_size=Dit pa pwail:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Wiye:
+document_properties_author=Ngat mucoyo:
+document_properties_subject=Lok:
+document_properties_keywords=Lok mapire tek:
+document_properties_creation_date=Nino dwe me cwec:
+document_properties_modification_date=Nino dwe me yub:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Lacwec:
+document_properties_producer=Layub PDF:
+document_properties_version=Kit PDF:
+document_properties_page_count=Kwan me pot buk:
+document_properties_close=Lor
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Lok gintic ma inget
+toggle_sidebar_label=Lok gintic ma inget
+outline.title=Nyut rek pa gin acoya
+outline_label=Pek pa gin acoya
+attachments.title=Nyut twec
+attachments_label=Twec
+thumbs.title=Nyut cal
+thumbs_label=Cal
+findbar.title=Nong iye gin acoya
+findbar_label=Nong
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pot buk {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Cal me pot buk {{page}}
+
+# Find panel button title and messages
+find_label=Nong:
+find_previous.title=Nong timme pa lok mukato
+find_previous_label=Mukato
+find_next.title=Nong timme pa lok malubo
+find_next_label=Malubo
+find_highlight=Wer weng
+find_match_case_label=Lok marwate
+find_reached_top=Oo iwi gin acoya, omede ki i tere
+find_reached_bottom=Oo i agiki me gin acoya, omede ki iwiye
+find_not_found=Lok pe ononge
+
+# Error panel labels
+error_more_info=Ngec Mukene
+error_less_info=Ngec Manok
+error_close=Lor
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Kwena: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Can kikore {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Pwail: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rek: {{line}}
+rendering_error=Bal otime i kare me nyuto pot buk.
+
+# Predefined zoom values
+page_scale_width=Lac me iye pot buk
+page_scale_fit=Porre me pot buk
+page_scale_auto=Kwot pire kene
+page_scale_actual=Dite kikome
+
+# Loading indicator messages
+loading_error_indicator=Bal
+loading_error=Bal otime kun cano PDF.
+invalid_file_error=Pwail me PDF ma pe atir onyo obale woko.
+missing_file_error=Pwail me PDF tye ka rem.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Lok angea manok]
+password_label=Ket mung me donyo me yabo pwail me PDF man.
+password_invalid=Mung me donyo pe atir. Tim ber i tem doki.
+password_ok=OK
+password_cancel=Juk
+
+printing_not_supported=Ciko: Layeny ma pe teno goyo liweng.
+printing_not_ready=Ciko: PDF pe ocane weng me agoya.
+web_fonts_disabled=Kijuko dit pa coc me kakube woko: pe romo tic ki dit pa coc me PDF ma kiketo i kine.
+document_colors_disabled=Pe ki ye ki gin acoya me PDF me tic ki rangi gi kengi: 'Ye pot buk me yero rangi mamegi kengi' kijuko woko i layeny.
diff --git a/static/pdf.js/locale/af/viewer.properties b/static/pdf.js/locale/af/viewer.properties
new file mode 100644
index 000000000..5bda09b75
--- /dev/null
+++ b/static/pdf.js/locale/af/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Vorige bladsy
+previous_label=Vorige
+next.title=Volgende bladsy
+next_label=Volgende
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Bladsy:
+page_of=van {{pageCount}}
+
+zoom_out.title=Zoem uit
+zoom_out_label=Zoem uit
+zoom_in.title=Zoem in
+zoom_in_label=Zoem in
+zoom.title=Zoem
+presentation_mode.title=Wissel na voorleggingsmodus
+presentation_mode_label=Voorleggingsmodus
+open_file.title=Open lêer
+open_file_label=Open
+print.title=Druk
+print_label=Druk
+download.title=Laai af
+download_label=Laai af
+bookmark.title=Huidige aansig (kopieer of open in nuwe venster)
+bookmark_label=Huidige aansig
+
+# Secondary toolbar and context menu
+tools.title=Nutsgoed
+tools_label=Nutsgoed
+first_page.title=Gaan na eerste bladsy
+first_page.label=Gaan na eerste bladsy
+first_page_label=Gaan na eerste bladsy
+last_page.title=Gaan na laaste bladsy
+last_page.label=Gaan na laaste bladsy
+last_page_label=Gaan na laaste bladsy
+page_rotate_cw.title=Roteer kloksgewys
+page_rotate_cw.label=Roteer kloksgewys
+page_rotate_cw_label=Roteer kloksgewys
+page_rotate_ccw.title=Roteer anti-kloksgewys
+page_rotate_ccw.label=Roteer anti-kloksgewys
+page_rotate_ccw_label=Roteer anti-kloksgewys
+
+hand_tool_enable.title=Aktiveer handjie
+hand_tool_enable_label=Aktiveer handjie
+hand_tool_disable.title=Deaktiveer handjie
+hand_tool_disable_label=Deaktiveer handjie
+
+# Document properties dialog box
+document_properties.title=Dokumenteienskappe…
+document_properties_label=Dokumenteienskappe…
+document_properties_file_name=Lêernaam:
+document_properties_file_size=Lêergrootte:
+document_properties_kb={{size_kb}} kG ({{size_b}} grepe)
+document_properties_mb={{size_mb}} MG ({{size_b}} grepe)
+document_properties_title=Titel:
+document_properties_author=Outeur:
+document_properties_subject=Onderwerp:
+document_properties_keywords=Sleutelwoorde:
+document_properties_creation_date=Skeppingsdatum:
+document_properties_modification_date=Wysigingsdatum:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Skepper:
+document_properties_producer=PDF-vervaardiger:
+document_properties_version=PDF-weergawe:
+document_properties_page_count=Aantal bladsye:
+document_properties_close=Sluit
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Sypaneel aan/af
+toggle_sidebar_label=Sypaneel aan/af
+outline.title=Wys dokumentoorsig
+outline_label=Dokumentoorsig
+attachments.title=Wys aanhegsels
+attachments_label=Aanhegsels
+thumbs.title=Wys duimnaels
+thumbs_label=Duimnaels
+findbar.title=Soek in dokument
+findbar_label=Vind
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Bladsy {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Duimnael van bladsy {{page}}
+
+# Find panel button title and messages
+find_label=Vind:
+find_previous.title=Vind die vorige voorkoms van die frase
+find_previous_label=Vorige
+find_next.title=Vind die volgende voorkoms van die frase
+find_next_label=Volgende
+find_highlight=Verlig alle
+find_match_case_label=Kassensitief
+find_reached_top=Bokant van dokument is bereik; gaan voort van onder af
+find_reached_bottom=Einde van dokument is bereik; gaan voort van bo af
+find_not_found=Frase nie gevind nie
+
+# Error panel labels
+error_more_info=Meer inligting
+error_less_info=Minder inligting
+error_close=Sluit
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (ID: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Boodskap: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stapel: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Lêer: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Lyn: {{line}}
+rendering_error='n Fout het voorgekom toe die bladsy weergegee is.
+
+# Predefined zoom values
+page_scale_width=Bladsywydte
+page_scale_fit=Pas bladsy
+page_scale_auto=Outomatiese zoem
+page_scale_actual=Werklike grootte
+
+# Loading indicator messages
+loading_error_indicator=Fout
+loading_error='n Fout het voorgekom met die laai van die PDF.
+invalid_file_error=Ongeldige of korrupte PDF-lêer.
+missing_file_error=PDF-lêer is weg.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}}-annotasie
+password_label=Gee die wagwoord om dié PDF-lêer mee te open.
+password_invalid=Ongeldige wagwoord. Probeer gerus weer.
+password_ok=OK
+password_cancel=Kanselleer
+
+printing_not_supported=Waarskuwing: Dié blaaier ondersteun nie drukwerk ten volle nie.
+printing_not_ready=Waarskuwing: Die PDF is nog nie volledig gelaai vir drukwerk nie.
+web_fonts_disabled=Webfonte is gedeaktiveer: kan nie PDF-fonte wat ingebed is, gebruik nie.
+document_colors_disabled=PDF-dokumente word nie toegelaat om hul eie kleure te gebruik nie: 'Laat bladsye toe om hul eie kleure te kies' is gedeaktiveer in die blaaier.
diff --git a/static/pdf.js/locale/ak/viewer.properties b/static/pdf.js/locale/ak/viewer.properties
new file mode 100644
index 000000000..883c2ab8e
--- /dev/null
+++ b/static/pdf.js/locale/ak/viewer.properties
@@ -0,0 +1,123 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Krataafa baako a etwa mu
+previous_label=Ekyiri-baako
+next.title=Krataafa a edi so baako
+next_label=Dea-É›-di-so-baako
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Krataafa:
+page_of=wÉ” {{pageCount}}
+
+zoom_out.title=Zuum pue
+zoom_out_label=Zuum ba abɔnten
+zoom_in.title=Zuum kÉ” mu
+zoom_in_label=Zuum kÉ” mu
+zoom.title=Zuum
+presentation_mode.title=Sesa kɔ Yɛkyerɛ Tebea mu
+presentation_mode_label=Yɛkyerɛ Tebea
+open_file.title=Bue Fael
+open_file_label=Bue
+print.title=Prente
+print_label=Prente
+download.title=Twe
+download_label=Twe
+bookmark.title=Seisei nhwÉ› (fa anaaso bue wÉ” tokuro foforo mu)
+bookmark_label=Seisei nhwÉ›
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_title=Ti asɛm:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=SÉ” anaaso dum saedbaa
+toggle_sidebar_label=SÉ” anaaso dum saedbaa
+outline.title=Kyerɛ dɔkomɛnt bɔbea
+outline_label=Dɔkomɛnt bɔbea
+thumbs.title=KyerÉ› mfoniwaa
+thumbs_label=Mfoniwaa
+findbar.title=Hu wɔ dɔkomɛnt no mu
+findbar_label=Hu
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Krataafa {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Krataafa ne mfoniwaa {{page}}
+
+# Find panel button title and messages
+find_label=Hunu:
+find_previous.title=San hu fres wÉ” ekyiri baako
+find_previous_label=Ekyiri baako
+find_next.title=San hu fres no wÉ” enim baako
+find_next_label=Ndiso
+find_highlight=HyÉ› bibiara nso
+find_match_case_label=Fa susu kaase
+find_reached_top=Edu krataafa ne soro, atoa so efiri ase
+find_reached_bottom=Edu krataafa n'ewiei, atoa so efiri soro
+find_not_found=Ennhu fres
+
+# Error panel labels
+error_more_info=Infɔmehyɛn bio a wɔka ho
+error_less_info=Te infɔmehyɛn bio a wɔka ho so
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{vɛɛhyen}} (nsi: {{si}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Nkrato: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Staake: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fael: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Laen: {{line}}
+rendering_error=Mfomso bae wÉ” bere a wÉ” rekyerÉ› krataafa no.
+
+# Predefined zoom values
+page_scale_width=Krataafa tɛtrɛtɛ
+page_scale_fit=Krataafa ehimtwa
+page_scale_auto=Zuum otomatik
+page_scale_actual=Kɛseyɛ ankasa
+
+# Loading indicator messages
+loading_error_indicator=Mfomso
+loading_error=Mfomso bae wɔ bere a wɔreloode PDF no.
+invalid_file_error=PDF fael no nndi mu anaaso ho atÉ” kyima.
+missing_file_error=PDF fael no ayera.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Tɛkst-nyiano]
+password_ok=OK
+password_cancel=Twa-mu
+
+printing_not_supported=Kɔkɔbɔ: Brawsa yi nnhyɛ daa mma prent ho kwan.
+printing_not_ready=Kɔkɔbɔ: Wɔnntwee PDF fael no nyinara mmbaee ama wo ɛ tumi aprente.
+web_fonts_disabled=Ɔedum wɛb-mfɔnt: nntumi mmfa PDF mfɔnt a wɔhyɛ mu nndi dwuma.
+document_colors_disabled=Wɔmma ho kwan sɛ PDF adɔkomɛnt de wɔn ara wɔn ahosu bɛdi dwuma: wɔ adum 'Ma ho kwan ma nkrataafa mpaw wɔn ara wɔn ahosu' wɔ brawsa yi mu.
diff --git a/static/pdf.js/locale/an/viewer.properties b/static/pdf.js/locale/an/viewer.properties
new file mode 100644
index 000000000..dc6107719
--- /dev/null
+++ b/static/pdf.js/locale/an/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Pachina anterior
+previous_label=Anterior
+next.title=Pachina siguient
+next_label=Siguient
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pachina:
+page_of=de {{pageCount}}
+
+zoom_out.title=Achiquir
+zoom_out_label=Achiquir
+zoom_in.title=Agrandir
+zoom_in_label=Agrandir
+zoom.title=Grandaria
+presentation_mode.title=Cambear t'o modo de presentación
+presentation_mode_label=Modo de presentación
+open_file.title=Ubrir o fichero
+open_file_label=Ubrir
+print.title=Imprentar
+print_label=Imprentar
+download.title=Descargar
+download_label=Descargar
+bookmark.title=Vista actual (copiar u ubrir en una nueva finestra)
+bookmark_label=Anvista actual
+
+# Secondary toolbar and context menu
+tools.title=Ferramientas
+tools_label=Ferramientas
+first_page.title=Ir ta la primer pachina
+first_page.label=Ir ta la primer pachina
+first_page_label=Ir ta la primer pachina
+last_page.title=Ir ta la zaguer pachina
+last_page.label=Ir ta la zaguera pachina
+last_page_label=Ir ta la zaguer pachina
+page_rotate_cw.title=Chirar enta la dreita
+page_rotate_cw.label=Chirar enta la dreita
+page_rotate_cw_label=Chira enta la dreita
+page_rotate_ccw.title=Chirar enta la zurda
+page_rotate_ccw.label=Chirar en sentiu antihorario
+page_rotate_ccw_label=Chirar enta la zurda
+
+hand_tool_enable.title=Activar a ferramienta man
+hand_tool_enable_label=Activar a ferramenta man
+hand_tool_disable.title=Desactivar a ferramienta man
+hand_tool_disable_label=Desactivar a ferramienta man
+
+# Document properties dialog box
+document_properties.title=Propiedatz d'o documento...
+document_properties_label=Propiedatz d'o documento...
+document_properties_file_name=Nombre de fichero:
+document_properties_file_size=Grandaria d'o fichero:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Titol:
+document_properties_author=Autor:
+document_properties_subject=Afer:
+document_properties_keywords=Parolas clau:
+document_properties_creation_date=Calendata de creyación:
+document_properties_modification_date=Calendata de modificación:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creyador:
+document_properties_producer=Creyador de PDF:
+document_properties_version=Versión de PDF:
+document_properties_page_count=Numero de pachinas:
+document_properties_close=Zarrar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Amostrar u amagar a barra lateral
+toggle_sidebar_label=Amostrar a barra lateral
+outline.title=Amostrar o esquema d'o documento
+outline_label=Esquema d'o documento
+attachments.title=Amostrar os adchuntos
+attachments_label=Adchuntos
+thumbs.title=Amostrar as miniaturas
+thumbs_label=Miniaturas
+findbar.title=Trobar en o documento
+findbar_label=Trobar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pachina {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura d'a pachina {{page}}
+
+# Find panel button title and messages
+find_label=Trobar:
+find_previous.title=Trobar l'anterior coincidencia d'a frase
+find_previous_label=Anterior
+find_next.title=Trobar a siguient coincidencia d'a frase
+find_next_label=Siguient
+find_highlight=Resaltar-lo tot
+find_match_case_label=Coincidencia de mayusclas/minusclas
+find_reached_top=S'ha plegau a l'inicio d'o documento, se contina dende baixo
+find_reached_bottom=S'ha plegau a la fin d'o documento, se contina dende alto
+find_not_found=No s'ha trobau a frase
+
+# Error panel labels
+error_more_info=Mas información
+error_less_info=Menos información
+error_close=Zarrar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mensache: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fichero: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linia: {{line}}
+rendering_error=Ha ocurriu una error en renderizar a pachina.
+
+# Predefined zoom values
+page_scale_width=Amplaria d'a pachina
+page_scale_fit=Achuste d'a pachina
+page_scale_auto=Grandaria automatica
+page_scale_actual=Grandaria actual
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=S'ha produciu una error en cargar o PDF.
+invalid_file_error=O PDF no ye valido u ye estorbau.
+missing_file_error=No i ha fichero PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotación {{type}}]
+password_label=Introduzca a clau ta ubrir iste fichero PDF.
+password_invalid=Clau invalida. Torna a intentar-lo.
+password_ok=Acceptar
+password_cancel=Cancelar
+
+printing_not_supported=Pare cuenta: Iste navegador no maneya totalment as impresions.
+printing_not_ready=Aviso: Encara no se ha cargau completament o PDF ta imprentar-lo.
+web_fonts_disabled=As fuents web son desactivadas: no se puet incrustar fichers PDF.
+document_colors_disabled=Os documentos PDF no pueden fer servir as suyas propias colors: 'Permitir que as pachinas triguen as suyas propias colors' ye desactivau en o navegador.
diff --git a/static/pdf.js/locale/ar/viewer.properties b/static/pdf.js/locale/ar/viewer.properties
index 0c6e943e5..949b656df 100644
--- a/static/pdf.js/locale/ar/viewer.properties
+++ b/static/pdf.js/locale/ar/viewer.properties
@@ -14,99 +14,150 @@
# Main toolbar buttons (tooltips and alt text for images)
previous.title=الصÙØØ© السابقة
-previous_label=السابق
-next.title=الصÙØØ© التاليه
-next_label=التالي
+previous_label=السابقة
+next.title=الصÙØØ© التالية
+next_label=التالية
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
-page_label=الصÙØØ©:
+page_label=صÙØØ©:
page_of=من {{pageCount}}
-zoom_out.title=تصغير
-zoom_out_label=تصغير
-zoom_in.title=تكبير
-zoom_in_label=تكبير
-zoom.title=التكبير
-fullscreen.title=ملء الشاشة
-fullscreen_label=ملء الشاشة
-open_file.title=ÙØªØ Ø§Ù„Ù…Ù„Ù
-open_file_label=ÙتØ
-print.title=طباعة
-print_label=طباعة
-download.title=تØميل
-download_label=تØميل
-bookmark.title=المشهد الØالي (نسخ أو ÙØªØ ÙÙŠ ناÙذة جديدة)
-bookmark_label=المشهد الØالي
+zoom_out.title=بعّد
+zoom_out_label=بعّد
+zoom_in.title=قرّب
+zoom_in_label=قرّب
+zoom.title=التقريب
+presentation_mode.title=انتقل لوضع العرض التقديمي
+presentation_mode_label=وضع العرض التقديمي
+open_file.title=اÙØªØ Ù…Ù„Ùًا
+open_file_label=اÙتØ
+print.title=اطبع
+print_label=اطبع
+download.title=نزّل
+download_label=نزّل
+bookmark.title=المنظور الØالي (انسخ أو اÙØªØ ÙÙŠ ناÙذة جديدة)
+bookmark_label=المنظور الØالي
# Secondary toolbar and context menu
-page_rotate_cw.title=تدوير مع عقارب الساعة
-page_rotate_cw.label=تدوير مع عقارب الساعة
-page_rotate_cw_label=تدوير مع عقارب الساعة
-page_rotate_ccw.title=تدوير عكس عقارب الساعة
-page_rotate_ccw.label=تدوير عكس عقارب الساعة
-page_rotate_ccw_label=تدوير عكس عقارب الساعة
+tools.title=الأدوات
+tools_label=الأدوات
+first_page.title=اذهب إلى الصÙØØ© الأولى
+first_page.label=اذهب إلى الصÙØØ© الأولى
+first_page_label=اذهب إلى الصÙØØ© الأولى
+last_page.title=اذهب إلى الصÙØØ© الأخيرة
+last_page.label=اذهب إلى الصÙØØ© الأخيرة
+last_page_label=اذهب إلى الصÙØØ© الأخيرة
+page_rotate_cw.title=أدر باتجاه عقارب الساعة
+page_rotate_cw.label=أدر باتجاه عقارب الساعة
+page_rotate_cw_label=أدر باتجاه عقارب الساعة
+page_rotate_ccw.title=أدر بعكس اتجاه عقارب الساعة
+page_rotate_ccw.label=أدر بعكس اتجاه عقارب الساعة
+page_rotate_ccw_label=أدر بعكس اتجاه عقارب الساعة
+
+hand_tool_enable.title=Ùعّل أداة اليد
+hand_tool_enable_label=Ùعّل أداة اليد
+hand_tool_disable.title=عطّل أداة اليد
+hand_tool_disable_label=عطّل أداة اليد
+
+# Document properties dialog box
+document_properties.title=خصائص المستند…
+document_properties_label=خصائص المستند…
+document_properties_file_name=اسم الملÙ:
+document_properties_file_size=Øجم الملÙ:
+document_properties_kb={{size_kb}} ك.بايت ({{size_b}} بايت)
+document_properties_mb={{size_mb}} م.بايت ({{size_b}} بايت)
+document_properties_title=العنوان:
+document_properties_author=المؤلÙ:
+document_properties_subject=الموضوع:
+document_properties_keywords=الكلمات الأساسية:
+document_properties_creation_date=تاريخ الإنشاء:
+document_properties_modification_date=تاريخ التعديل:
+document_properties_date_string={{date}}، {{time}}
+document_properties_creator=المنشئ:
+document_properties_producer=منتج PDF:
+document_properties_version=إصدارة PDF:
+document_properties_page_count=عدد الصÙØات:
+document_properties_close=أغلق
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_slider.title=تبديل الزلاق
-toggle_slider_label=تبديل الزلاق
-outline.title=إظهار ملخص المستند
-outline_label=ملخص المستند
-thumbs.title=إظهار الصور المصغرة
-thumbs_label=الصور المصغرة
-findbar.title=البØØ« ÙÙŠ المستند
-findbar_label=بØØ«
+toggle_sidebar.title=بدّل الشريط الجانبي
+toggle_sidebar_label=بدّل الشريط الجانبي
+outline.title=اعرض مخطط المستند
+outline_label=مخطط المستند
+attachments.title=اعرض المرÙقات
+attachments_label=المÙرÙقات
+thumbs.title=اعرض Ù…Ùصغرات
+thumbs_label=Ù…Ùصغّرات
+findbar.title=ابØØ« ÙÙŠ المستند
+findbar_label=ابØØ«
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
# number.
-thumb_page_title=الصÙØØ© {{page}}
+thumb_page_title=صÙØØ© {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=صورة مصغرة من الصÙØØ© {{page}}
+thumb_page_canvas=مصغّرة صÙØØ© {{page}}
# Find panel button title and messages
-find=بØØ«
-find_terms_not_found=(لا يوجد)
+find_label=ابØØ«:
+find_previous.title=ابØØ« عن التّواجد السّابق للعبارة
+find_previous_label=السابق
+find_next.title=ابØØ« عن التّواجد التّالي للعبارة
+find_next_label=التالي
+find_highlight=أبرÙز الكل
+find_match_case_label=طابق Øالة الأØرÙ
+find_reached_top=تابعت من الأسÙÙ„ بعدما وصلت إلى بداية المستند
+find_reached_bottom=تابعت من الأعلى بعدما وصلت إلى نهاية المستند
+find_not_found=لا وجود للعبارة
# Error panel labels
-error_more_info=مزيد من المعلومات
+error_more_info=معلومات أكثر
error_less_info=معلومات أقل
-error_close=إغلاق
-# LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
-# build ID.
-error_build=بناء PDF.JS: {{build}}
+error_close=أغلق
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=â€PDF.js Ù†{{version}} â€(بناء: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=رسالة: {{message}}
+error_message=الرسالة: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
-error_stack=المكدس: {{stack}}
+error_stack=الرصّة: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=الملÙ: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=السطر: {{line}}
-rendering_error=Øدث خطأ اثناء رسم الصÙØØ©.
+rendering_error=Øدث خطأ أثناء عرض الصÙØØ©.
# Predefined zoom values
page_scale_width=عرض الصÙØØ©
-page_scale_fit=تناسب الصÙØØ©
+page_scale_fit=ملائمة الصÙØØ©
page_scale_auto=تقريب تلقائي
page_scale_actual=الØجم الØقيقي
# Loading indicator messages
-loading_error_indicator=خطأ
-loading_error=Øدث خطأ أثناء تØميل وثيقه الـPDF
+loading_error_indicator=عطل
+loading_error=Øدث عطل أثناء تØميل مل٠PDF.
+invalid_file_error=مل٠PDF تال٠أو غير صØÙŠØ
+missing_file_error=مل٠PDF غير موجود
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[ملاØظة {{type}}]
-request_password=الـPDF Ù…Øمي بكلمة مرور:
+text_annotation_type.alt=[تعليق {{type}}]
+password_label=أدخل لكلمة السر Ù„ÙØªØ Ù‡Ø°Ø§ الملÙ.
+password_invalid=كلمة سر خطأ. من Ùضلك أعد المØاولة.
+password_ok=Øسنا
+password_cancel=ألغÙ
-printing_not_supported=تØذير: الطباعة ليست مدعومة كليًا ÙÙŠ هذا المتصÙØ.
+printing_not_supported=تØذير: لا يدعم هذا المتصÙØ Ø§Ù„Ø·Ø¨Ø§Ø¹Ø© بشكل كامل.
+printing_not_ready=تØذير: مل٠PDF لم ÙŠÙØمّل كاملًا للطباعة.
+web_fonts_disabled=خطوط الوب Ù…Ùعطّلة: تعذّر استخدام خطوط PDF المÙضمّنة.
+document_colors_disabled=ليس مسموØًا لملÙات PDF باستخدام ألوانها الخاصة: خيار 'Ø§Ø³Ù…Ø Ù„Ù„ØµÙØات باختيار ألوانها الخاصة' ليس Ù…ÙÙعّلًا ÙÙŠ المتصÙØ.
diff --git a/static/pdf.js/locale/as/viewer.properties b/static/pdf.js/locale/as/viewer.properties
new file mode 100644
index 000000000..852ad0308
--- /dev/null
+++ b/static/pdf.js/locale/as/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=পূৰà§à¦¬à§±à§°à§à¦¤à§€ পৃষà§à¦ া
+previous_label=পূৰà§à¦¬à§±à§°à§à¦¤à§€
+next.title=পৰৱৰà§à¦¤à§€ পৃষà§à¦ া
+next_label=পৰৱৰà§à¦¤à§€
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=পৃষà§à¦ া:
+page_of=ৰ {{pageCount}}
+
+zoom_out.title=জà§à¦® আউট
+zoom_out_label=জà§à¦® আউট
+zoom_in.title=জà§à¦® ইন
+zoom_in_label=জà§à¦® ইন
+zoom.title=জà§à¦® কৰক
+presentation_mode.title=উপসà§à¦¥à¦¾à¦ªà¦¨ অৱসà§à¦¥à¦¾à¦²à§‡ যাওক
+presentation_mode_label=উপসà§à¦¥à¦¾à¦ªà¦¨ অৱসà§à¦¥à¦¾
+open_file.title=ফাইল খোলক
+open_file_label=খোলক
+print.title=পà§à§°à¦¿à¦¨à§à¦Ÿ কৰক
+print_label=পà§à§°à¦¿à¦¨à§à¦Ÿ কৰক
+download.title=ডাউনল'ড কৰক
+download_label=ডাউনল'ড কৰক
+bookmark.title=বৰà§à¦¤à¦®à¦¾à¦¨ দৃশà§à¦¯ (কপি কৰক অথবা নতà§à¦¨ উইনà§à¦¡à§‹à¦¤ খোলক)
+bookmark_label=বৰà§à¦¤à¦®à¦¾à¦¨ দৃশà§à¦¯
+
+# Secondary toolbar and context menu
+tools.title=সà¦à¦œà§à¦²à¦¿à¦¸à¦®à§‚হ
+tools_label=সà¦à¦œà§à¦²à¦¿à¦¸à¦®à§‚হ
+first_page.title=পà§à§°à¦¥à¦® পৃষà§à¦ াত যাওক
+first_page.label=পà§à§°à¦¥à¦® পৃষà§à¦ াত যাওক
+first_page_label=পà§à§°à¦¥à¦® পৃষà§à¦ াত যাওক
+last_page.title=সৰà§à¦¬à¦¶à§‡à¦· পৃষà§à¦ াত যাওক
+last_page.label=সৰà§à¦¬à¦¶à§‡à¦· পৃষà§à¦ াত যাওক
+last_page_label=সৰà§à¦¬à¦¶à§‡à¦· পৃষà§à¦ াত যাওক
+page_rotate_cw.title=ঘড়ীৰ দিশত ঘà§à§°à¦¾à¦“ক
+page_rotate_cw.label=ঘড়ীৰ দিশত ঘà§à§°à¦¾à¦“ক
+page_rotate_cw_label=ঘড়ীৰ দিশত ঘà§à§°à¦¾à¦“ক
+page_rotate_ccw.title=ঘড়ীৰ ওলোটা দিশত ঘà§à§°à¦¾à¦“ক
+page_rotate_ccw.label=ঘড়ীৰ ওলোটা দিশত ঘà§à§°à¦¾à¦“ক
+page_rotate_ccw_label=ঘড়ীৰ ওলোটা দিশত ঘà§à§°à¦¾à¦“ক
+
+hand_tool_enable.title=হাà¦à¦¤ সà¦à¦œà§à¦²à¦¿ সামৰà§à¦¥à¦¬à¦¾à¦¨ কৰক
+hand_tool_enable_label=হাà¦à¦¤ সà¦à¦œà§à¦²à¦¿ সামৰà§à¦¥à¦¬à¦¾à¦¨ কৰক
+hand_tool_disable.title=হাà¦à¦¤ সà¦à¦œà§à¦²à¦¿ অসামৰà§à¦¥à¦¬à¦¾à¦¨ কৰক
+hand_tool_disable_label=হাà¦à¦¤ সà¦à¦œà§à¦²à¦¿ অসামৰà§à¦¥à¦¬à¦¾à¦¨ কৰক
+
+# Document properties dialog box
+document_properties.title=দসà§à¦¤à¦¾à¦¬à§‡à¦œà§° বৈশিষà§à¦Ÿà§à¦¯à¦¸à¦®à§‚হ…
+document_properties_label=দসà§à¦¤à¦¾à¦¬à§‡à¦œà§° বৈশিষà§à¦Ÿà§à¦¯à¦¸à¦®à§‚হ…
+document_properties_file_name=ফাইল নাম:
+document_properties_file_size=ফাইলৰ আকাৰ:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=শীৰà§à¦·à¦•:
+document_properties_author=লেখক:
+document_properties_subject=বিষয়:
+document_properties_keywords=কিৱাৰà§à¦¡à¦¸à¦®à§‚হ:
+document_properties_creation_date=সৃষà§à¦Ÿà¦¿à§° তাৰিখ:
+document_properties_modification_date=পৰিবৰà§à¦¤à¦¨à§° তাৰিখ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=সৃষà§à¦Ÿà¦¿à¦•à§°à§à¦¤à¦¾:
+document_properties_producer=PDF উৎপাদক:
+document_properties_version=PDF সংসà§à¦•à§°à¦£:
+document_properties_page_count=পৃষà§à¦ াৰ গণনা:
+document_properties_close=বনà§à¦§ কৰক
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=কাষবাৰ টগল কৰক
+toggle_sidebar_label=কাষবাৰ টগল কৰক
+outline.title=দসà§à¦¤à¦¾à¦¬à§‡à¦œ আউটলাইন দেখà§à§±à¦¾à¦“ক
+outline_label=দসà§à¦¤à¦¾à¦¬à§‡à¦œ আউটলাইন
+attachments.title=à¦à¦Ÿà¦¾à¦šà¦®à§‡à¦¨à§à¦Ÿà¦¸à¦®à§‚হ দেখà§à§±à¦¾à¦“ক
+attachments_label=à¦à¦Ÿà¦¾à¦šà¦®à§‡à¦¨à§à¦Ÿà¦¸à¦®à§‚হ
+thumbs.title=থামà§à¦¬à¦¨à§‡à¦‡à¦²à¦¸à¦®à§‚হ দেখà§à§±à¦¾à¦“ক
+thumbs_label=থামà§à¦¬à¦¨à§‡à¦‡à¦²à¦¸à¦®à§‚হ
+findbar.title=দসà§à¦¤à¦¾à¦¬à§‡à¦œà¦¤ সনà§à¦§à¦¾à¦¨ কৰক
+findbar_label=সনà§à¦§à¦¾à¦¨ কৰক
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=পৃষà§à¦ া {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=পৃষà§à¦ াৰ থামà§à¦¬à¦¨à§‡à¦‡à¦² {{page}}
+
+# Find panel button title and messages
+find_label=সনà§à¦§à¦¾à¦¨ কৰক:
+find_previous.title=বাকà§à¦¯à¦¾à¦‚শৰ পূৰà§à¦¬à§±à§°à§à¦¤à§€ উপসà§à¦¥à¦¿à¦¤à¦¿ সনà§à¦§à¦¾à¦¨ কৰক
+find_previous_label=পূৰà§à¦¬à§±à§°à§à¦¤à§€
+find_next.title=বাকà§à¦¯à¦¾à¦‚শৰ পৰৱৰà§à¦¤à§€ উপসà§à¦¥à¦¿à¦¤à¦¿ সনà§à¦§à¦¾à¦¨ কৰক
+find_next_label=পৰৱৰà§à¦¤à§€
+find_highlight=সকলো উজà§à¦œà§à¦¬à¦² কৰক
+find_match_case_label=ফলা মিলাওক
+find_reached_top=তলৰ পৰা আৰমà§à¦ কৰি, দসà§à¦¤à¦¾à¦¬à§‡à¦œà§° ওপৰলৈ অহা হৈছে
+find_reached_bottom=ওপৰৰ পৰা আৰমà§à¦ কৰি, দসà§à¦¤à¦¾à¦¬à§‡à¦œà§° তললৈ অহা হৈছে
+find_not_found=বাকà§à¦¯à¦¾à¦‚শ পোৱা নগল
+
+# Error panel labels
+error_more_info=অধিক তথà§à¦¯
+error_less_info=কম তথà§à¦¯
+error_close=বনà§à¦§ কৰক
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=বাৰà§à¦¤à¦¾: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=সà§à¦Ÿà§‡à¦•: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ফাইল: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=শাৰী: {{line}}
+rendering_error=à¦à¦‡ পৃষà§à¦ া ৰেণà§à¦¡à¦¾à§° কৰোতে à¦à¦Ÿà¦¾ তà§à§°à§à¦Ÿà¦¿ দেখা দিলে।
+
+# Predefined zoom values
+page_scale_width=পৃষà§à¦ াৰ পà§à§°à¦¸à§à¦¥
+page_scale_fit=পৃষà§à¦ া খাপ
+page_scale_auto=সà§à¦¬à¦šà¦¾à¦²à¦¿à¦¤ জà§à¦®
+page_scale_actual=পà§à§°à¦•à§ƒà¦¤ আকাৰ
+
+# Loading indicator messages
+loading_error_indicator=তà§à§°à§à¦Ÿà¦¿
+loading_error=PDF ল'ড কৰোতে à¦à¦Ÿà¦¾ তà§à§°à§à¦Ÿà¦¿ দেখা দিলে।
+invalid_file_error=অবৈধ অথবা কà§à¦·à¦¤à¦¿à¦—à§à§°à¦¸à§à¦¥ PDF file।
+missing_file_error=সনà§à¦§à¦¾à¦¨à¦¹à¦¿à¦¨ PDF ফাইল।
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} টোকা]
+password_label=à¦à¦‡ PDF ফাইল খোলিবলৈ পাছৱৰà§à¦¡ সà§à¦®à§à§±à¦¾à¦“ক।
+password_invalid=অবৈধ পাছৱৰà§à¦¡à¥¤ অনà§à¦—à§à§°à¦¹ কৰি পà§à¦¨à§° চেষà§à¦Ÿà¦¾ কৰক।
+password_ok=ঠিক আছে
+password_cancel=বাতিল কৰক
+
+printing_not_supported=সতৰà§à¦•à¦¬à¦¾à§°à§à¦¤à¦¾: পà§à§°à¦¿à¦¨à§à¦Ÿà¦¿à¦‚ à¦à¦‡ বà§à§°à¦¾à¦‰à¦›à¦¾à§° দà§à¦¬à¦¾à§°à¦¾ সমà§à¦ªà§‚ৰà§à¦£à¦à¦¾à§±à§‡ সমৰà§à¦¥à¦¿à¦¤ নহয়।
+printing_not_ready=সতৰà§à¦•à¦¬à¦¾à§°à§à¦¤à¦¾: PDF পà§à§°à¦¿à¦¨à§à¦Ÿà¦¿à¦‚ৰ বাবে সমà§à¦ªà§‚ৰà§à¦£à¦à¦¾à§±à§‡ ল'ডেড নহয়।
+web_fonts_disabled=ৱেব ফনà§à¦Ÿà¦¸à¦®à§‚হ অসামৰà§à¦¥à¦¬à¦¾à¦¨ কৰা আছে: অনà§à¦¤à§°à§à¦à§à¦•à§à¦¤ PDF ফনà§à¦Ÿà¦¸à¦®à§‚হ বà§à¦¯à§±à¦¹à¦¾à§° কৰিবলে অকà§à¦·à¦®à¥¤
+document_colors_disabled=PDF দসà§à¦¤à¦¾à¦¬à§‡à¦œà¦¸à¦®à§‚হৰ সিহতৰ নিজসà§à¦¬ ৰঙ বà§à¦¯à§±à¦¹à¦¾à§° কৰাৰ অনà§à¦®à¦¤à¦¿ নাই: বà§à§°à¦¾à¦‰à¦›à¦¾à§°à¦¤ 'পৃষà§à¦ াসমূহক সিহতৰ নিজসà§à¦¬ ৰঙ নিৰà§à¦¬à¦¾à¦šà¦¨ কৰাৰ অনà§à¦®à¦¤à¦¿ দিয়ক' অসামৰà§à¦¥à¦¬à¦¾à¦¨ কৰা আছে।
diff --git a/static/pdf.js/locale/ast/viewer.properties b/static/pdf.js/locale/ast/viewer.properties
new file mode 100644
index 000000000..fd5fb11db
--- /dev/null
+++ b/static/pdf.js/locale/ast/viewer.properties
@@ -0,0 +1,107 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+previous.title = Páxina anterior
+previous_label = Anterior
+next.title = Páxina siguiente
+next_label = Siguiente
+page_label = Páxina:
+page_of = de {{pageCount}}
+zoom_out.title = Reducir
+zoom_out_label = Reducir
+zoom_in.title = Aumentar
+zoom_in_label = Aumentar
+zoom.title = Tamañu
+print.title = Imprentar
+print_label = Imprentar
+open_file.title = Abrir ficheru
+open_file_label = Abrir
+download.title = Descargar
+download_label = Descargar
+bookmark.title = Vista actual (copiar o abrir nuna nueva ventana)
+bookmark_label = Vista actual
+outline.title = Amosar l'esquema del documentu
+outline_label = Esquema del documentu
+thumbs.title = Amosar miniatures
+thumbs_label = Miniatures
+thumb_page_title = Páxina {{page}}
+thumb_page_canvas = Miniatura de la páxina {{page}}
+error_more_info = Más información
+error_less_info = Menos información
+error_close = Zarrar
+error_message = Mensaxe: {{message}}
+error_stack = Pila: {{stack}}
+error_file = Ficheru: {{file}}
+error_line = Llinia: {{line}}
+rendering_error = Hebo un fallu al renderizar la páxina.
+page_scale_width = Anchor de la páxina
+page_scale_fit = Axuste de la páxina
+page_scale_auto = Tamañu automáticu
+page_scale_actual = Tamañu actual
+loading_error_indicator = Fallu
+loading_error = Hebo un fallu al cargar el PDF.
+printing_not_supported = Avisu: Imprentar nun tien sofitu téunicu completu nesti navegador.
+presentation_mode_label =
+presentation_mode.title =
+page_rotate_cw.label =
+page_rotate_ccw.label =
+last_page.label = Dir a la cabera páxina
+invalid_file_error = Ficheru PDF inválidu o corruptu.
+first_page.label = Dir a la primer páxina
+findbar_label = Guetar
+findbar.title = Guetar nel documentu
+find_previous_label = Anterior
+find_previous.title = Alcontrar l'anterior apaición de la fras
+find_not_found = Frase non atopada
+find_next_label = Siguiente
+find_next.title = Alcontrar la siguiente apaición d'esta fras
+find_match_case_label = Coincidencia de mayús./minús.
+find_label = Guetar:
+find_highlight = Remarcar toos
+find_reached_top=Algamóse'l principiu del documentu, siguir dende'l final
+find_reached_bottom=Algamóse'l final del documentu, siguir dende'l principiu
+web_fonts_disabled = Les fontes web tán desactivaes: ye imposible usar les fontes PDF embebÃes.
+toggle_sidebar_label = Camudar barra llateral
+toggle_sidebar.title = Camudar barra llateral
+missing_file_error = Nun hai ficheru PDF.
+error_version_info = PDF.js v{{version}} (build: {{build}})
+printing_not_ready = Avisu: Esti PDF nun se cargó completamente pa poder imprentase.
+text_annotation_type.alt = [Anotación {{type}}]
+document_colors_disabled = Los documentos PDF nun tienen permitÃo usar los sos propios colores: 'Permitir a les páxines elexir los sos propios colores' ta desactivao nel navegador.
+tools_label = Ferramientes
+tools.title = Ferramientes
+password_ok = Aceutar
+password_label = Introduz la contraseña p'abrir esti ficheru PDF
+password_invalid = Contraseña non válida. Vuelvi a intentalo.
+password_cancel = Encaboxar
+page_rotate_cw_label = Xirar en sen horariu
+page_rotate_cw.title = Xirar en sen horariu
+page_rotate_ccw_label = Xirar en sen antihorariu
+page_rotate_ccw.title = Xirar en sen antihorariu
+last_page_label = Dir a la postrer páxina
+last_page.title = Dir a la postrer páxina
+hand_tool_enable_label = Activar ferramienta mano
+hand_tool_enable.title = Activar ferramienta mano
+hand_tool_disable_label = Desactivar ferramienta mano
+hand_tool_disable.title = Desactivar ferramienta mano
+first_page_label = Dir a la primer páxina
+first_page.title = Dir a la primer páxina
+document_properties_version = Versión PDF:
+document_properties_title = TÃtulu:
+document_properties_subject = Asuntu:
+document_properties_producer = Productor PDF:
+document_properties_page_count = Númberu de páxines:
+document_properties_modification_date = Data de modificación:
+document_properties_mb = {{size_mb}} MB ({{size_b}} bytes)
+document_properties_label = Propiedaes del documentu…
+document_properties_keywords = Pallabres clave:
+document_properties_kb = {{size_kb}} KB ({{size_b}} bytes)
+document_properties_file_size = Tamañu de ficheru:
+document_properties_file_name = Nome de ficheru:
+document_properties_date_string = {{date}}, {{time}}
+document_properties_creator = Creador:
+document_properties_creation_date = Data de creación:
+document_properties_close = Zarrar
+document_properties_author = Autor:
+document_properties.title = Propiedaes del documentu…
diff --git a/static/pdf.js/locale/az/viewer.properties b/static/pdf.js/locale/az/viewer.properties
new file mode 100644
index 000000000..c9bea3b43
--- /dev/null
+++ b/static/pdf.js/locale/az/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=ÆvvÉ™lki sÉ™hifÉ™
+previous_label=ÆvvÉ™lkini tap
+next.title=Növbəti səhifə
+next_label=İrəli
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Səhifə:
+page_of=/ {{pageCount}}
+
+zoom_out.title=UzaqlaÅŸ
+zoom_out_label=UzaqlaÅŸ
+zoom_in.title=Yaxınlaş
+zoom_in_label=Yaxınlaş
+zoom.title=Yaxınlaşdırma
+presentation_mode.title=Təqdimat Rejiminə Keç
+presentation_mode_label=Təqdimat Rejimi
+open_file.title=Fayl Aç
+open_file_label=Aç
+print.title=Yazdır
+print_label=Yazdır
+download.title=Yüklə
+download_label=Yüklə
+bookmark.title=Hazırkı görünüş (köçür və ya yeni pəncərədə aç)
+bookmark_label=Hazırki görünüş
+
+# Secondary toolbar and context menu
+tools.title=Alətlər
+tools_label=Alətlər
+first_page.title=İlk Səhifəyə get
+first_page.label=İlk Səhifəyə get
+first_page_label=İlk Səhifəyə get
+last_page.title=Son Səhifəyə get
+last_page.label=Son Səhifəyə get
+last_page_label=Son Səhifəyə get
+page_rotate_cw.title=Saat İstiqamətində Fırlat
+page_rotate_cw.label=Saat İstiqamətində Fırlat
+page_rotate_cw_label=Saat İstiqamətində Fırlat
+page_rotate_ccw.title=Saat Ä°stiqamÉ™tinin ÆksinÉ™ Fırlat
+page_rotate_ccw.label=Saat Ä°stiqamÉ™tinin ÆksinÉ™ Fırlat
+page_rotate_ccw_label=Saat Ä°stiqamÉ™tinin ÆksinÉ™ Fırlat
+
+hand_tool_enable.title=Æl alÉ™tini aktiv et
+hand_tool_enable_label=Æl alÉ™tini aktiv et
+hand_tool_disable.title=Æl alÉ™tini deaktiv et
+hand_tool_disable_label=Æl alÉ™tini deaktiv et
+
+# Document properties dialog box
+document_properties.title=Sənəd xüsusiyyətləri…
+document_properties_label=Sənəd xüsusiyyətləri…
+document_properties_file_name=Fayl adı:
+document_properties_file_size=Fayl ölçüsü:
+document_properties_kb={{size_kb}} KB ({{size_b}} bayt)
+document_properties_mb={{size_mb}} MB ({{size_b}} bayt)
+document_properties_title=Başlık:
+document_properties_author=Müəllif:
+document_properties_subject=Mövzu:
+document_properties_keywords=Açar sözlər:
+document_properties_creation_date=Yaradılış Tarixi :
+document_properties_modification_date=Dəyişdirilmə Tarixi :
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Yaradan:
+document_properties_producer=PDF yaradıcısı:
+document_properties_version=PDF versiyası:
+document_properties_page_count=Səhifə sayı:
+document_properties_close=Qapat
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Yan Paneli Aç/Bağla
+toggle_sidebar_label=Yan Paneli Aç/Bağla
+outline.title=Sənəd struktunu göstər
+outline_label=Sənəd strukturu
+attachments.title=Bağlamaları göstər
+attachments_label=BaÄŸlamalar
+thumbs.title=Kiçik şəkilləri göstər
+thumbs_label=Kiçik şəkillər
+findbar.title=Sənəddə Tap
+findbar_label=Axtar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Səhifə{{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}} səhifəsinin kiçik vəziyyəti
+
+# Find panel button title and messages
+find_label=Tap:
+find_previous.title=Bir öncəki uyğun gələn sözü tapır
+find_previous_label=Geri
+find_next.title=Bir sonrakı uyğun gələn sözü tapır
+find_next_label=İrəli
+find_highlight=İşarələ
+find_match_case_label=Böyük/kiçik hərfə həssaslıq
+find_reached_top=Sənədin yuxarısına çatdı, aşağıdan davam edir
+find_reached_bottom=Sənədin sonuna çatdı, yuxarıdan davam edir
+find_not_found=Uyğunlaşma tapılmadı
+
+# Error panel labels
+error_more_info=Daha çox məlumati
+error_less_info=Daha az məlumat
+error_close=Qapat
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (yığma: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=İsmarıc: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stek: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fayl: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Sətir: {{line}}
+rendering_error=Səhifə göstərilərkən səhv yarandı.
+
+# Predefined zoom values
+page_scale_width=Səhifə genişliyi
+page_scale_fit=Səhifəni sığdır
+page_scale_auto=Avtomatik yaxınlaşdır
+page_scale_actual=Hazırki Həcm
+
+# Loading indicator messages
+loading_error_indicator=Səhv
+loading_error=PDF yüklenərkən bir səhv yarandı.
+invalid_file_error=Səhv və ya zədələnmiş olmuş PDF fayl.
+missing_file_error=PDF fayl yoxdur.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotasiyası]
+password_label=Bu PDF faylı açmaq üçün şifrəni daxil edin.
+password_invalid=Şifrə yanlışdır. Bir daha sınayın.
+password_ok=OK
+password_cancel=Ləğv et
+
+printing_not_supported=Xəbərdarlıq: Çap bu səyyah tərəfindən tam olaraq dəstəklənmir.
+printing_not_ready=Xəbərdarlıq: PDF çap üçün tam yüklənməyib.
+web_fonts_disabled=Web Şriftlər söndürülüb: yerləşdirilmiş PDF şriftlərini istifadə etmək mümkün deyil.
+document_colors_disabled=PDF sənədlərə öz rənglərini işlətməyə icazə verilmir: 'Səhifələrə öz rənglərini istifadə etməyə icazə vermə' səyyahda söndürülüb.
diff --git a/static/pdf.js/locale/be/viewer.properties b/static/pdf.js/locale/be/viewer.properties
new file mode 100644
index 000000000..031b1df5d
--- /dev/null
+++ b/static/pdf.js/locale/be/viewer.properties
@@ -0,0 +1,105 @@
+previous.title = ПапÑÑ€ÑднÑÑ Ñтаронка
+previous_label = ПапÑÑ€ÑднÑÑ
+next.title = ÐаÑÑ‚ÑƒÐ¿Ð½Ð°Ñ Ñтаронка
+next_label = ÐаÑтупнаÑ
+page_label = Старонка:
+page_of = з {{pageCount}}
+zoom_out.title = Паменшыць
+zoom_out_label = Паменшыць
+zoom_in.title = ПавÑлічыць
+zoom_in_label = ПавÑлічыць
+zoom.title = ПавÑлічÑнне Ñ‚ÑкÑту
+presentation_mode.title = Пераключыцца Ñž Ñ€Ñжым паказу
+presentation_mode_label = Ð Ñжым паказу
+open_file.title = Ðдчыніць файл
+open_file_label = Ðдчыніць
+print.title = Друкаваць
+print_label = Друкаваць
+download.title = Загрузка
+download_label = Загрузка
+bookmark.title = ЦÑперашнÑÑ Ð¿Ñ€Ð°Ñва (ÑкапіÑваць або адчыніць у новым акне)
+bookmark_label = ЦÑперашнÑÑ Ð¿Ñ€Ð°Ñва
+tools.title = Прылады
+tools_label = Прылады
+first_page.title = ПерайÑці на першую Ñтаронку
+first_page.label = ПерайÑці на першую Ñтаронку
+first_page_label = ПерайÑці на першую Ñтаронку
+last_page.title = ПерайÑці на апошнюю Ñтаронку
+last_page.label = ПерайÑці на апошнюю Ñтаронку
+last_page_label = ПерайÑці на апошнюю Ñтаронку
+page_rotate_cw.title = ПавÑрнуць па гадзіннікавай ÑÑ‚Ñ€Ñлцы
+page_rotate_cw.label = ПавÑрнуць па гадзіннікавай ÑÑ‚Ñ€Ñлцы
+page_rotate_cw_label = ПавÑрнуць па гадзіннікавай ÑÑ‚Ñ€Ñлцы
+page_rotate_ccw.title = ПавÑрнуць Ñупраць гадзіннікавай ÑÑ‚Ñ€Ñлкі
+page_rotate_ccw.label = ПавÑрнуць Ñупраць гадзіннікавай ÑÑ‚Ñ€Ñлкі
+page_rotate_ccw_label = ПавÑрнуць Ñупраць гадзіннікавай ÑÑ‚Ñ€Ñлкі
+hand_tool_enable.title = Дазволіць ручную прыладу
+hand_tool_enable_label = Дазволіць ручную прыладу
+hand_tool_disable.title = Забараніць ручную прыладу
+hand_tool_disable_label = Забараніць ручную прыладу
+document_properties.title = УлаÑціваÑці дакумента…
+document_properties_label = УлаÑціваÑці дакумента…
+document_properties_file_name = Ðазва файла:
+document_properties_file_size = Памер файла:
+document_properties_kb = {{size_kb}} КБ ({{size_b}} байт)
+document_properties_mb = {{size_mb}} МБ ({{size_b}} байт)
+document_properties_title = Загаловак:
+document_properties_author = Ðўтар:
+document_properties_subject = ТÑма:
+document_properties_keywords = ÐšÐ»ÑŽÑ‡Ð°Ð²Ñ‹Ñ Ñловы:
+document_properties_creation_date = Дата ÑтварÑннÑ:
+document_properties_modification_date = Дата змÑненнÑ:
+document_properties_date_string = {{date}}, {{time}}
+document_properties_creator = Стваральнік:
+document_properties_producer = Вырабнік PDF:
+document_properties_version = ВерÑÑ–Ñ PDF:
+document_properties_page_count = КолькаÑць Ñтаронак:
+document_properties_close = Зачыніць
+toggle_sidebar.title = ПераключÑнне палічкі
+toggle_sidebar_label = Пераключыць палічку
+outline.title = Паказ будовы дакумента
+outline_label = Будова дакумента
+attachments.title = Паказаць далучÑнні
+attachments_label = ДалучÑнні
+thumbs.title = Паказ накідаў
+thumbs_label = Ðакіды
+findbar.title = Пошук у дакуменце
+findbar_label = ЗнайÑці
+thumb_page_title = Старонка {{page}}
+thumb_page_canvas = Ðакід Ñтаронкі {{page}}
+find_label = Пошук:
+find_previous.title = ЗнайÑці папÑÑ€Ñдні выпадак выразу
+find_previous_label = ПапÑÑ€Ñдні
+find_next.title = ЗнайÑці наÑтупны выпадак выразу
+find_next_label = ÐаÑтупны
+find_highlight = Падфарбаваць уÑе
+find_match_case_label = Ðдрозніваць вÑлікіÑ/Ð¼Ð°Ð»Ñ‹Ñ Ð»Ñ–Ñ‚Ð°Ñ€Ñ‹
+find_reached_top = ДаÑÑгнуты пачатак дакумента, працÑг з канца
+find_reached_bottom = ДаÑÑгнуты канец дакумента, працÑг з пачатку
+find_not_found = Выраз не знойдзены
+error_more_info = ПадрабÑзней
+error_less_info = СціÑла
+error_close = Закрыць
+error_version_info = PDF.js в{{version}} (пабудова: {{build}})
+error_message = Паведамленне: {{message}}
+error_stack = СтоÑ: {{stack}}
+error_file = Файл: {{file}}
+error_line = Радок: {{line}}
+rendering_error = ЗдарылаÑÑ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ° Ð¿Ð°Ð´Ñ‡Ð°Ñ Ð°Ð´Ð»ÑŽÑÑ‚Ñ€Ð°Ð²Ð°Ð½Ð½Ñ Ñтаронкі.
+page_scale_width = Ð¨Ñ‹Ñ€Ñ‹Ð½Ñ Ñтаронкі
+page_scale_fit = УціÑненне Ñтаронкі
+page_scale_auto = СамаÑтойнае павÑлічÑнне
+page_scale_actual = Сапраўдны памер
+loading_error_indicator = Памылка
+loading_error = ЗдарылаÑÑ Ð¿Ð°Ð¼Ñ‹Ð»ÐºÐ° Ð¿Ð°Ð´Ñ‡Ð°Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÑ– PDF.
+invalid_file_error = ÐÑÑпраўны або пашкоджаны файл PDF.
+missing_file_error = ÐдÑутны файл PDF.
+text_annotation_type.alt = [{{type}} Annotation]
+password_label = УвÑдзіце пароль, каб адчыніць гÑÑ‚Ñ‹ файл PDF.
+password_invalid = Крывы пароль. ПаÑпрабуйце зноў.
+password_ok = Добра
+password_cancel = СкаÑаваць
+printing_not_supported = ПапÑÑ€Ñджанне: друк не падтрымлівацца цалкам гÑтым азіральнікам.
+printing_not_ready = Увага: PDF не ÑцÑгнуты цалкам Ð´Ð»Ñ Ð´Ñ€ÑƒÐºÐ°Ð²Ð°Ð½Ð½Ñ.
+web_fonts_disabled = Шрыфты Сеціва забаронены: немгчыма ўжываць ÑƒÐºÐ»Ð°Ð´Ð·ÐµÐ½Ñ‹Ñ ÑˆÑ€Ñ‹Ñ„Ñ‚Ñ‹ PDF.
+document_colors_disabled = Дакументам PDF не дазволена карыÑтацца Ñваімі ўлаÑнымі колерамі: 'Дазволіць Ñтаронкам выбіраць Ñвае ўлаÑÐ½Ñ‹Ñ ÐºÐ¾Ð»ÐµÑ€Ñ‹' абÑздзейнена Ñž азіральніку.
diff --git a/static/pdf.js/locale/bg/viewer.properties b/static/pdf.js/locale/bg/viewer.properties
new file mode 100644
index 000000000..8681774d3
--- /dev/null
+++ b/static/pdf.js/locale/bg/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Предишна Ñтраница
+previous_label=Предишна
+next.title=Следваща Ñтраница
+next_label=Следваща
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Страница:
+page_of=от {{pageCount}}
+
+zoom_out.title=Отдалечаване
+zoom_out_label=Отдалечаване
+zoom_in.title=Приближаване
+zoom_in_label=Приближаване
+zoom.title=Мащабиране
+presentation_mode.title=Превключване към режим на предÑтавÑне
+presentation_mode_label=Режим на предÑтавÑне
+open_file.title=ОтварÑне на файл
+open_file_label=ОтварÑне
+print.title=Отпечатване
+print_label=Отпечатване
+download.title=ИзтеглÑне
+download_label=ИзтеглÑне
+bookmark.title=Текущ изглед (копиране или отварÑне в нов прозорец)
+bookmark_label=Текущ изглед
+
+# Secondary toolbar and context menu
+tools.title=ИнÑтрументи
+tools_label=ИнÑтрументи
+first_page.title=Към първата Ñтраница
+first_page.label=Към първата Ñтраница
+first_page_label=Към първата Ñтраница
+last_page.title=Към поÑледната Ñтраница
+last_page.label=Към поÑледната Ñтраница
+last_page_label=Към поÑледната Ñтраница
+page_rotate_cw.title=Превъртане по чаÑовниковата Ñтрелка
+page_rotate_cw.label=Превъртане по чаÑовниковата Ñтрелка
+page_rotate_cw_label=Превъртане по чаÑовниковата Ñтрелка
+page_rotate_ccw.title=Превъртане обратно на чаÑовниковата Ñтрелка
+page_rotate_ccw.label=Превъртане обратно на чаÑовниковата Ñтрелка
+page_rotate_ccw_label=Превъртане обратно на чаÑовниковата Ñтрелка
+
+hand_tool_enable.title=Ðктивиране на инÑтрумента ръка
+hand_tool_enable_label=Ðктивиране на инÑтрумента ръка
+hand_tool_disable.title=Деактивиране на инÑтрумента ръка
+hand_tool_disable_label=Деактивиране на инÑтрумента ръка
+
+# Document properties dialog box
+document_properties.title=СвойÑтва на документа…
+document_properties_label=СвойÑтва на документа…
+document_properties_file_name=Име на файл:
+document_properties_file_size=Големина на файл:
+document_properties_kb={{size_kb}} KiB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MiB ({{size_b}} bytes)
+document_properties_title=Заглавие:
+document_properties_author=Ðвтор:
+document_properties_subject=Тема:
+document_properties_keywords=Ключови думи:
+document_properties_creation_date=Дата на Ñъздаване:
+document_properties_modification_date=Дата на промÑна:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Създател:
+document_properties_producer=PDF произведен от:
+document_properties_version=PDF верÑиÑ:
+document_properties_page_count=Брой Ñтраници:
+document_properties_close=ЗатварÑне
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Превключване на Ñтраничната лента
+toggle_sidebar_label=Превключване на Ñтраничната лента
+outline.title=Показване на очертаниÑта на документа
+outline_label=Очертание на документа
+attachments.title=Показване на притурките
+attachments_label=Притурки
+thumbs.title=Показване на миниатюрите
+thumbs_label=Миниатюри
+findbar.title=Ðамиране в документа
+findbar_label=ТърÑене
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Страница {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Миниатюра на Ñтраница {{page}}
+
+# Find panel button title and messages
+find_label=ТърÑене:
+find_previous.title=Ðамиране на предното Ñпоменаване на тази фраза
+find_previous_label=Предишна
+find_next.title=Ðамиране на Ñледващото Ñпоменаване на тази фраза
+find_next_label=Следваща
+find_highlight=Маркирай вÑички
+find_match_case_label=Точно ÑъвпадениÑ
+find_reached_top=ДоÑтигнато е началото на документа. ТърÑенето ще продължи до ÐºÑ€Ð°Ñ Ð¼Ñƒ.
+find_reached_bottom=ДоÑтигнат е ÐºÑ€Ð°Ñ Ð½Ð° документа. ТърÑенето ще продължи от началото му.
+find_not_found=Фразата не е намерена
+
+# Error panel labels
+error_more_info=Повече информациÑ
+error_less_info=По-малко информациÑ
+error_close=ЗатварÑне
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js верÑÐ¸Ñ {{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Съобщение: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Стек: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Файл: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Ред: {{line}}
+rendering_error=Грешка при изчертаване на Ñтраницата.
+
+# Predefined zoom values
+page_scale_width=Ширина на Ñтраницата
+page_scale_fit=ВмеÑтване в Ñтраницата
+page_scale_auto=Ðвтоматично мащабиране
+page_scale_actual=ДейÑтвителен размер
+
+# Loading indicator messages
+loading_error_indicator=Грешка
+loading_error=Получи Ñе грешка при зареждане на PDF-а.
+invalid_file_error=Ðевалиден или повреден PDF файл
+missing_file_error=ЛипÑващ PDF файл.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[ÐÐ½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ {{type}}]
+password_label=Въведете парола за отварÑне на този PDF файл.
+password_invalid=Ðевалидна парола. МолÑ, опитайте отново.
+password_ok=Добре
+password_cancel=Отказ
+
+printing_not_supported=Внимание: Този браузър нÑма пълна поддръжка на отпечатване.
+printing_not_ready=Внимание: Този PDF файл не е напълно зареден за печат.
+web_fonts_disabled=Уеб-шрифтовете Ñа забранени: разрешаване на използването на вградените PDF шрифтове.
+document_colors_disabled=Ðа PDF-документите не е разрешено да използват ÑобÑтвени цветове: „Разрешаване на Ñтраниците да избират ÑобÑтвени цветове“ е деактивирано в браузъра.
diff --git a/static/pdf.js/locale/bn-BD/viewer.properties b/static/pdf.js/locale/bn-BD/viewer.properties
new file mode 100644
index 000000000..6577a3660
--- /dev/null
+++ b/static/pdf.js/locale/bn-BD/viewer.properties
@@ -0,0 +1,139 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=পূরà§à¦¬à¦¬à¦°à§à¦¤à§€ পৃষà§à¦ া
+previous_label=পূরà§à¦¬à¦¬à¦°à§à¦¤à§€
+next.title=পরবরà§à¦¤à§€ পৃষà§à¦ া
+next_label=পরবরà§à¦¤à§€
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=পৃষà§à¦ া:
+page_of={{pageCount}} à¦à¦°
+
+zoom_out.title=ছোট আকারে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom_out_label=ছোট আকারে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom_in.title=বড় আকারে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom_in_label=বড় আকারে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom.title=বড় আকারে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+presentation_mode.title=উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾ মোডে সà§à¦¯à§à¦‡à¦š করà§à¦¨
+presentation_mode_label=উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾ মোড
+open_file.title=ফাইল খà§à¦²à§à¦¨
+open_file_label=খà§à¦²à§à¦¨
+print.title=মà§à¦¦à§à¦°à¦£
+print_label=মà§à¦¦à§à¦°à¦£
+download.title=ডাউনলোড
+download_label=ডাউনলোড
+bookmark.title=বরà§à¦¤à¦®à¦¾à¦¨ অবসà§à¦¥à¦¾ (অনà§à¦²à¦¿à¦ªà¦¿ অথবা নতà§à¦¨ উইনà§à¦¡à§‹ তে খà§à¦²à§à¦¨)
+bookmark_label=বরà§à¦¤à¦®à¦¾à¦¨ অবসà§à¦¥à¦¾
+
+# Secondary toolbar and context menu
+tools.title=টà§à¦²
+tools_label=টà§à¦²
+first_page.title=পà§à¦°à¦¥à¦® পাতায় যাও
+first_page.label=পà§à¦°à¦¥à¦® পাতায় যাও
+first_page_label=পà§à¦°à¦¥à¦® পাতায় যাও
+last_page.title=শেষ পাতায় যাও
+last_page.label=শেষ পাতায় যাও
+last_page_label=শেষ পাতায় যাও
+page_rotate_cw.title=ঘড়ির কাà¦à¦Ÿà¦¾à¦° দিকে ঘোরাও
+page_rotate_cw.label=ঘড়ির কাà¦à¦Ÿà¦¾à¦° দিকে ঘোরাও
+page_rotate_cw_label=ঘড়ির কাà¦à¦Ÿà¦¾à¦° দিকে ঘোরাও
+page_rotate_ccw.title=ঘড়ির কাà¦à¦Ÿà¦¾à¦° বিপরীতে ঘোরাও
+page_rotate_ccw.label=ঘড়ির কাà¦à¦Ÿà¦¾à¦° বিপরীতে ঘোরাও
+page_rotate_ccw_label=ঘড়ির কাà¦à¦Ÿà¦¾à¦° বিপরীতে ঘোরাও
+
+
+# Document properties dialog box
+document_properties_title=শিরোনাম:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=সাইডবার টগল করà§à¦¨
+toggle_sidebar_label=সাইডবার টগল করà§à¦¨
+outline.title=নথির রূপরেখা পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করà§à¦¨
+outline_label=নথির রূপরেখা
+thumbs.title=থামà§à¦¬à¦¨à§‡à¦‡à¦² সমূহ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ করà§à¦¨
+thumbs_label=থামà§à¦¬à¦¨à§‡à¦‡à¦² সমূহ
+findbar.title=নথির মধà§à¦¯à§‡ খà§à¦à¦œà§à¦¨
+findbar_label=অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=পৃষà§à¦ া {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}} পৃষà§à¦ ার থামà§à¦¬à¦¨à§‡à¦‡à¦²
+
+# Find panel button title and messages
+find_label=অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨:
+find_previous.title=বাকà§à¦¯à¦¾à¦‚শের পূরà§à¦¬à¦¬à¦°à§à¦¤à§€ উপসà§à¦¥à¦¿à¦¤à¦¿ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨
+find_previous_label=পূরà§à¦¬à¦¬à¦°à§à¦¤à§€
+find_next.title=বাকà§à¦¯à¦¾à¦‚শের পরবরà§à¦¤à§€ উপসà§à¦¥à¦¿à¦¤à¦¿ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨
+find_next_label=পরবরà§à¦¤à§€
+find_highlight=সব হাইলাইট করা হবে
+find_match_case_label=অকà§à¦·à¦°à§‡à¦° ছাà¦à¦¦ মেলানো
+find_reached_top=পৃষà§à¦ ার শà§à¦°à§à¦¤à§‡ পৌছে গেছে, নীচ থেকে আরমà§à¦ করা হয়েছে
+find_reached_bottom=পৃষà§à¦ ার শেষে পৌছে গেছে, উপর থেকে আরমà§à¦ করা হয়েছে
+find_not_found=বাকà§à¦¯à¦¾à¦‚শ পাওয়া যায়নি
+
+# Error panel labels
+error_more_info=আরও তথà§à¦¯
+error_less_info=কম তথà§à¦¯
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=বারà§à¦¤à¦¾: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=নথি: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=লাইন: {{line}}
+rendering_error=পৃষà§à¦ া উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾à¦° সময় তà§à¦°à§à¦Ÿà¦¿ দেখা দিয়েছে।
+
+# Predefined zoom values
+page_scale_width=পৃষà§à¦ ার পà§à¦°à¦¸à§à¦¥
+page_scale_fit=পৃষà§à¦ া ফিট করà§à¦¨
+page_scale_auto=সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿ জà§à¦®
+page_scale_actual=পà§à¦°à¦•à§ƒà¦¤ আকার
+
+# Loading indicator messages
+loading_error_indicator=তà§à¦°à§à¦Ÿà¦¿
+loading_error=পিডিà¦à¦« লোড করার সময় তà§à¦°à§à¦Ÿà¦¿ দেখা দিয়েছে।
+invalid_file_error=অকারà§à¦¯à¦•à¦° অথবা কà§à¦·à¦¤à¦¿à¦—à§à¦°à¦¸à§à¦¤ পিডিà¦à¦« ফাইল।
+missing_file_error=পিডিà¦à¦« ফাইল পাওয়া যাচà§à¦›à§‡ না।
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} টীকা]
+password_label=পিডিà¦à¦« ফাইলটি ওপেন করতে পাসওয়ারà§à¦¡ দিন।
+password_invalid=à¦à§à¦² পাসওয়ারà§à¦¡à¥¤ অনà§à¦—à§à¦°à¦¹ করে আবার চেষà§à¦Ÿà¦¾ করà§à¦¨à¥¤
+password_ok=ঠিক আছে
+password_cancel=বাতিল
+
+printing_not_supported=সতরà§à¦•à¦¤à¦¾: à¦à¦‡ বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°à§‡ মà§à¦¦à§à¦°à¦£ সমà§à¦ªà§‚রà§à¦£à¦à¦¾à¦¬à§‡ সমরà§à¦¥à¦¿à¦¤ নয়।
+printing_not_ready=সতরà§à¦•à§€à¦•à¦°à¦£: পিডিà¦à¦«à¦Ÿà¦¿ মà§à¦¦à§à¦°à¦£à§‡à¦° জনà§à¦¯ সমà§à¦ªà§‚রà§à¦£ লোড হয়নি।
+web_fonts_disabled=ওয়েব ফনà§à¦Ÿ নিষà§à¦•à§à¦°à¦¿à§Ÿ: সংযà§à¦•à§à¦¤ পিডিà¦à¦« ফনà§à¦Ÿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করা যাচà§à¦›à§‡ না।
+document_colors_disabled=পিডিà¦à¦« ডকà§à¦®à§‡à¦¨à§à¦Ÿà¦•à§‡ তাদের নিজসà§à¦¬ রঙ বà§à¦¯à¦¬à¦¹à¦¾à¦°à§‡ অনà§à¦®à¦¤à¦¿ নেই: 'পাতা তাদের নিজেসà§à¦¬ রঙ নিরà§à¦¬à¦¾à¦šà¦¨ করতে অনà§à¦®à¦¤à¦¿ দিন' à¦à¦‡ বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°à§‡ নিষà§à¦•à§à¦°à¦¿à§Ÿ রয়েছে।
diff --git a/static/pdf.js/locale/bn-IN/viewer.properties b/static/pdf.js/locale/bn-IN/viewer.properties
new file mode 100644
index 000000000..8bf265d90
--- /dev/null
+++ b/static/pdf.js/locale/bn-IN/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=পূরà§à¦¬à¦¬à¦°à§à¦¤à§€ পৃষà§à¦ া
+previous_label=পূরà§à¦¬à¦¬à¦°à§à¦¤à§€
+next.title=পরবরà§à¦¤à§€ পৃষà§à¦ া
+next_label=পরবরà§à¦¤à§€
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=পৃষà§à¦ া:
+page_of=সরà§à¦¬à¦®à§‹à¦Ÿ {{pageCount}}
+
+zoom_out.title=ছোট মাপে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom_out_label=ছোট মাপে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom_in.title=বড় মাপে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom_in_label=বড় মাপে পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+zoom.title=পà§à¦°à¦¦à¦°à§à¦¶à¦¨à§‡à¦° মাপ
+presentation_mode.title=উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾ মোড সà§à¦¯à§à¦‡à¦š করà§à¦¨
+presentation_mode_label=উপসà§à¦¥à¦¾à¦ªà¦¨à¦¾ মোড
+open_file.title=ফাইল খà§à¦²à§à¦¨
+open_file_label=খà§à¦²à§à¦¨
+print.title=পà§à¦°à¦¿à¦¨à§à¦Ÿ করà§à¦¨
+print_label=পà§à¦°à¦¿à¦¨à§à¦Ÿ করà§à¦¨
+download.title=ডাউনলোড করà§à¦¨
+download_label=ডাউনলোড করà§à¦¨
+bookmark.title=বরà§à¦¤à¦®à¦¾à¦¨ পà§à¦°à¦¦à¦°à§à¦¶à¦¨ (কপি করà§à¦¨ অথবা নতà§à¦¨ উইনà§à¦¡à§‹à¦¤à§‡ খà§à¦²à§à¦¨)
+bookmark_label=বরà§à¦¤à¦®à¦¾à¦¨ পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+
+# Secondary toolbar and context menu
+tools.title=সরঞà§à¦œà¦¾à¦®
+tools_label=সরঞà§à¦œà¦¾à¦®
+first_page.title=পà§à¦°à¦¥à¦® পৃষà§à¦ ায় চলà§à¦¨
+first_page.label=পà§à¦°à¦¥à¦® পৃষà§à¦ ায় চলà§à¦¨
+first_page_label=পà§à¦°à¦¥à¦® পৃষà§à¦ ায় চলà§à¦¨
+last_page.title=সরà§à¦¬à¦¶à§‡à¦· পৃষà§à¦ ায় চলà§à¦¨
+last_page.label=সরà§à¦¬à¦¶à§‡à¦· পৃষà§à¦ ায় চলà§à¦¨
+last_page_label=সরà§à¦¬à¦¶à§‡à¦· পৃষà§à¦ ায় চলà§à¦¨
+page_rotate_cw.title=ডানদিকে ঘোরানো হবে
+page_rotate_cw.label=ডানদিকে ঘোরানো হবে
+page_rotate_cw_label=ডানদিকে ঘোরানো হবে
+page_rotate_ccw.title=বাà¦à¦¦à¦¿à¦•à§‡ ঘোরানো হবে
+page_rotate_ccw.label=বাà¦à¦¦à¦¿à¦•à§‡ ঘোরানো হবে
+page_rotate_ccw_label=বাà¦à¦¦à¦¿à¦•à§‡ ঘোরানো হবে
+
+hand_tool_enable.title=হà§à¦¯à¦¾à¦¨à§à¦¡ টà§à¦² সকà§à¦°à¦¿à§Ÿ করà§à¦¨
+hand_tool_enable_label=হà§à¦¯à¦¾à¦¨à§à¦¡ টà§à¦² সকà§à¦°à¦¿à§Ÿ করà§à¦¨
+hand_tool_disable.title=হà§à¦¯à¦¾à¦¨à§à¦¡ টà§à¦² নিসà§à¦•à§à¦°à¦¿à§Ÿ করà§à¦¨
+hand_tool_disable_label=হà§à¦¯à¦¾à¦¨à§à¦¡ টà§à¦² নিসà§à¦•à§à¦°à¦¿à§Ÿ করà§à¦¨
+
+# Document properties dialog box
+document_properties.title=নথির বৈশিষà§à¦Ÿà§à¦¯â€¦
+document_properties_label=নথির বৈশিষà§à¦Ÿà§à¦¯â€¦
+document_properties_file_name=ফাইলের নাম:
+document_properties_file_size=ফাইলের মাপ:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} মেগাবাইট ({{size_b}} bytes)
+document_properties_title=শিরোনাম:
+document_properties_author=লেখক:
+document_properties_subject=বিষয়:
+document_properties_keywords=নিরà§à¦¦à§‡à¦¶à¦• শবà§à¦¦:
+document_properties_creation_date=নিরà§à¦®à¦¾à¦£à§‡à¦° তারিখ:
+document_properties_modification_date=পরিবরà§à¦¤à¦¨à§‡à¦° তারিখ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=নিরà§à¦®à¦¾à¦¤à¦¾:
+document_properties_producer=PDF নিরà§à¦®à¦¾à¦¤à¦¾:
+document_properties_version=PDF সংসà§à¦•à¦°à¦£:
+document_properties_page_count=মোট পৃষà§à¦ া:
+document_properties_close=বনà§à¦§ করà§à¦¨
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=সাইডবার টগল করà§à¦¨
+toggle_sidebar_label=সাইডবার টগল করà§à¦¨
+outline.title=নথির রূপরেখা পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+outline_label=নথির রূপরেখা পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+attachments.title=সংযà§à¦•à§à¦¤à¦¿à¦¸à¦®à§‚হ দেখান
+attachments_label=সংযà§à¦•à§à¦¤ বসà§à¦¤à§
+thumbs.title=থামà§à¦¬-নেইল পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+thumbs_label=থামà§à¦¬-নেইল পà§à¦°à¦¦à¦°à§à¦¶à¦¨
+findbar.title=নথিতে খà§à¦à¦œà§à¦¨
+findbar_label=অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=পৃষà§à¦ া {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=পৃষà§à¦ া {{page}}-র থামà§à¦¬-নেইল
+
+# Find panel button title and messages
+find_label=অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨:
+find_previous.title=চিহà§à¦¨à¦¿à¦¤ পংকà§à¦¤à¦¿à¦° পূরà§à¦¬à¦¬à¦°à§à¦¤à§€ উপসà§à¦¥à¦¿à¦¤à¦¿ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨
+find_previous_label=পূরà§à¦¬à¦¬à¦°à§à¦¤à§€
+find_next.title=চিহà§à¦¨à¦¿à¦¤ পংকà§à¦¤à¦¿à¦° পরবরà§à¦¤à§€ উপসà§à¦¥à¦¿à¦¤à¦¿ অনà§à¦¸à¦¨à§à¦§à¦¾à¦¨ করà§à¦¨
+find_next_label=পরবরà§à¦¤à§€
+find_highlight=সমগà§à¦° উজà§à¦œà§à¦¬à¦² করà§à¦¨
+find_match_case_label=হরফের ছাà¦à¦¦ মেলানো হবে
+find_reached_top=পৃষà§à¦ ার পà§à¦°à¦¾à¦°à¦®à§à¦à§‡ পৌছে গেছে, নীচের অংশ থেকে আরমà§à¦ করা হবে
+find_reached_bottom=পৃষà§à¦ ার অনà§à¦¤à¦¿à¦® পà§à¦°à¦¾à¦¨à§à¦¤à§‡ পৌছে গেছে, পà§à¦°à¦¥à¦® অংশ থেকে আরমà§à¦ করা হবে
+find_not_found=পংকà§à¦¤à¦¿ পাওয়া যায়নি
+
+# Error panel labels
+error_more_info=অতিরিকà§à¦¤ তথà§à¦¯
+error_less_info=কম তথà§à¦¯
+error_close=বনà§à¦§ করà§à¦¨
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Message: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=File: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Line: {{line}}
+rendering_error=পৃষà§à¦ া পà§à¦°à¦¦à¦°à§à¦¶à¦¨à¦•à¦¾à¦²à§‡ à¦à¦•à¦Ÿà¦¿ সমসà§à¦¯à¦¾ দেখা দিয়েছে।
+
+# Predefined zoom values
+page_scale_width=পৃষà§à¦ ার পà§à¦°à¦¸à§à¦¥ অনà§à¦¯à¦¾à§Ÿà§€
+page_scale_fit=পৃষà§à¦ ার মাপ অনà§à¦¯à¦¾à§Ÿà§€
+page_scale_auto=সà§à¦¬à§Ÿà¦‚কà§à¦°à¦¿à§Ÿ মাপ নিরà§à¦§à¦¾à¦°à¦£
+page_scale_actual=পà§à¦°à¦•à§ƒà¦¤ মাপ
+
+# Loading indicator messages
+loading_error_indicator=তà§à¦°à§à¦Ÿà¦¿
+loading_error=PDF লোড করার সময় সমসà§à¦¯à¦¾ দেখা দিয়েছে।
+invalid_file_error=অবৈধ বা কà§à¦·à¦¤à¦¿à¦—à§à¦°à¦¸à§à¦¤ পিডিà¦à¦« ফাইল।
+missing_file_error=অনà§à¦ªà¦¸à§à¦¥à¦¿à¦¤ PDF ফাইল
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=à¦à¦‡ PDF ফাইল খোলার জনà§à¦¯ পাসওয়ারà§à¦¡ দিন।
+password_invalid=পাসওয়ারà§à¦¡ সঠিক নয়। অনà§à¦—à§à¦°à¦¹ করে পà§à¦¨à¦°à¦¾à§Ÿ পà§à¦°à¦šà§‡à¦·à§à¦Ÿà¦¾ করà§à¦¨à¥¤
+password_ok=OK
+password_cancel=বাতিল করà§à¦¨
+
+printing_not_supported=সতরà§à¦•à¦¬à¦¾à¦°à§à¦¤à¦¾: à¦à¦‡ বà§à¦°à¦¾à¦‰à¦œà¦¾à¦° দà§à¦¬à¦¾à¦°à¦¾ পà§à¦°à¦¿à¦¨à§à¦Ÿ বà§à¦¯à¦¬à¦¸à§à¦¥à¦¾ সমà§à¦ªà§‚রà§à¦£à¦°à§‚পে সমরà§à¦¥à¦¿à¦¤ নয়।
+printing_not_ready=সতরà§à¦•à¦¬à¦¾à¦£à§€: পিডিà¦à¦« সমà§à¦ªà§‚রà§à¦£à¦°à§‚পে মà§à¦¦à§à¦°à¦£à§‡à¦° জনà§à¦¯ লোড করা হয় না.
+web_fonts_disabled=ওয়েব ফনà§à¦Ÿ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করা হয়েছে: à¦à¦®à¦¬à§‡à¦¡à§‡à¦¡ পিডিà¦à¦« ফনà§à¦Ÿ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে অকà§à¦·à¦®.
+document_colors_disabled=পিডিà¦à¦« নথি তাদের নিজসà§à¦¬ রং বà§à¦¯à¦¬à¦¹à¦¾à¦° করার জনà§à¦¯ অনà§à¦®à¦¤à¦¿à¦ªà§à¦°à¦¾à¦ªà§à¦¤ নয়: বà§à¦°à¦¾à¦‰à¦œà¦¾à¦°à§‡ নিষà§à¦•à§à¦°à¦¿à¦¯à¦¼ করা হয়েছে য়েন 'পেজ তাদের নিজসà§à¦¬ রং নিরà§à¦¬à¦¾à¦šà¦¨ করার অনà§à¦®à¦¤à¦¿ পà§à¦°à¦¦à¦¾à¦¨ করা য়ায়।'
diff --git a/static/pdf.js/locale/br/viewer.properties b/static/pdf.js/locale/br/viewer.properties
new file mode 100644
index 000000000..de8063955
--- /dev/null
+++ b/static/pdf.js/locale/br/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Pajenn a-raok
+previous_label=A-raok
+next.title=Pajenn war-lerc'h
+next_label=War-lerc'h
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pajenn :
+page_of=eus {{pageCount}}
+
+zoom_out.title=Zoum bihanaat
+zoom_out_label=Zoum bihanaat
+zoom_in.title=Zoum brasaat
+zoom_in_label=Zoum brasaat
+zoom.title=Zoum
+presentation_mode.title=Trec'haoliñ etrezek ar mod kinnigadenn
+presentation_mode_label=Mod kinnigadenn
+open_file.title=Digeriñ ur restr
+open_file_label=Digeriñ ur restr
+print.title=Moullañ
+print_label=Moullañ
+download.title=Pellgargañ
+download_label=Pellgargañ
+bookmark.title=Gwel bremanel (eilañ pe zigeriñ e-barzh ur prenestr nevez)
+bookmark_label=Gwel bremanel
+
+# Secondary toolbar and context menu
+tools.title=Ostilhoù
+tools_label=Ostilhoù
+first_page.title=Mont d'ar bajenn gentañ
+first_page.label=Mont d'ar bajenn gentañ
+first_page_label=Mont d'ar bajenn gentañ
+last_page.title=Mont d'ar bajenn diwezhañ
+last_page.label=Mont d'ar bajenn diwezhañ
+last_page_label=Mont d'ar bajenn diwezhañ
+page_rotate_cw.title=C'hwelañ gant roud ar bizied
+page_rotate_cw.label=C'hwelañ gant roud ar bizied
+page_rotate_cw_label=C'hwelañ gant roud ar bizied
+page_rotate_ccw.title=C'hwelañ gant roud gin ar bizied
+page_rotate_ccw.label=C'hwelañ gant roud gin ar bizied
+page_rotate_ccw_label=C'hwelañ gant roud gin ar bizied
+
+hand_tool_enable.title=Gweredekaat an ostilh "dorn"
+hand_tool_enable_label=Gweredekaat an ostilh "dorn"
+hand_tool_disable.title=Diweredekaat an ostilh "dorn"
+hand_tool_disable_label=Diweredekaat an ostilh "dorn"
+
+# Document properties dialog box
+document_properties.title=Perzhioù an teul…
+document_properties_label=Perzhioù an teul…
+document_properties_file_name=Anv restr :
+document_properties_file_size=Ment ar restr :
+document_properties_kb={{size_kb}} Ke ({{size_b}} eizhbit)
+document_properties_mb={{size_mb}} Me ({{size_b}} eizhbit)
+document_properties_title=Titl :
+document_properties_author=Aozer :
+document_properties_subject=Danvez :
+document_properties_keywords=Gerioù-alc'hwez :
+document_properties_creation_date=Deiziad krouiñ :
+document_properties_modification_date=Deiziad kemmañ :
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Krouer :
+document_properties_producer=Kenderc'her PDF :
+document_properties_version=Handelv PDF :
+document_properties_page_count=Niver a bajennoù :
+document_properties_close=Serriñ
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Diskouez/kuzhat ar varrenn gostez
+toggle_sidebar_label=Diskouez/kuzhat ar varrenn gostez
+outline.title=Diskouez ar sinedoù
+outline_label=Sinedoù an teuliad
+attachments.title=Diskouez ar c'henstagadurioù
+attachments_label=Kenstagadurioù
+thumbs.title=Diskouez ar melvennoù
+thumbs_label=Melvennoù
+findbar.title=Klask e-barzh an teuliad
+findbar_label=Klask
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pajenn {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Melvenn ar bajenn {{page}}
+
+# Find panel button title and messages
+find_label=Kavout :
+find_previous.title=Kavout an tamm frazenn kent o klotañ ganti
+find_previous_label=Kent
+find_next.title=Kavout an tamm frazenn war-lerc'h o klotañ ganti
+find_next_label=War-lerc'h
+find_highlight=Usskediñ pep tra
+find_match_case_label=Teurel evezh ouzh ar pennlizherennoù
+find_reached_top=Tizhet eo bet derou ar bajenn, kenderc'hel diouzh an diaz
+find_reached_bottom=Tizhet eo bet dibenn ar bajenn, kenderc'hel diouzh ar c'hrec'h
+find_not_found=N'haller ket kavout ar frazenn
+
+# Error panel labels
+error_more_info=Muioc'h a ditouroù
+error_less_info=Nebeutoc'h a ditouroù
+error_close=Serriñ
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js handelv {{version}} (kempunadur : {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Kemennadenn : {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Torn : {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Restr : {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linenn : {{line}}
+rendering_error=Degouezhet ez eus bet ur fazi e-pad skrammañ ar bajennad.
+
+# Predefined zoom values
+page_scale_width=Led ar bajenn
+page_scale_fit=Pajenn a-bezh
+page_scale_auto=Zoum emgefreek
+page_scale_actual=Ment wir
+
+# Loading indicator messages
+loading_error_indicator=Fazi
+loading_error=Degouezhet ez eus bet ur fazi e-pad kargañ ar PDF.
+invalid_file_error=Restr PDF didalvoudek pe kontronet.
+missing_file_error=Restr PDF o vankout.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Notennañ]
+password_label=Enankit ar ger-tremen evit digeriñ ar restr PDF-mañ.
+password_invalid=Ger-tremen didalvoudek. Klaskit en-dro mar plij.
+password_ok=Mat eo
+password_cancel=Nullañ
+
+printing_not_supported=Kemenn : N'eo ket skoret penn-da-benn ar moullañ gant ar merdeer-mañ.
+printing_not_ready=Kemenn : N'hall ket bezañ moullet ar restr PDF rak n'eo ket karget penn-da-benn.
+web_fonts_disabled=Diweredekaet eo an nodrezhoù web : n'haller ket arverañ an nodrezhoù PDF enframmet.
+document_colors_disabled=N'eo ket aotreet an teuliadoù PDF da arverañ o livioù dezho : diweredekaet eo 'Aotren ar pajennoù da zibab o livioù dezho' e-barzh ar merdeer.
diff --git a/static/pdf.js/locale/bs/viewer.properties b/static/pdf.js/locale/bs/viewer.properties
new file mode 100644
index 000000000..a89bf7afd
--- /dev/null
+++ b/static/pdf.js/locale/bs/viewer.properties
@@ -0,0 +1,125 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Prethodna strana
+previous_label=Prethodna
+next.title=Sljedeća strna
+next_label=Sljedeća
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Strana:
+page_of=od {{pageCount}}
+
+zoom_out.title=Umanji
+zoom_out_label=Umanji
+zoom_in.title=Uvećaj
+zoom_in_label=Uvećaj
+zoom.title=Uvećanje
+print.title=Å tampaj
+print_label=Å tampaj
+presentation_mode.title=Prebaci se u prezentacijski režim
+presentation_mode_label=Prezentacijski režim
+open_file.title=Otvori fajl
+open_file_label=Otvori
+download.title=Preuzmi
+download_label=Preuzmi
+bookmark.title=Trenutni prikaz (kopiraj ili otvori u novom prozoru)
+bookmark_label=Trenutni prikaz
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=UkljuÄi/iskljuÄi boÄnu traku
+toggle_sidebar_label=UkljuÄi/iskljuÄi boÄnu traku
+outline.title=Prikaži konture dokumenta
+outline_label=Konture dokumenta
+thumbs.title=Prikaži thumbnailove
+thumbs_label=Thumbnailovi
+findbar.title=Pronađi u dokumentu
+findbar_label=Pronađi
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Strana {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Thumbnail strane {{page}}
+
+# Context menu
+first_page.label=Idi na prvu stranu
+last_page.label=Idi na zadnju stranu
+page_rotate_cw.label=Rotiraj u smjeru kazaljke na satu
+page_rotate_ccw.label=Rotiraj suprotno smjeru kazaljke na satu
+
+# Find panel button title and messages
+find_label=Pronađi:
+find_previous.title=Pronađi prethodno pojavljivanje fraze
+find_previous_label=Prethodno
+find_next.title=Pronađi sljedeće pojavljivanje fraze
+find_next_label=Sljedeće
+find_highlight=OznaÄi sve
+find_match_case_label=Osjetljivost na karaktere
+find_reached_top=Dostigao sam vrh dokumenta, nastavljam sa dna
+find_reached_bottom=Dostigao sam kraj dokumenta, nastavljam sa vrha
+find_not_found=Fraza nije pronađena
+
+# Error panel labels
+error_more_info=Više informacija
+error_less_info=Manje informacija
+error_close=Zatvori
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Poruka: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fajl: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linija: {{line}}
+rendering_error=Došlo je do greške prilikom renderiranja strane.
+
+# Predefined zoom values
+page_scale_width=Å irina strane
+page_scale_fit=Uklopi stranu
+page_scale_auto=Automatsko uvećanje
+page_scale_actual=Stvarna veliÄina
+
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+loading_error_indicator=Greška
+loading_error=DoÅ¡lo je do greÅ¡ke prilikom uÄitavanja PDF-a.
+invalid_file_error=Neispravan ili oštećen PDF fajl.
+missing_file_error=Nedostaje PDF fajl.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{[type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} pribilješka]
+request_password=PDF je zaštićen lozinkom:
+invalid_password=Pogrešna lozinka.
+
+printing_not_supported=Upozorenje: Štampanje nije u potpunosti podržano u ovom browseru.
+printing_not_ready=Upozorenje: PDF nije u potpunosti uÄitan za Å¡tampanje.
+web_fonts_disabled=Web fontovi su onemogućeni: nemoguće koristiti ubaÄene PDF fontove.
+document_colors_disabled=PDF dokumentima nije dozvoljeno da koriste vlastite boje: \'Dozvoli stranicama da izaberu vlastite boje\' je deaktivirano u browseru.
diff --git a/static/pdf.js/locale/ca/viewer.properties b/static/pdf.js/locale/ca/viewer.properties
index b3f97c320..3a872e9b7 100644
--- a/static/pdf.js/locale/ca/viewer.properties
+++ b/static/pdf.js/locale/ca/viewer.properties
@@ -1,131 +1,163 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
-
-# Main toolbar buttons (tooltips and alt text for images)
-previous.title=PÃ gina anterior
-previous_label=Anterior
-next.title=Pà gina següent
-next_label=Següent
-
-# LOCALIZATION NOTE (page_label, page_of):
-# These strings are concatenated to form the "Page: X of Y" string.
-# Do not translate "{{pageCount}}", it will be substituted with a number
-# representing the total number of pages.
-page_label=PÃ gina:
-page_of=de {{pageCount}}
-
-zoom_out.title=Reduir
-zoom_out_label=Reduir
-zoom_in.title=Ampliar
-zoom_in_label=Ampliar
-zoom.title=Ampliació
-presentation_mode.title=Canviar a mode de Presentació
-presentation_mode_label=Mode de Presentació
-open_file.title=Obrir arxiu
-open_file_label=Obrir
-print.title=Imprimir
-print_label=Imprimir
-download.title=Descarregar
-download_label=Descarregar
-bookmark.title=Vista actual (copiï o obri en una finestra nova)
-bookmark_label=Vista actual
-
-# Secondary toolbar and context menu
-first_page.title=Primera pà gina
-first_page.label=Primera pà gina
-first_page_label=Primera pà gina
-last_page.title=Darrera pà gina
-last_page.label=Darrera pà gina
-last_page_label=Darrera pà gina
-page_rotate_cw.title=Rotar sentit horari
-page_rotate_cw.label=Rotar sentit horari
-page_rotate_cw_label=Rotar sentit horari
-page_rotate_ccw.title=Rotar sentit anti-horari
-page_rotate_ccw.label=Rotar sentit anti-horari
-page_rotate_ccw_label=Rotar sentit anti-horari
-
-# Tooltips and alt text for side panel toolbar buttons
-# (the _label strings are alt text for the buttons, the .title strings are
-# tooltips)
-toggle_slider.title=Alternar lliscador
-toggle_slider_label=Alternar lliscador
-outline.title=Mostrar esquema del document
-outline_label=Esquema del document
-thumbs.title=Mostrar miniatures
-thumbs_label=Miniatures
-findbar.title=Cercar en el document
-findbar_label=Cercar
-
-# Thumbnails panel item (tooltip and alt text for images)
-# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
-# number.
-thumb_page_title=PÃ gina {{page}}
-# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
-# number.
-thumb_page_canvas=Miniatura de la pà gina {{page}}
-
-# Find panel button title and messages
-find=Cercar
-find_terms_not_found=(No trobat)
-
-# Find panel button title and messages
-find_label=Cerca:
-find_previous.title=Trobar ocurrència anterior
-find_previous_label=Previ
-find_next.title=Trobar ocurrència posterior
-find_next_label=Següent
-find_highlight=Contrastar tot
-find_match_case_label=Majúscules i minúscules
-find_wrapped_to_bottom=Part superior assolida, continu a la part inferior
-find_wrapped_to_top=Final de pà gina finalitzada, continu a la part superior
-find_not_found=Frase no trobada
-
-# Error panel labels
-error_more_info=Més informació
-error_less_info=Menys informació
-error_close=Tancar
-# LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
-# build ID.
-error_build=Compilació de PDF.JS: {{build}}
-# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
-# english string describing the error.
-error_message=Missatge: {{message}}
-# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
-# trace.
-error_stack=Pila: {{stack}}
-# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
-error_file=Arxiu: {{file}}
-# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=LÃnia: {{line}}
-rendering_error=Ha ocurregut un error mentre es renderitzava la pà gina.
-
-# Predefined zoom values
-page_scale_width=Ample de pà gina
-page_scale_fit=Ajustar a la pà gina
-page_scale_auto=Ampliació automà tica
-page_scale_actual=Tamany real
-
-# Loading indicator messages
-loading_error_indicator=Error
-loading_error=Ha ocorregut un error mentres es carregava el PDF.
-invalid_file_error=Invà lid o fitxer PDF corrupte.
-
-# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
-# "{{type}}" will be replaced with an annotation type from a list defined in
-# the PDF spec (32000-1:2008 Table 169 – Annotation types).
-# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[Anotació {{type}}]
-request_password=El PDF està protegit amb una contrasenya:
-
-printing_not_supported=AvÃs: La impressió no és compatible totalment en aquest navegador.
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=PÃ gina anterior
+previous_label=Anterior
+next.title=Pà gina següent
+next_label=Següent
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=PÃ gina:
+page_of=de {{pageCount}}
+
+zoom_out.title=Allunya
+zoom_out_label=Allunya
+zoom_in.title=Apropa
+zoom_in_label=Apropa
+zoom.title=Escala
+presentation_mode.title=Canvia al mode de presentació
+presentation_mode_label=Mode de presentació
+open_file.title=Obre el fitxer
+open_file_label=Obre
+print.title=Imprimeix
+print_label=Imprimeix
+download.title=Baixa
+download_label=Baixa
+bookmark.title=Vista actual (copia o obre en una finestra nova)
+bookmark_label=Vista actual
+
+# Secondary toolbar and context menu
+tools.title=Eines
+tools_label=Eines
+first_page.title=Vés a la primera pà gina
+first_page.label=Vés a la primera pà gina
+first_page_label=Vés a la primera pà gina
+last_page.title=Vés a l'última pà gina
+last_page.label=Vés a l'última pà gina
+last_page_label=Vés a l'última pà gina
+page_rotate_cw.title=Gira cap a la dreta
+page_rotate_cw.label=Gira cap a la dreta
+page_rotate_cw_label=Gira cap a la dreta
+page_rotate_ccw.title=Gira cap a l'esquerra
+page_rotate_ccw.label=Gira cap a l'esquerra
+page_rotate_ccw_label=Gira cap a l'esquerra
+
+hand_tool_enable.title=Habilita l'eina de mÃ
+hand_tool_enable_label=Habilita l'eina de mÃ
+hand_tool_disable.title=Inhabilita l'eina de mÃ
+hand_tool_disable_label=Inhabilita l'eina de mÃ
+
+# Document properties dialog box
+document_properties.title=Propietats del document…
+document_properties_label=Propietats del document…
+document_properties_file_name=Nom del fitxer:
+document_properties_file_size=Mida del fitxer:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=TÃtol:
+document_properties_author=Autor:
+document_properties_subject=Assumpte:
+document_properties_keywords=Paraules clau:
+document_properties_creation_date=Data de creació:
+document_properties_modification_date=Data de modificació:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creador:
+document_properties_producer=Generador de PDF:
+document_properties_version=Versió de PDF:
+document_properties_page_count=Nombre de pà gines:
+document_properties_close=Close
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Mostra/amaga la barra lateral
+toggle_sidebar_label=Mostra/amaga la barra lateral
+outline.title=Mostra el contorn del document
+outline_label=Contorn del document
+attachments.title=Mostra les adjuncions
+attachments_label=Adjuncions
+thumbs.title=Mostra les miniatures
+thumbs_label=Miniatures
+findbar.title=Cerca al document
+findbar_label=Cerca
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=PÃ gina {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura de la pà gina {{page}}
+
+# Find panel button title and messages
+find_label=Cerca:
+find_previous.title=Cerca l'anterior coincidència de l'expressió
+find_previous_label=Anterior
+find_next.title=Cerca la següent coincidència de l'expressió
+find_next_label=Següent
+find_highlight=Ressalta-ho tot
+find_match_case_label=Distingeix entre majúscules i minúscules
+find_reached_top=S'ha arribat al principi del document, es continua pel final
+find_reached_bottom=S'ha arribat al final del document, es continua pel principi
+find_not_found=No s'ha trobat l'expressió
+
+# Error panel labels
+error_more_info=Més informació
+error_less_info=Menys informació
+error_close=Tanca
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (muntatge: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Missatge: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fitxer: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=LÃnia: {{line}}
+rendering_error=S'ha produït un error mentre es renderitzava la pà gina
+
+# Predefined zoom values
+page_scale_width=Amplà ria de la pà gina
+page_scale_fit=Ajusta la pà gina
+page_scale_auto=Zoom automà tic
+page_scale_actual=Mida real
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=S'ha produït un error en carregar el PDF.
+invalid_file_error=El fitxer PDF no és và lid o està malmès.
+missing_file_error=Falta el fitxer PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotació {{type}}]
+password_label=Introduïu la contrasenya per obrir aquest fitxer PDF.
+password_invalid=La contrasenya no és và lida. Torneu-ho a provar.
+password_ok=D'acord
+password_cancel=Cancel·la
+
+printing_not_supported=AvÃs: la impressió no és plenament funcional en aquest navegador.
+printing_not_ready=Atenció: el PDF no s'ha acabat de carregar per imprimir-lo.
+web_fonts_disabled=Les fonts web estan inhabilitades: no es poden incrustar fitxers PDF.
+document_colors_disabled=Els documents PDF no poden usar els seus colors propis: «Permet a les pà gines triar els colors propis» es troba desactivat al navegador.
diff --git a/static/pdf.js/locale/cs/viewer.properties b/static/pdf.js/locale/cs/viewer.properties
index 69ae650da..ce164ebd0 100644
--- a/static/pdf.js/locale/cs/viewer.properties
+++ b/static/pdf.js/locale/cs/viewer.properties
@@ -12,47 +12,152 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-bookmark.title=Aktuálnà zobrazenà (zkopÃrovat nebo otevÅ™Ãt v novém oknÄ›)
+# Main toolbar buttons (tooltips and alt text for images)
previous.title=Předchozà stránka
+previous_label=PÅ™edchozÃ
next.title=Dalšà stránka
-print.title=Tisk
-download.title=Stáhnout
-zoom_out.title=Zmenšit
-zoom_in.title=Zvětšit
+next_label=DalÅ¡Ã
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Stránka:
+page_of=z {{pageCount}}
+
+zoom_out.title=Zmenšà velikost
+zoom_out_label=Zmenšit
+zoom_in.title=Zvětšà velikost
+zoom_in_label=Zvětšit
+zoom.title=Nastavà velikost
+presentation_mode.title=Přepne režimu prezentace
+presentation_mode_label=Režim prezentace
+open_file.title=Otevře soubor
+open_file_label=OtevÅ™Ãt
+print.title=Vytiskne dokument
+print_label=Tisk
+download.title=Stáhne dokument
+download_label=Stáhnout
+bookmark.title=Aktuálnà pohled (kopÃrovat nebo otevÅ™Ãt v novém oknÄ›)
+bookmark_label=Aktuálnà pohled
+
+# Secondary toolbar and context menu
+tools.title=Nástroje
+tools_label=Nástroje
+first_page.title=Přejde na prvnà stránku
+first_page.label=PÅ™ejÃt na prvnà stránku
+first_page_label=PÅ™ejÃt na prvnà stránku
+last_page.title=Přejde na poslednà stránku
+last_page.label=PÅ™ejÃt na poslednà stránku
+last_page_label=PÅ™ejÃt na poslednà stránku
+page_rotate_cw.title=OtoÄà po smÄ›ru hodin
+page_rotate_cw.label=OtoÄit po smÄ›ru hodin
+page_rotate_cw_label=OtoÄit po smÄ›ru hodin
+page_rotate_ccw.title=OtoÄà proti smÄ›ru hodin
+page_rotate_ccw.label=OtoÄit proti smÄ›ru hodin
+page_rotate_ccw_label=OtoÄit proti smÄ›ru hodin
+
+hand_tool_enable.title=Povolit nástroj ruÄiÄka
+hand_tool_enable_label=Povolit nástroj ruÄiÄka
+hand_tool_disable.title=Zakázat nástroj ruÄiÄka
+hand_tool_disable_label=Zakázat nástroj ruÄiÄka
+
+# Document properties dialog box
+document_properties.title=Vlastnosti dokumentu…
+document_properties_label=Vlastnosti dokumentu…
+document_properties_file_name=Název souboru:
+document_properties_file_size=Velikost souboru:
+document_properties_kb={{size_kb}} kB ({{size_b}} bajtů)
+document_properties_mb={{size_mb}} MB ({{size_b}} bajtů)
+document_properties_title=Nadpis:
+document_properties_author=Autor:
+document_properties_subject=Subjekt:
+document_properties_keywords=KlÃÄová slova:
+document_properties_creation_date=Datum vytvoÅ™enÃ:
+document_properties_modification_date=Datum úpravy:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Vytvořil:
+document_properties_producer=Tvůrce PDF:
+document_properties_version=Verze PDF:
+document_properties_page_count=PoÄet stránek:
+document_properties_close=ZavÅ™Ãt
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Postrannà lišta
+toggle_sidebar_label=Postrannà lišta
+outline.title=Zobrazà osnovu dokumentu
+outline_label=Osnova dokumentu
+attachments.title=Zobrazà pÅ™Ãlohy
+attachments_label=PÅ™Ãlohy
+thumbs.title=Zobrazà náhledy
+thumbs_label=Náhledy
+findbar.title=Najde v dokumentu
+findbar_label=NajÃt
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Strana {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Náhled strany {{page}}
+
+# Find panel button title and messages
+find_label=NajÃt:
+find_previous.title=Najde pÅ™edchozà výskyt hledaného spojenÃ
+find_previous_label=PÅ™edchozÃ
+find_next.title=Najde dalÅ¡Ã výskyt hledaného spojenÃ
+find_next_label=DalÅ¡Ã
+find_highlight=Zvýraznit
+find_match_case_label=Rozlišovat velikost
+find_reached_top=Dosažen zaÄátek dokumentu, pokraÄuje se od konce
+find_reached_bottom=Dosažen konec dokumentu, pokraÄuje se o zaÄátku
+find_not_found=Hledané spojenà nenalezeno
+
+# Error panel labels
error_more_info=VÃce informacÃ
error_less_info=MénÄ› informacÃ
error_close=ZavÅ™Ãt
-error_build=PDF.JS Build: {{build}}
-error_message=Zpráva:{{message}}
-error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (sestavenÃ: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Zpráva: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ZásobnÃk: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Soubor: {{file}}
-error_line=Řádek: {{line}}
-page_scale_width=Å ÃÅ™ka stránky
-page_scale_fit=Stránka
-page_scale_auto=Automatické pÅ™ibliženÃ
-page_scale_actual=SkuteÄná velikost
-toggle_slider.title=PÅ™epnout posuvnÃk
-thumbs.title=Zobrazit náhledy
-outline.title=Zobrazit osnovu dokumentu
-loading=NaÄÃtám... {{percent}} %
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Řádka: {{line}}
+rendering_error=Při vykreslovánà stránky nastala chyba.
+
+# Predefined zoom values
+page_scale_width=Podle Å¡ÃÅ™ky
+page_scale_fit=Podle výšky
+page_scale_auto=Automatická velikost
+page_scale_actual=Aktuálnà velikost
+
+# Loading indicator messages
loading_error_indicator=Chyba
-loading_error=DoÅ¡lo k chybÄ› pÅ™i naÄÃtánà PDF.
-rendering_error=Došlo k chybě při vykreslovánà stránky.
-page_label=Stránka:
-page_of=z {{pageCount}}
-open_file.title=OtevÅ™Ãt soubor
-text_annotation_type.alt=[{{type}}Anotace]
-toggle_slider_label=PÅ™epnout posuvnÃk
-thumbs_label=Náhledy
-outline_label=Přehled dokumentu
-bookmark_label=Aktuálnà zobrazenÃ
-previous_label=PÅ™edchozÃ
-next_label=DalÅ¡Ã
-print_label=Tisk
-download_label=Stáhnout
-zoom_out_label=Zmenšit
-zoom_in_label=PřiblÞit
-zoom.title=Zvětšit
-thumb_page_title=Stránka {{page}}
-thumb_page_canvas=Náhled stránky {{page}}
-request_password=PDF je chráněn heslem:
+loading_error=Při nahrávánà PDF nastala chyba.
+invalid_file_error=Neplatný nebo chybný soubor PDF.
+missing_file_error=Chybà soubor PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotace typu {{type}}]
+password_label=Pro otevřenà PDF souboru vložte heslo.
+password_invalid=Neplatné heslo. Zkuste to znovu.
+password_ok=OK
+password_cancel=Zrušit
+
+printing_not_supported=UpozornÄ›nÃ: Tisk nenà v tomto prohlÞeÄi plnÄ› podporován.
+printing_not_ready=UpozornÄ›nÃ: Dokument PDF nenà kompletnÄ› naÄten.
+web_fonts_disabled=Webová pÃsma jsou zakázána, proto nenà možné použÃt vložená pÃsma PDF.
+document_colors_disabled=PDF dokumenty nemajà povoleny použÃvánà vlastnÃch barev: volba "Povolit stránkám použÃvat vlastnà barvy namÃsto výše zvolených" je v prohlÞeÄi deaktivována.
diff --git a/static/pdf.js/locale/csb/viewer.properties b/static/pdf.js/locale/csb/viewer.properties
new file mode 100644
index 000000000..293a353c1
--- /dev/null
+++ b/static/pdf.js/locale/csb/viewer.properties
@@ -0,0 +1,134 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Pòprzédnô strona
+previous_label=Pòprzédnô
+next.title=Nôslédnô strona
+next_label=Nôslédnô
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Strona:
+page_of=z {{pageCount}}
+
+zoom_out.title=Zmniészë
+zoom_out_label=Zmniészë
+zoom_in.title=Zwikszë
+zoom_in_label=Wiôlgòsc
+zoom.title=Wiôlgòsc
+print.title=Drëkùjë
+print_label=Drëkùjë
+presentation_mode.title=Przéńdzë w trib prezentacje
+presentation_mode_label=Trib prezentacje
+open_file.title=Ã’temkni lopk
+open_file_label=Ã’temkni
+download.title=Zladënk
+download_label=Zladënk
+bookmark.title=Spamiãtôj wëzdrzatk (kòpérëje, abò òtemkni w nowim òknnie)
+bookmark_label=Aktualny wëzdrzatk
+
+find_label=Szëkôj:
+find_previous.title=Biéj do pòprzédnégò wënikù szëkbë
+find_previous_label=Pòprzédny
+find_next.title=Biéj do nôslédnégò wënikù szëkbë
+find_next_label=Nôslédny
+find_highlight=Pòdszkrzëni wszëtczé
+find_match_case_label=Rozeznôwôj miarã lëterów
+find_not_found=Nie nalôzł tekstu
+find_reached_bottom=Doszedł do kùńca dokùmentu, zaczinającë òd górë
+find_reached_top=Doszedł do pòczątkù dokùmentu, zaczinającë òd dołù
+
+toggle_sidebar.title=Pòsuwk wëbiérkù
+toggle_sidebar_label=Pòsuwk wëbiérkù
+
+outline.title=Wëskrzëni òbcéch dokùmentu
+outline_label=Òbcéch dokùmentu
+thumbs.title=Wëskrzëni miniaturë
+thumbs_label=Miniaturë
+findbar.title=Przeszëkôj dokùment
+findbar_label=Nalezë
+tools_label=Nôrzãdła
+first_page.title=Biéj do pierszi stronë
+first_page.label=Biéj do pierszi stronë
+last_page.label=Biéj do òstatny stronë
+invalid_file_error=Lëchi ôrt, abò pòpsëti lopk PDF.
+
+
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Strona {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura stronë {{page}}
+
+# Error panel labels
+error_more_info=Wicy infòrmacje
+error_less_info=Mni infòrmacje
+error_close=Close
+error_version_info=PDF.js v{{version}} (build: {{build}})
+
+
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Message: {{wiadło}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stóg}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=File: {{lopk}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Line: {{line}}
+rendering_error=Pòkôza sã fela przë renderowanim stronë.
+
+# Predefined zoom values
+page_scale_width=Szérzawa stronë
+page_scale_fit=Dopasëje stronã
+page_scale_auto=Aùtomatnô wiôlgòsc
+page_scale_actual=Naturalnô wiôlgòsc
+
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+loading_error_indicator=Fela
+loading_error=Pòkôza sã fela przë wczëtiwanim PDFù.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{[type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+
+request_password=PDF je zabezpieczony parolÄ…:
+printing_not_supported = Òstrzéga: przezérnik nie je do kùńca wspieróny przez drëkôrze
+
+# Context menu
+page_rotate_cw.label=Òbkrãcë w prawò
+page_rotate_ccw.label=Òbkrãcë w lewò
+
+
+last_page.title=Biéj do pòprzédny stronë
+last_page_label=Biéj do pòprzédny stronë
+page_rotate_cw.title=Òbkrãcë w prawò
+page_rotate_cw_label=Òbkrãcë w prawò
+page_rotate_ccw.title=Òbkrãcë w lewò
+page_rotate_ccw_label=Òbkrãcë w lewò
+
+
+web_fonts_disabled=Sécowé czconczi są wëłączoné: włączë je, bë móc ùżiwac òsadzonëch czconków w lopkach PDF.
+
+
+missing_file_error=Felëje lopka PDF.
+printing_not_ready = Òstrzéga: lopk mùszi sã do kùńca wczëtac zanim gò mòże drëkòwac
+
+document_colors_disabled=Dokùmentë PDF nie mògą ù swòjich farwów: \'Pòzwòlë stronóm wëbierac swòje farwë\' je wëłączoné w przezérnikù.
+invalid_password=Lëchô parola.
+text_annotation_type.alt=[Adnotacjô {{type}}]
+
+tools.title=Tools
+first_page_label=Go to First Page
+
+
diff --git a/static/pdf.js/locale/cy/viewer.properties b/static/pdf.js/locale/cy/viewer.properties
index 2133dabfb..15d2656e0 100644
--- a/static/pdf.js/locale/cy/viewer.properties
+++ b/static/pdf.js/locale/cy/viewer.properties
@@ -15,7 +15,7 @@
# Main toolbar buttons (tooltips and alt text for images)
previous.title=Tudalen Flaenorol
previous_label=Blaenorol
-next.title=Nesaf Tudalen
+next.title=Tudalen Nesaf
next_label=Nesaf
# LOCALIZATION NOTE (page_label, page_of):
@@ -30,16 +30,16 @@ zoom_out_label=Chwyddo Allan
zoom_in.title=Chwyddo Mewn
zoom_in_label=Chwyddo Mewn
zoom.title=Chwyddo
-presentation_mode.title=Newid i'r Modd Cyflwyn
-presentation_mode_label=Modd Cyflwyniad
+presentation_mode.title=Newid i'r Modd Cyflwyno
+presentation_mode_label=Modd Cyflwyno
open_file.title=Agor Ffeil
open_file_label=Agor
-print.title=Llwyth
+print.title=Argraffu
print_label=Argraffu
-download.title=Lawrlwytho
+download.title=Llwyth
download_label=Llwytho i Lawr
bookmark.title=Golwg cyfredol (copïo neu agor ffenestr newydd)
-bookmark_label=Golwg cyfredol
+bookmark_label=Golwg Gyfredol
# Secondary toolbar and context menu
tools.title=Offer
@@ -50,12 +50,37 @@ first_page_label=Mynd i'r Dudalen Gyntaf
last_page.title=Mynd i'r Dudalen Olaf
last_page.label=Mynd i'r Dudalen Olaf
last_page_label=Mynd i'r Dudalen Olaf
-page_rotate_cw.title=Cylchdroi yn Glocwedd
-page_rotate_cw.label=Cylchdroi yn Glocwedd
-page_rotate_cw_label=Cylchdroi yn Glocwedd
-page_rotate_ccw.title=Cylchdroi yn Wrthglocwedd
-page_rotate_ccw.label=Cylchdroi yn Wrthglocwedd
-page_rotate_ccw_label=Cylchdroi yn Wrthglocwedd
+page_rotate_cw.title=Cylchdroi Clocwedd
+page_rotate_cw.label=Cylchdroi Clocwedd
+page_rotate_cw_label=Cylchdroi Clocwedd
+page_rotate_ccw.title=Cylchdroi Gwrthglocwedd
+page_rotate_ccw.label=Cylchdroi Gwrthglocwedd
+page_rotate_ccw_label=Cylchdroi Gwrthglocwedd
+
+hand_tool_enable.title=Galluogi offeryn llaw
+hand_tool_enable_label=Galluogi offeryn llaw
+hand_tool_disable.title=Analluogi offeryn llaw
+hand_tool_disable_label=Analluogi offeryn llaw
+
+# Document properties dialog box
+document_properties.title=Priodweddau Dogfen…
+document_properties_label=Priodweddau Dogfen…
+document_properties_file_name=Enw ffeil:
+document_properties_file_size=Maint ffeil:
+document_properties_kb={{size_kb}} KB ({{size_b}} beit)
+document_properties_mb={{size_mb}} MB ({{size_b}} beit)
+document_properties_title=Teitl:
+document_properties_author=Awdur:
+document_properties_subject=Pwnc:
+document_properties_keywords=Allweddair:
+document_properties_creation_date=Dyddiad Creu:
+document_properties_modification_date=Dyddiad Addasu:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Crewr:
+document_properties_producer=Cynhyrchydd PDF:
+document_properties_version=Fersiwn PDF:
+document_properties_page_count=Cyfrif Tudalen:
+document_properties_close=Cau
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
@@ -64,6 +89,8 @@ toggle_sidebar.title=Toglo'r Bar Ochr
toggle_sidebar_label=Toglo'r Bar Ochr
outline.title=Dangos Amlinell Dogfen
outline_label=Amlinelliad Dogfen
+attachments.title=Dangos Atodiadau
+attachments_label=Atodiadau
thumbs.title=Dangos Lluniau Bach
thumbs_label=Lluniau Bach
findbar.title=Canfod yn y Ddogfen
@@ -95,7 +122,7 @@ error_less_info=Llai o wybodaeth
error_close=Cau
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v {{version}} (build: {{build}})
+error_version_info=PDF.js v{{version}} (build: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
error_message=Neges: {{message}}
@@ -117,16 +144,18 @@ page_scale_actual=Maint Gwirioneddol
# Loading indicator messages
loading_error_indicator=Gwall
loading_error=Digwyddodd gwall wrth lwytho'r PDF.
-invalid_file_error=Annilys neu llygredig ffeil PDF.
-missing_file_error=Ar goll ffeil PDF.
+invalid_file_error=Ffeil PDF annilys neu llwgr.
+missing_file_error=Ffeil PDF coll.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
text_annotation_type.alt=[Anodiad {{type}} ]
-request_password=PDF yn cael ei diogelu gan gyfrinair:
-invalid_password=Cyfrinair annilys.
+password_label=Rhowch gyfrinair i agor y PDF.
+password_invalid=Cyfrinair annilys. Ceisiwch eto.
+password_ok=Iawn
+password_cancel=Diddymu
printing_not_supported=Rhybudd: Nid yw argraffu yn cael ei gynnal yn llawn gan y porwr.
printing_not_ready=Rhybudd: Nid yw'r PDF wedi ei lwytho'n llawn ar gyfer argraffu.
diff --git a/static/pdf.js/locale/da/viewer.properties b/static/pdf.js/locale/da/viewer.properties
index fe97b4b4f..f44262222 100644
--- a/static/pdf.js/locale/da/viewer.properties
+++ b/static/pdf.js/locale/da/viewer.properties
@@ -12,16 +12,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Værktøjslinje knapper (tooltups og billedtekster)
-previous.title=Forrige
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Forrige side
previous_label=Forrige
-next.title=Næste
+next.title=Næste side
next_label=Næste
-# Oversættelsesnote:
-# Disse tekststrenge bliver sammensat i formen "Side: X af Y"
-# Oversæt ikke "{{pageCount}}", det er en variabel og vil blive erstattet
-# med det egentlig antal sider i PDF filen
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
page_label=Side:
page_of=af {{pageCount}}
@@ -30,103 +30,134 @@ zoom_out_label=Zoom ud
zoom_in.title=Zoom ind
zoom_in_label=Zoom ind
zoom.title=Zoom
-fullscreen.title=Fuldskærm
-fullscreen_label=Fuldskærm
+print.title=Udskriv
+print_label=Udskriv
+presentation_mode.title=Skift til præsentations-tilstand
+presentation_mode_label=Præsentations-tilstand
open_file.title=Ã…bn fil
open_file_label=Ã…bn
-print_label=Udskriv
-print.title=Udskriv
download.title=Hent
download_label=Hent
bookmark.title=Aktuel visning (kopier eller åbn i et nyt vindue)
bookmark_label=Aktuel visning
# Secondary toolbar and context menu
+tools.title=Værktøj
+tools_label=Værktøj
first_page.title=Gå til første side
first_page.label=Gå til første side
first_page_label=Gå til første side
last_page.title=GÃ¥ til sidste side
last_page.label=GÃ¥ til sidste side
last_page_label=GÃ¥ til sidste side
-page_rotate_cw.title=Rotér med uret
-page_rotate_cw.label=Rotér med uret
-page_rotate_cw_label=Rotér med uret
-page_rotate_ccw.title=Roéer mod uret
-page_rotate_ccw.label=Roéer mod uret
-page_rotate_ccw_label=Roéer mod uret
+page_rotate_cw.title=Roter med uret
+page_rotate_cw.label=Roter med uret
+page_rotate_cw_label=Roter med uret
+page_rotate_ccw.title=Roter mod uret
+page_rotate_ccw.label=Roter mod uret
+page_rotate_ccw_label=Roter mod uret
-# Tooltips of alternativ billedtekst til sidepanelet
-# (_label strengene er den alternative billedtekst, mens .title
-# strengene er tooltips
-toggle_slider.title=Skift slider
-toggle_slider_label=Skift slider
-outline.title=Vis dokumentoversigt
-outline_label=Dokumentoversigt
-thumbs.title=Vis thumbnails
-thumbs_label=Thumbnails
-findbar.title=Søg i dokumentet
-findbar_label=Søg
+hand_tool_enable.title=Aktiver håndværktøj
+hand_tool_enable_label=Aktiver håndværktøj
+hand_tool_disable.title=Deaktiver håndværktøj
+hand_tool_disable_label=Deaktiver håndværktøj
-# Thumbnails panelet (tooltips og alt. billedtekst)
-# Oversættelsesnote: "{{page}}" vil blive erstattet af det
-# egentlige sidetal
+# Document properties dialog box
+document_properties.title=Dokumentegenskaber…
+document_properties_label=Dokumentegenskaber…
+document_properties_file_name=Filnavn:
+document_properties_file_size=Filstørrelse:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Titel:
+document_properties_author=Forfatter:
+document_properties_subject=Emne:
+document_properties_keywords=Nøgleord:
+document_properties_creation_date=Oprettet:
+document_properties_modification_date=Redigeret:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Program:
+document_properties_producer=PDF-producent:
+document_properties_version=PDF-version:
+document_properties_page_count=Antal sider:
+document_properties_close=Luk
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Slå sidepanel til eller fra
+toggle_sidebar_label=Slå sidepanel til eller fra
+outline.title=Vis dokumentets disposition
+outline_label=Dokument-disposition
+attachments.title=Vis vedhæftede filer
+attachments_label=Vedhæftede filer
+thumbs.title=Vis miniaturer
+thumbs_label=Miniaturer
+findbar.title=Find i dokument
+findbar_label=Find
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
thumb_page_title=Side {{page}}
-# Oversættelsesnote: "{{page}}" vil blive erstattet af det
-# egentlige sidetal
-thumb_page_canvas=Thumbnail af side {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniature af side {{page}}
-# Søgepanelet samt knapper og beskeder
+# Find panel button title and messages
find_label=Find:
find_previous.title=Find den forrige forekomst
find_previous_label=Forrige
find_next.title=Find den næste forekomst
find_next_label=Næste
-find_highlight=Fremhæv alle forekomster
+find_highlight=Fremhæv alle
find_match_case_label=Forskel på store og små bogstaver
find_reached_top=Toppen af siden blev nået, fortsatte fra bunden
find_reached_bottom=Bunden af siden blev nået, fortsatte fra toppen
find_not_found=Der blev ikke fundet noget
-# Fejlpanel
+# Error panel labels
error_more_info=Mere information
error_less_info=Mindre information
error_close=Luk
-# Oversættelsesnote: "{{version}}" og "{{build}}" vil blive erstattet af
-# PDF.JS versionen og build ID
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
error_version_info=PDF.js v{{version}} (build: {{build}})
-# Oversættelsesnote: "{{message}}" vil blive erstattet af
-# en (engelsk) fejlbesked
-error_message=Besked: {{message}}
-# Oversættelsesnote: "{{stack}}" vil blive erstattet af et stack trace
-#
-error_stack=Stak: {{stack}}
-# Oversættelsesnote: "{{file}}" vil blive erstattet af et filnavn
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Fejlmeddelelse: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Fil: {{file}}
-# Oversættelsesnote: "{{line}}" vil blive erstattet af et linjetal
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Linje: {{line}}
-rendering_error=Der skete en fejl under gengivelsen af PDF-filen
+rendering_error=Der opstod en fejl ved generering af siden.
-# Prædefinerede zoom værdier
+# Predefined zoom values
page_scale_width=Sidebredde
-page_scale_fit=Helside
+page_scale_fit=Tilpas til side
page_scale_auto=Automatisk zoom
page_scale_actual=Faktisk størrelse
-# Indlæsningsindikator (load ikon)
+# Loading indicator messages
loading_error_indicator=Fejl
-loading_error=Der skete en fejl under indlæsningen af PDF-filen
-invalid_file_error=Ugyldig eller beskadiget PDF-fil
-missing_file_error=Manglende PDF-fil
+loading_error=Der opstod en fejl ved indlæsning af PDF-filen.
+invalid_file_error=PDF-filen er ugyldig eller ødelagt.
+missing_file_error=Manglende PDF-fil.
-# Oversættelsesnote: Dette vil blive brugt som et tooltip
-# "{{type}}" vil blive ersattet af en kommentar type fra en liste
-# defineret i PDF specifikationen (32000-1:2008 Table 169 – Annotation types).
-# Nogle almindelige typer er f.eks.: "Check", "Text", "Comment" og "Note"
-text_annotation_type.alt=[{{type}} Kommentar]
-request_password=PDF filen er beskyttet med et kodeord:
-invalid_password=Ugyldigt kodeord.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}}kommentar]
+password_label=Angiv adgangskode til at åbne denne PDF-fil.
+password_invalid=Ugyldig adgangskode. Prøv igen.
+password_ok=OK
+password_cancel=Fortryd
-printing_not_supported=Advarsel: Denne browser er ikke fuldt understøttet ved udskrift.
-printing_not_ready=Advarsel: PDF-filen er ikke helt klar til udskrivning.
-web_fonts_disabled=Web skrifttyper er slået fra: kan ikke benytte de indlejrede skrifttyper.
-web_colors_disabled=Web farver are slået fra.
+printing_not_supported=Advarsel: Udskrivning er ikke fuldt understøttet af browseren.
+printing_not_ready=Advarsel: PDF-filen er ikke fuldt indlæst til udskrivning.
+web_fonts_disabled=Webskrifttyper er deaktiverede. De indlejrede skrifttyper i PDF-filen kan ikke anvendes.
+document_colors_disabled=PDF-dokumenter må ikke bruge deres egne farver: \u0022'Tillad sider at vælge deres egne farver\u0022' er deaktiveret i browseren.
diff --git a/static/pdf.js/locale/de/viewer.properties b/static/pdf.js/locale/de/viewer.properties
index c9908b506..b641e2bc1 100644
--- a/static/pdf.js/locale/de/viewer.properties
+++ b/static/pdf.js/locale/de/viewer.properties
@@ -30,48 +30,70 @@ zoom_out_label=Verkleinern
zoom_in.title=Vergrößern
zoom_in_label=Vergrößern
zoom.title=Zoom
-presentation_mode.title=Zum Präsentationsmodus wechseln
-presentation_mode_label=Bildschirmpräsentation
-open_file.title=Datei öffnen
-open_file_label=Öffnen
print.title=Drucken
print_label=Drucken
-download.title=Herunterladen
-download_label=Herunterladen
-bookmark.title=Aktuelle Ansicht (Kopieren oder in einem neuen Fenster öffnen)
+presentation_mode.title=In Präsentationsmodus wechseln
+presentation_mode_label=Präsentationsmodus
+open_file.title=Datei öffnen
+open_file_label=Öffnen
+download.title=Dokument speichern
+download_label=Speichern
+bookmark.title=Aktuelle Ansicht (zum Kopieren oder Öffnen in einem neuen Fenster)
bookmark_label=Aktuelle Ansicht
# Secondary toolbar and context menu
tools.title=Werkzeuge
tools_label=Werkzeuge
-first_page.title=Erste Seite
-first_page.label=Erste Seite
-first_page_label=Erste Seite
-last_page.title=Letzte Seite
-last_page.label=Letzte Seite
-last_page_label=Letzte Seite
+first_page.title=Erste Seite anzeigen
+first_page.label=Erste Seite anzeigen
+first_page_label=Erste Seite anzeigen
+last_page.title=Letzte Seite anzeigen
+last_page.label=Letzte Seite anzeigen
+last_page_label=Letzte Seite anzeigen
page_rotate_cw.title=Im Uhrzeigersinn drehen
page_rotate_cw.label=Im Uhrzeigersinn drehen
page_rotate_cw_label=Im Uhrzeigersinn drehen
-page_rotate_ccw.title=Gegen den Uhrzeigersinn drehen
-page_rotate_ccw.label=Gegen den Uhrzeigersinn drehen
-page_rotate_ccw_label=Gegen den Uhrzeigersinn drehen
+page_rotate_ccw.title=Gegen Uhrzeigersinn drehen
+page_rotate_ccw.label=Gegen Uhrzeigersinn drehen
+page_rotate_ccw_label=Gegen Uhrzeigersinn drehen
hand_tool_enable.title=Hand-Werkzeug aktivieren
hand_tool_enable_label=Hand-Werkzeug aktivieren
hand_tool_disable.title=Hand-Werkzeug deaktivieren
hand_tool_disable_label=Hand-Werkzeug deaktivieren
+# Document properties dialog box
+document_properties.title=Dokumenteigenschaften
+document_properties_label=Dokumenteigenschaften…
+document_properties_file_name=Dateiname:
+document_properties_file_size=Dateigröße:
+document_properties_kb={{size_kb}} KB ({{size_b}} Bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} Bytes)
+document_properties_title=Titel:
+document_properties_author=Autor:
+document_properties_subject=Thema:
+document_properties_keywords=Stichwörter:
+document_properties_creation_date=Erstelldatum:
+document_properties_modification_date=Bearbeitungsdatum:
+document_properties_date_string={{date}} {{time}}
+document_properties_creator=Anwendung:
+document_properties_producer=PDF erstellt mit:
+document_properties_version=PDF-Version:
+document_properties_page_count=Seitenzahl:
+document_properties_close=Schließen
+
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Seitenleiste anzeigen
-toggle_sidebar_label=Seitenleiste
-outline.title=Zeige Inhaltsverzeichnis
-outline_label=Inhaltsverzeichnis
-thumbs.title=Zeige Vorschaubilder
-thumbs_label=Vorschaubilder
-findbar.title=Im Dokument suchen
+toggle_sidebar.title=Sidebar umschalten
+toggle_sidebar_label=Sidebar umschalten
+outline.title=Dokumentstruktur anzeigen
+outline_label=Dokumentstruktur
+attachments.title=Anhänge anzeigen
+attachments_label=Anhänge
+thumbs.title=Miniaturansichten anzeigen
+thumbs_label=Miniaturansichten
+findbar.title=Dokument durchsuchen
findbar_label=Suchen
# Thumbnails panel item (tooltip and alt text for images)
@@ -80,62 +102,62 @@ findbar_label=Suchen
thumb_page_title=Seite {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=Vorschau von Seite {{page}}
+thumb_page_canvas=Miniaturansicht von Seite {{page}}
# Find panel button title and messages
find_label=Suchen:
-find_previous.title=Das vorherige Auftreten des Ausdrucks suchen
-find_previous_label=Aufwärts
-find_next.title=Das nächste Auftreten des Ausdrucks suchen
-find_next_label=Abwärts
-find_highlight=Hervorheben
-find_match_case_label=Groß-/Kleinschreibung
-find_reached_top=Der Anfang des Dokuments wurde erreicht, Suche am Ende des Dokuments fortgesetzt
-find_reached_bottom=Das Ende des Dokuments wurde erreicht, Suche am Anfang des Dokuments fortgesetzt
-find_not_found=Ausdruck nicht gefunden
+find_previous.title=Vorheriges Auftreten des Suchbegriffs finden
+find_previous_label=Zurück
+find_next.title=Nächstes Auftreten des Suchbegriffs finden
+find_next_label=Weiter
+find_highlight=Alle hervorheben
+find_match_case_label=Groß-/Kleinschreibung beachten
+find_reached_top=Anfang des Dokuments erreicht, fahre am Ende fort
+find_reached_bottom=Ende des Dokuments erreicht, fahre am Anfang fort
+find_not_found=Suchbegriff nicht gefunden
# Error panel labels
-error_more_info=Mehr Info
-error_less_info=Weniger Info
+error_more_info=Mehr Informationen
+error_less_info=Weniger Informationen
error_close=Schließen
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (build: {{build}})
+error_version_info=PDF.js Version {{version}} (build: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
error_message=Nachricht: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
-error_stack=Stack: {{stack}}
+error_stack=Aufrufliste: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Datei: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Zeile: {{line}}
-rendering_error=Die PDF-Datei konnte nicht angezeigt werden.
+rendering_error=Beim Darstellen der Seite trat ein Fehler auf.
# Predefined zoom values
page_scale_width=Seitenbreite
-page_scale_fit=Ganze Seite
-page_scale_auto=Automatisch
+page_scale_fit=Seitengröße
+page_scale_auto=Automatischer Zoom
page_scale_actual=Originalgröße
# Loading indicator messages
loading_error_indicator=Fehler
-loading_error=Die PDF-Datei konnte nicht geladen werden.
-invalid_file_error=Ungültige oder beschädigte PDF-Datei.
-missing_file_error=Fehlende PDF-Datei.
+loading_error=Beim Laden der PDF-Datei trat ein Fehler auf.
+invalid_file_error=Ungültige oder beschädigte PDF-Datei
+missing_file_error=Fehlende PDF-Datei
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[{{type}} Annotation]
-password_label=Geben Sie das Passwort ein, um diese Datei zu öffnen.
-password_invalid=Ungültiges Passwort. Versuchen Sie es erneut.
+text_annotation_type.alt=[Anlage: {{type}}]
+password_label=Geben Sie zum Öffnen der PDF-Datei deren Passwort ein.
+password_invalid=Falsches Passwort. Bitte versuchen Sie es erneut.
password_ok=OK
password_cancel=Abbrechen
-printing_not_supported=Warnung: Drucken wird durch diesen Browser nicht vollständig unterstützt.
-printing_not_ready=Warnung: Die PDF-Datei ist zum Drucken noch nicht vollständig geladen.
-web_fonts_disabled=Webfonts sind deaktiviert: Eingebundene PDF-Schriftarten können nicht verwendet werden.
-document_colors_disabled=PDF-Dateien können eigene Farben nicht verwenden: \'Seiten das Verwenden von eigenen Farben erlauben\' ist im Browser deaktiviert.
+printing_not_supported=Warnung: Die Drucken-Funktion wird durch diesen Browser nicht vollständig unterstützt.
+printing_not_ready=Warnung: Die PDF-Datei ist nicht vollständig geladen, dies ist für das Drucken aber empfohlen.
+web_fonts_disabled=Web-Schriftarten sind deaktiviert: Eingebettete PDF-Schriftarten konnten nicht geladen werden.
+document_colors_disabled=PDF-Dokumenten ist es nicht erlaubt, ihre eigenen Farben zu verwenden: \'Seiten das Verwenden von eigenen Farben erlauben\' ist im Browser deaktiviert.
diff --git a/static/pdf.js/locale/el/viewer.properties b/static/pdf.js/locale/el/viewer.properties
index dfa852f44..36723c22b 100644
--- a/static/pdf.js/locale/el/viewer.properties
+++ b/static/pdf.js/locale/el/viewer.properties
@@ -1,16 +1,6 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Main toolbar buttons (tooltips and alt text for images)
previous.title=Î ÏοηγοÏμενη σελίδα
@@ -32,8 +22,6 @@ zoom_in_label=ΜεγÎθυνση
zoom.title=ΜεγÎθυνση
print.title=ΕκτÏπωση
print_label=ΕκτÏπωση
-presentation_mode.title=Μετάβαση σε λειτουÏγία παÏουσίασης
-presentation_mode_label=ΛειτουÏγία παÏουσίασης
open_file.title=Άνοιγμα αÏχείου
open_file_label=Άνοιγμα
download.title=Λήψη
@@ -44,14 +32,12 @@ bookmark_label=ΤÏÎχουσα Ï€Ïοβολή
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Εναλλαγή Ï€Ïοβολής πλευÏικής στήλης
-toggle_sidebar_label=Εναλλαγή Ï€Ïοβολής πλευÏικής στήλης
outline.title=Î Ïοβολή διάÏθÏωσης κειμÎνου
-outline_label=ΔιάθÏωση κειμÎνου
+outline_label=ΔιάÏθÏωση κειμÎνου
thumbs.title=Î Ïοβολή μικÏογÏαφιών
thumbs_label=ΜικÏογÏαφίες
-findbar.title=ΕÏÏεση στο ÎγγÏαφο
-findbar_label=ΕÏÏεση
+
+
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
@@ -61,12 +47,54 @@ thumb_page_title=Σελίδα {{page}}
# number.
thumb_page_canvas=ΜικÏογÏαφία της σελίδας {{page}}
-# Context menu
first_page.label=Μετάβαση στην Ï€Ïώτη σελίδα
-last_page.label=Μετάβαση στην τελευταία σελίδα
+
+# Error panel labels
+error_more_info=ΠεÏισσότεÏες πληÏοφοÏίες
+error_less_info=ΛιγότεÏες πληÏοφοÏίες
+error_close=Κλείσιμο
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Μήνυμα: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ΑÏχείο: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Line: {{line}}
+rendering_error=Î ÏοÎκυψε σφάλμα κατά την ανάλυση της σελίδας.
+
+# Predefined zoom values
+page_scale_width=Πλάτος σελίδας
+page_scale_fit=ÎœÎγεθος σελίδας
+page_scale_auto=Αυτόματη μεγÎθυνση
+page_scale_actual=Î Ïαγματικό μÎγεθος
+
+
+# Context menu
page_rotate_cw.label=ΔεξιόστÏοφη πεÏιστÏοφή
page_rotate_ccw.label=ΑÏιστεÏόστÏοφη πεÏιστÏοφή
+presentation_mode.title=Μετάβαση σε λειτουÏγία παÏουσίασης
+presentation_mode_label=ΛειτουÏγία παÏουσίασης
+
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+
+loading_error_indicator=Σφάλμα
+loading_error=Î ÏοÎκυψε Îνα σφάλμα κατά τη φόÏτωση του PDF.
+
+request_password=Το PDF Ï€ÏοστατεÏεται από κωδικό:
+
+printing_not_supported=Î Ïοειδοποίηση: Η εκτÏπωση δεν υποστηÏίζεται πλήÏως από αυτόν τον πεÏιηγητή.
+
+
+
+findbar.title=ΕÏÏεση στο ÎγγÏαφο
+findbar_label=ΕÏÏεση
+
+
# Find panel button title and messages
find_label=ΕÏÏεση:
find_previous.title=ΕÏÏεση της Ï€ÏοηγοÏμενης εμφάνισης της φÏάσης
@@ -79,46 +107,25 @@ find_reached_top=Έλευση στην αÏχή του εγγÏάφου, συν
find_reached_bottom=Έλευση στο Ï„Îλος του εγγÏάφου, συνÎχεια από την αÏχή
find_not_found=Η φÏάση δεν βÏÎθηκε
-# Error panel labels
-error_more_info=ΠεÏισσότεÏες πληÏοφοÏίες
-error_less_info=ΛιγότεÏες πληÏοφοÏίες
-error_close=Κλείσιμο
+invalid_file_error=Μη ÎγκυÏο ή κατεστÏαμμÎνο αÏχείο PDF.
+last_page.label=Μετάβαση στη τελευταία σελίδα
+
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
error_version_info=PDF.js v{{version}} (build: {{build}})
-# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
-# english string describing the error.
-error_message=Μήνυμα: {{message}}
-# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
-# trace.
-error_stack=Stack: {{stack}}
-# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
-error_file=ΑÏχείο: {{file}}
-# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=ΓÏαμμή: {{line}}
-rendering_error=Î ÏοÎκυψε σφάλμα κατά την ανάλυση της σελίδας.
-# Predefined zoom values
-page_scale_width=Πλάτος σελίδας
-page_scale_fit=ÎœÎγεθος σελίδας
-page_scale_auto=Αυτόματη μεγÎθυνση
-page_scale_actual=Î Ïαγματικό μÎγεθος
+missing_file_error=Λείπει αÏχείο PDF.
-# Loading indicator messages
-loading_error_indicator=Σφάλμα
-loading_error=Î ÏοÎκυψε σφάλμα κατά τη φόÏτωση του PDF.
-invalid_file_error=Μη ÎγκυÏο ή κατεστÏαμμÎνο αÏχείο PDF.
-missing_file_error=Λείπει το αÏχείο PDF.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
-# "{{type}}" will be replaced with an annotation type from a list defined in
-# the PDF spec (32000-1:2008 Table 169 – Annotation types).
-# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Σημείωση]
-request_password=Το PDF Ï€ÏοστατεÏεται από κωδικό:
+toggle_sidebar.title=Εναλλαγή Ï€Ïοβολής πλευÏικής στήλης
+toggle_sidebar_label=Εναλλαγή Ï€Ïοβολής πλευÏικής στήλης
+
+web_fonts_disabled=Οι γÏαμματοσειÏÎÏ‚ Web απενεÏγοποιημÎνες: αδυναμία χÏήσης των ενσωματωμÎνων γÏαμματοσειÏών PDF.
+
+printing_not_ready=Î Ïοειδοποίηση: Το PDF δεν φοÏτώθηκε πλήÏως για εκτÏπωση.
+
+document_colors_disabled=Δεν επιτÏÎπεται στα ÎγγÏαφα PDF να χÏησιμοποιοÏν τα δικά τους χÏώματα: Η επιλογή \'Îα επιτÏÎπεται η χÏήση χÏωμάτων της σελίδας\' δεν είναι ενεÏγή στην εφαÏμογή.
+
invalid_password=Μη ÎγκυÏος κωδικός.
+text_annotation_type.alt=[{{type}} Annotation]
-printing_not_supported=Î Ïοειδοποίηση: Η εκτÏπωση δεν υποστηÏίζεται πλήÏως από αυτόν τον πεÏιηγητή.
-printing_not_ready=Î Ïοσοχή: Το PDF δεν είναι πλήÏως φοÏτωμÎνο για εκτÏπωση.
-web_fonts_disabled=Οι γÏαμματοσειÏÎÏ‚ Web είναι απενεÏγοποιημÎνες: δεν είναι δυνατή η χÏήση ενσωματωμÎνων γÏαμματοσειÏών PDF.
-document_colors_disabled=Στα ÎγγÏαφα PDF δεν επιτÏÎπεται να χÏησιμοποιοÏν τα δικά τους χÏώματα: Η ÏÏθμιση \'ΕπιτÏÎπεται στις σελίδες να επιλÎξουν τα δικά τους χÏώματα \' είναι απενεÏγοποιημÎνη στο Ï€ÏόγÏαμμα πεÏιήγησης.
diff --git a/static/pdf.js/locale/en-GB/viewer.properties b/static/pdf.js/locale/en-GB/viewer.properties
new file mode 100644
index 000000000..64239d285
--- /dev/null
+++ b/static/pdf.js/locale/en-GB/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Previous Page
+previous_label=Previous
+next.title=Next Page
+next_label=Next
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Page:
+page_of=of {{pageCount}}
+
+zoom_out.title=Zoom Out
+zoom_out_label=Zoom Out
+zoom_in.title=Zoom In
+zoom_in_label=Zoom In
+zoom.title=Zoom
+presentation_mode.title=Switch to Presentation Mode
+presentation_mode_label=Presentation Mode
+open_file.title=Open File
+open_file_label=Open
+print.title=Print
+print_label=Print
+download.title=Download
+download_label=Download
+bookmark.title=Current view (copy or open in new window)
+bookmark_label=Current View
+
+# Secondary toolbar and context menu
+tools.title=Tools
+tools_label=Tools
+first_page.title=Go to First Page
+first_page.label=Go to First Page
+first_page_label=Go to First Page
+last_page.title=Go to Last Page
+last_page.label=Go to Last Page
+last_page_label=Go to Last Page
+page_rotate_cw.title=Rotate Clockwise
+page_rotate_cw.label=Rotate Clockwise
+page_rotate_cw_label=Rotate Clockwise
+page_rotate_ccw.title=Rotate Anti-Clockwise
+page_rotate_ccw.label=Rotate Anti-Clockwise
+page_rotate_ccw_label=Rotate Anti-Clockwise
+
+hand_tool_enable.title=Enable hand tool
+hand_tool_enable_label=Enable hand tool
+hand_tool_disable.title=Disable hand tool
+hand_tool_disable_label=Disable hand tool
+
+# Document properties dialog box
+document_properties.title=Document Properties…
+document_properties_label=Document Properties…
+document_properties_file_name=File name:
+document_properties_file_size=File size:
+document_properties_kb={{size_kb}} kB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Title:
+document_properties_author=Author:
+document_properties_subject=Subject:
+document_properties_keywords=Keywords:
+document_properties_creation_date=Creation Date:
+document_properties_modification_date=Modification Date:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creator:
+document_properties_producer=PDF Producer:
+document_properties_version=PDF Version:
+document_properties_page_count=Page Count:
+document_properties_close=Close
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Toggle Sidebar
+toggle_sidebar_label=Toggle Sidebar
+outline.title=Show Document Outline
+outline_label=Document Outline
+attachments.title=Show Attachments
+attachments_label=Attachments
+thumbs.title=Show Thumbnails
+thumbs_label=Thumbnails
+findbar.title=Find in Document
+findbar_label=Find
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Page {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Thumbnail of Page {{page}}
+
+# Find panel button title and messages
+find_label=Find:
+find_previous.title=Find the previous occurrence of the phrase
+find_previous_label=Previous
+find_next.title=Find the next occurrence of the phrase
+find_next_label=Next
+find_highlight=Highlight all
+find_match_case_label=Match case
+find_reached_top=Reached top of document, continued from bottom
+find_reached_bottom=Reached end of document, continued from top
+find_not_found=Phrase not found
+
+# Error panel labels
+error_more_info=More Information
+error_less_info=Less Information
+error_close=Close
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Message: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=File: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Line: {{line}}
+rendering_error=An error occurred while rendering the page.
+
+# Predefined zoom values
+page_scale_width=Page Width
+page_scale_fit=Page Fit
+page_scale_auto=Automatic Zoom
+page_scale_actual=Actual Size
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=An error occurred while loading the PDF.
+invalid_file_error=Invalid or corrupted PDF file.
+missing_file_error=Missing PDF file.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=Enter the password to open this PDF file.
+password_invalid=Invalid password. Please try again.
+password_ok=OK
+password_cancel=Cancel
+
+printing_not_supported=Warning: Printing is not fully supported by this browser.
+printing_not_ready=Warning: The PDF is not fully loaded for printing.
+web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts.
+document_colors_disabled=PDF documents are not allowed to use their own colours: \'Allow pages to choose their own colours\' is deactivated in the browser.
diff --git a/static/pdf.js/locale/en-US/viewer.properties b/static/pdf.js/locale/en-US/viewer.properties
index 2c893a4a3..c52020c5c 100644
--- a/static/pdf.js/locale/en-US/viewer.properties
+++ b/static/pdf.js/locale/en-US/viewer.properties
@@ -62,6 +62,26 @@ hand_tool_enable_label=Enable hand tool
hand_tool_disable.title=Disable hand tool
hand_tool_disable_label=Disable hand tool
+# Document properties dialog box
+document_properties.title=Document Properties…
+document_properties_label=Document Properties…
+document_properties_file_name=File name:
+document_properties_file_size=File size:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Title:
+document_properties_author=Author:
+document_properties_subject=Subject:
+document_properties_keywords=Keywords:
+document_properties_creation_date=Creation Date:
+document_properties_modification_date=Modification Date:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creator:
+document_properties_producer=PDF Producer:
+document_properties_version=PDF Version:
+document_properties_page_count=Page Count:
+document_properties_close=Close
+
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
@@ -69,6 +89,8 @@ toggle_sidebar.title=Toggle Sidebar
toggle_sidebar_label=Toggle Sidebar
outline.title=Show Document Outline
outline_label=Document Outline
+attachments.title=Show Attachments
+attachments_label=Attachments
thumbs.title=Show Thumbnails
thumbs_label=Thumbnails
findbar.title=Find in Document
@@ -124,6 +146,7 @@ loading_error_indicator=Error
loading_error=An error occurred while loading the PDF.
invalid_file_error=Invalid or corrupted PDF file.
missing_file_error=Missing PDF file.
+unexpected_response_error=Unexpected server response.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
diff --git a/static/pdf.js/locale/en-ZA/viewer.properties b/static/pdf.js/locale/en-ZA/viewer.properties
new file mode 100644
index 000000000..5588ff195
--- /dev/null
+++ b/static/pdf.js/locale/en-ZA/viewer.properties
@@ -0,0 +1,161 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Previous Page
+previous_label=Previous
+next.title=Next Page
+next_label=Next
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Page:
+page_of=of {{pageCount}}
+
+zoom_out.title=Zoom Out
+zoom_out_label=Zoom Out
+zoom_in.title=Zoom In
+zoom_in_label=Zoom In
+zoom.title=Zoom
+presentation_mode.title=Switch to Presentation Mode
+presentation_mode_label=Presentation Mode
+open_file.title=Open File
+open_file_label=Open
+print.title=Print
+print_label=Print
+download.title=Download
+download_label=Download
+bookmark.title=Current view (copy or open in new window)
+bookmark_label=Current View
+
+# Secondary toolbar and context menu
+tools.title=Tools
+tools_label=Tools
+first_page.title=Go to First Page
+first_page.label=Go to First Page
+first_page_label=Go to First Page
+last_page.title=Go to Last Page
+last_page.label=Go to Last Page
+last_page_label=Go to Last Page
+page_rotate_cw.title=Rotate Clockwise
+page_rotate_cw.label=Rotate Clockwise
+page_rotate_cw_label=Rotate Clockwise
+page_rotate_ccw.title=Rotate Counterclockwise
+page_rotate_ccw.label=Rotate Counterclockwise
+page_rotate_ccw_label=Rotate Counterclockwise
+
+hand_tool_enable.title=Enable hand tool
+hand_tool_enable_label=Enable hand tool
+hand_tool_disable.title=Disable hand tool
+hand_tool_disable_label=Disable hand tool
+
+# Document properties dialog box
+document_properties.title=Document Properties…
+document_properties_label=Document Properties…
+document_properties_file_name=File name:
+document_properties_file_size=File size:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Title:
+document_properties_author=Author:
+document_properties_subject=Subject:
+document_properties_keywords=Keywords:
+document_properties_creation_date=Creation Date:
+document_properties_modification_date=Modification Date:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creator:
+document_properties_producer=PDF Producer:
+document_properties_version=PDF Version:
+document_properties_page_count=Page Count:
+document_properties_close=Close
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Toggle Sidebar
+toggle_sidebar_label=Toggle Sidebar
+outline.title=Show Document Outline
+outline_label=Document Outline
+thumbs.title=Show Thumbnails
+thumbs_label=Thumbnails
+findbar.title=Find in Document
+findbar_label=Find
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Page {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Thumbnail of Page {{page}}
+
+# Find panel button title and messages
+find_label=Find:
+find_previous.title=Find the previous occurrence of the phrase
+find_previous_label=Previous
+find_next.title=Find the next occurrence of the phrase
+find_next_label=Next
+find_highlight=Highlight all
+find_match_case_label=Match case
+find_reached_top=Reached top of document, continued from bottom
+find_reached_bottom=Reached end of document, continued from top
+find_not_found=Phrase not found
+
+# Error panel labels
+error_more_info=More Information
+error_less_info=Less Information
+error_close=Close
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Message: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=File: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Line: {{line}}
+rendering_error=An error occurred while rendering the page.
+
+# Predefined zoom values
+page_scale_width=Page Width
+page_scale_fit=Page Fit
+page_scale_auto=Automatic Zoom
+page_scale_actual=Actual Size
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=An error occurred while loading the PDF.
+invalid_file_error=Invalid or corrupted PDF file.
+missing_file_error=Missing PDF file.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=Enter the password to open this PDF file.
+password_invalid=Invalid password. Please try again.
+password_ok=OK
+password_cancel=Cancel
+
+printing_not_supported=Warning: Printing is not fully supported by this browser.
+printing_not_ready=Warning: The PDF is not fully loaded for printing.
+web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts.
+document_colors_disabled=PDF documents are not allowed to use their own colours: 'Allow pages to choose their own colours' is deactivated in the browser.
diff --git a/static/pdf.js/locale/eo/viewer.properties b/static/pdf.js/locale/eo/viewer.properties
new file mode 100644
index 000000000..78b822943
--- /dev/null
+++ b/static/pdf.js/locale/eo/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=AntaÅa paÄo
+previous_label=MalantaÅen
+next.title=Venonta paÄo
+next_label=AntaÅen
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=PaÄo:
+page_of=el {{pageCount}}
+
+zoom_out.title=Malpligrandigi
+zoom_out_label=Malpligrandigi
+zoom_in.title=Pligrandigi
+zoom_in_label=Pligrandigi
+zoom.title=Pligrandigilo
+presentation_mode.title=Iri al prezenta reÄimo
+presentation_mode_label=Prezenta reÄimo
+open_file.title=Malfermi dosieron
+open_file_label=Malfermi
+print.title=Presi
+print_label=Presi
+download.title=ElÅuti
+download_label=ElÅuti
+bookmark.title=Nuna vido (kopii aÅ malfermi en nova fenestro)
+bookmark_label=Nuna vido
+
+# Secondary toolbar and context menu
+tools.title=Iloj
+tools_label=Iloj
+first_page.title=Iri al la unua paÄo
+first_page.label=Iri al la unua paÄo
+first_page_label=Iri al la unua paÄo
+last_page.title=Iri al la lasta paÄo
+last_page.label=Iri al la lasta paÄo
+last_page_label=Iri al la lasta paÄo
+page_rotate_cw.title=Rotaciigi dekstrume
+page_rotate_cw.label=Rotaciigi dekstrume
+page_rotate_cw_label=Rotaciigi dekstrume
+page_rotate_ccw.title=Rotaciigi maldekstrume
+page_rotate_ccw.label=Rotaciigi maldekstrume
+page_rotate_ccw_label=Rotaciigi maldekstrume
+
+hand_tool_enable.title=Aktivigi manan ilon
+hand_tool_enable_label=Aktivigi manan ilon
+hand_tool_disable.title=Malaktivigi manan ilon
+hand_tool_disable_label=Malaktivigi manan ilon
+
+# Document properties dialog box
+document_properties.title=Atributoj de dokumento…
+document_properties_label=Atributoj de dokumento…
+document_properties_file_name=Nomo de dosiero:
+document_properties_file_size=Grado de dosiero:
+document_properties_kb={{size_kb}} KO ({{size_b}} oktetoj)
+document_properties_mb={{size_mb}} MO ({{size_b}} oktetoj)
+document_properties_title=Titolo:
+document_properties_author=AÅtoro:
+document_properties_subject=Temo:
+document_properties_keywords=Åœlosilvorto:
+document_properties_creation_date=Dato de kreado:
+document_properties_modification_date=Dato de modifo:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Kreinto:
+document_properties_producer=Produktinto de PDF:
+document_properties_version=Versio de PDF:
+document_properties_page_count=Nombro de paÄoj:
+document_properties_close=Fermi
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Montri/kaÅi flankan strion
+toggle_sidebar_label=Montri/kaÅi flankan strion
+outline.title=Montri skemon de dokumento
+outline_label=Skemo de dokumento
+attachments.title=Montri kunsendaĵojn
+attachments_label=Kunsendaĵojn
+thumbs.title=Montri miniaturojn
+thumbs_label=Miniaturoj
+findbar.title=Serĉi en dokumento
+findbar_label=Serĉi
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=PaÄo {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniaturo de paÄo {{page}}
+
+# Find panel button title and messages
+find_label=Serĉi:
+find_previous.title=Serĉi la antaÅan aperon de la frazo
+find_previous_label=MalantaÅen
+find_next.title=Serĉi la venontan aperon de la frazo
+find_next_label=AntaÅen
+find_highlight=Elstarigi ĉiujn
+find_match_case_label=Distingi inter majuskloj kaj minuskloj
+find_reached_top=Komenco de la dokumento atingita, daÅrigado ekde la fino
+find_reached_bottom=Fino de la dokumento atingita, daÅrigado ekde la komenco
+find_not_found=Frazo ne trovita
+
+# Error panel labels
+error_more_info=Pli da informo
+error_less_info=Mapli da informo
+error_close=Fermi
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=MesaÄo: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stako: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Dosiero: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linio: {{line}}
+rendering_error=Okazis eraro dum la montrado de la paÄo.
+
+# Predefined zoom values
+page_scale_width=LarÄo de paÄo
+page_scale_fit=Adapti paÄon
+page_scale_auto=AÅtomata skalo
+page_scale_actual=Reala gandeco
+
+# Loading indicator messages
+loading_error_indicator=Eraro
+loading_error=Okazis eraro dum la Åargado de la PDF dosiero.
+invalid_file_error=Nevalida aÅ difektita PDF dosiero.
+missing_file_error=Mankas dosiero PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Prinoto: {{type}}]
+password_label=Tajpu pasvorton por malfermi tiun ĉi dosieron PDF.
+password_invalid=Nevalida pasvorto. Bonvolu provi denove.
+password_ok=Akcepti
+password_cancel=Nuligi
+
+printing_not_supported=Averto: tiu ĉi retesplorilo ne plene subtenas presadon.
+printing_not_ready=Warning: La PDF dosiero ne estas plene Åargita por presado.
+web_fonts_disabled=Neaktivaj teksaĵaj tiparoj: ne elbas uzi enmetitajn tiparojn de PDF.
+document_colors_disabled=Dokumentoj PDF ne rajtas havi siajn proprajn kolorojn: \'Permesi al paÄoj elekti siajn proprajn kolorojn\' estas malaktiva en la retesplorilo.
diff --git a/static/pdf.js/locale/es-AR/viewer.properties b/static/pdf.js/locale/es-AR/viewer.properties
new file mode 100644
index 000000000..c931a101c
--- /dev/null
+++ b/static/pdf.js/locale/es-AR/viewer.properties
@@ -0,0 +1,169 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Página anterior
+previous_label=Anterior
+next.title=Página siguiente
+next_label=Siguiente
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Página:
+page_of=de {{pageCount}}
+
+zoom_out.title=Alejar
+zoom_out_label=Alejar
+zoom_in.title=Acercar
+zoom_in_label=Acercar
+zoom.title=Zoom
+print.title=Imprimir
+print_label=Imprimir
+presentation_mode.title=Cambiar a modo presentación
+presentation_mode_label=Modo presentación
+open_file.title=Abrir archivo
+open_file_label=Abrir
+download.title=Descargar
+download_label=Descargar
+bookmark.title=Vista actual (copiar o abrir en nueva ventana)
+bookmark_label=Vista actual
+
+# Secondary toolbar and context menu
+tools.title=Herramientas
+tools_label=Herramientas
+first_page.title=Ir a primera página
+first_page.label=Ir a primera página
+first_page_label=Ir a primera página
+last_page.title=Ir a última página
+last_page.label=Ir a última página
+last_page_label=Ir a última página
+page_rotate_cw.title=Rotar horario
+page_rotate_cw.label=Rotar horario
+page_rotate_cw_label=Rotar horario
+page_rotate_ccw.title=Rotar antihorario
+page_rotate_ccw.label=Rotar antihorario
+page_rotate_ccw_label=Rotar antihorario
+
+hand_tool_enable.title=Habilitar herramienta mano
+hand_tool_enable_label=Habilitar herramienta mano
+hand_tool_disable.title=Deshabilitar herramienta mano
+hand_tool_disable_label=Deshabilitar herramienta mano
+
+# Document properties dialog box
+document_properties.title=Propiedades del documento…
+document_properties_label=Propiedades del documento…
+document_properties_file_name=Nombre de archivo:
+document_properties_file_size=Tamaño de archovo:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=TÃtulo:
+document_properties_author=Autor:
+document_properties_subject=Asunto:
+document_properties_keywords=Palabras clave:
+document_properties_creation_date=Fecha de creación:
+document_properties_modification_date=Fecha de modificación:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creador:
+document_properties_producer=PDF Productor:
+document_properties_version=Versión de PDF:
+document_properties_page_count=Cantidad de páginas:
+document_properties_close=Cerrar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Alternar barra lateral
+toggle_sidebar_label=Alternar barra lateral
+outline.title=Mostrar esquema del documento
+outline_label=Esquema del documento
+attachments.title=Mostrar adjuntos
+attachments_label=Adjuntos
+thumbs.title=Mostrar miniaturas
+thumbs_label=Miniaturas
+findbar.title=Buscar en documento
+findbar_label=Buscar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Página {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura de página {{page}}
+
+# Context menu
+first_page.label=Ir a la primera página
+last_page.label=Ir a la última página
+page_rotate_cw.label=Rotar en sentido horario
+page_rotate_ccw.label=Rotar en sentido antihorario
+
+# Find panel button title and messages
+find_label=Buscar:
+find_previous.title=Buscar la aparición anterior de la frase
+find_previous_label=Anterior
+find_next.title=Buscar la siguiente aparición de la frase
+find_next_label=Siguiente
+find_highlight=Resaltar todo
+find_match_case_label=Coincidir mayúsculas
+find_reached_top=Inicio de documento alcanzado, continuando desde abajo
+find_reached_bottom=Fin de documento alcanzando, continuando desde arriba
+find_not_found=Frase no encontrada
+
+# Error panel labels
+error_more_info=Más información
+error_less_info=Menos información
+error_close=Cerrar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mensaje: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Archivo: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=LÃnea: {{line}}
+rendering_error=Ocurrió un error al dibujar la página.
+
+# Predefined zoom values
+page_scale_width=Ancho de página
+page_scale_fit=Ajustar página
+page_scale_auto=Zoom automático
+page_scale_actual=Tamaño real
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=Ocurrió un error al cargar el PDF.
+invalid_file_error=Archivo PDF no válido o cocrrupto.
+missing_file_error=Archivo PDF faltante.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Anotación]
+password_label=Ingrese la contraseña para abrir este archivo PDF
+password_invalid=Contraseña inválida. Intente nuevamente.
+password_ok=Aceptar
+password_cancel=Cancelar
+
+printing_not_supported=Advertencia: La impresión no está totalmente soportada por este navegador.
+printing_not_ready=Advertencia: El PDF no está completamente cargado para impresión.
+web_fonts_disabled=TipografÃa web deshabilitada: no se pueden usar tipos incrustados en PDF.
+document_colors_disabled=Los documentos PDF no tienen permitido usar sus propios colores: \'Permitir a las páginas elegir sus propios colores\' está desactivado en el navegador.
diff --git a/static/pdf.js/locale/es-CL/viewer.properties b/static/pdf.js/locale/es-CL/viewer.properties
new file mode 100644
index 000000000..9219cc9c1
--- /dev/null
+++ b/static/pdf.js/locale/es-CL/viewer.properties
@@ -0,0 +1,128 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+previous.title = Página anterior
+previous_label = Anterior
+next.title = Página siguiente
+next_label = Siguiente
+page_label = Página:
+page_of = de {{pageCount}}
+zoom_out.title = Alejar
+zoom_out_label = Alejar
+zoom_in.title = Acercar
+zoom_in_label = Acercar
+zoom.title = Ampliación
+print.title = Imprimir
+print_label = Imprimir
+presentation_mode.title = Cambiar al modo de presentación
+presentation_mode_label = Modo de presentación
+open_file.title = Abrir archivo
+open_file_label = Abrir
+download.title = Descargar
+download_label = Descargar
+bookmark.title = Vista actual (copiar o abrir en nueva ventana)
+bookmark_label = Vista actual
+tools.title=Herramientas
+tools_label=Herramientas
+first_page.title=Ir a la primera página
+first_page.label=Ir a la primera página
+first_page_label=Ir a la primera página
+last_page.title=Ir a la última página
+last_page.label=Ir a la última página
+last_page_label=Ir a la última página
+page_rotate_cw.title=Girar a la derecha
+page_rotate_cw.label=Girar a la derecha
+page_rotate_cw_label=Girar a la derecha
+page_rotate_ccw.title=Girar a la izquierda
+page_rotate_ccw.label=Girar a la izquierda
+page_rotate_ccw_label=Girar a la izquierda
+
+hand_tool_enable.title=Activar herramienta de mano
+hand_tool_enable_label=Activar herramienta de mano
+hand_tool_disable.title=Desactivar herramienta de mano
+hand_tool_disable_label=Desactivar herramienta de mano
+
+document_properties.title=Propiedades del documento…
+document_properties_label=Propiedades del documento…
+document_properties_file_name=Nombre del archivo:
+document_properties_file_size=Tamaño del archivo:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=TÃtulo:
+document_properties_author=Autor:
+document_properties_subject=Asunto:
+document_properties_keywords=Palabras clave:
+document_properties_creation_date=Fecha de creación:
+document_properties_modification_date=Fecha de modificación:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creador:
+document_properties_producer=Productor del PDF:
+document_properties_version=Versión de PDF:
+document_properties_page_count=Cantidad de páginas:
+document_properties_close=Cerrar
+
+toggle_sidebar.title=Barra lateral
+toggle_sidebar_label=Mostrar u ocultar la barra lateral
+outline.title = Mostrar esquema del documento
+outline_label = Esquema del documento
+attachments.title=Mostrar adjuntos
+attachments_label=Adjuntos
+thumbs.title = Mostrar miniaturas
+thumbs_label = Miniaturas
+findbar.title = Buscar en el documento
+findbar_label = Buscar
+thumb_page_title = Página {{page}}
+thumb_page_canvas = Miniatura de la página {{page}}
+first_page.label = Ir a la primera página
+last_page.label = Ir a la última página
+page_rotate_cw.label = Rotar en sentido de los punteros del reloj
+page_rotate_ccw.label = Rotar en sentido contrario a los punteros del reloj
+find_label = Buscar:
+find_previous.title = Encontrar la aparición anterior de la frase
+find_previous_label = Previo
+find_next.title = Encontrar la siguiente aparición de la frase
+find_next_label = Siguiente
+find_highlight = Destacar todos
+find_match_case_label = Coincidir mayús./minús.
+find_reached_top=Se alcanzó el inicio del documento, continuando desde el final
+find_reached_bottom=Se alcanzó el final del documento, continuando desde el inicio
+find_not_found = Frase no encontrada
+error_more_info = Más información
+error_less_info = Menos información
+error_close = Cerrar
+error_version_info=PDF.js v{{version}} (compilación: {{build}})
+error_message = Mensaje: {{message}}
+error_stack = Pila: {{stack}}
+error_file = Archivo: {{file}}
+error_line = LÃnea: {{line}}
+rendering_error = Ha ocurrido un error al renderizar la página.
+page_scale_width = Ancho de página
+page_scale_fit = Ajuste de página
+page_scale_auto = Aumento automático
+page_scale_actual = Tamaño actual
+loading_error_indicator = Error
+loading_error = Ha ocurrido un error al cargar el PDF.
+invalid_file_error = Archivo PDF inválido o corrupto.
+missing_file_error=Falta el archivo PDF.
+
+text_annotation_type.alt=[{{type}} Anotación]
+password_label=Ingrese la contraseña para abrir este archivo PDF.
+password_invalid=Contraseña inválida. Por favor, vuelva a intentarlo.
+password_ok=Aceptar
+password_cancel=Cancelar
+
+printing_not_supported = Advertencia: Imprimir no está soportado completamente por este navegador.
+printing_not_ready=Advertencia: El PDF no está completamente cargado para ser impreso.
+web_fonts_disabled=Las fuentes web están desactivadas: imposible usar las fuentes PDF embebidas.
+document_colors_disabled=Los documentos PDF no tienen permitido usar sus propios colores: 'Permitir a las páginas elegir sus propios colores' está desactivado en el navegador.
diff --git a/static/pdf.js/locale/es-ES/viewer.properties b/static/pdf.js/locale/es-ES/viewer.properties
new file mode 100644
index 000000000..e0db6b00d
--- /dev/null
+++ b/static/pdf.js/locale/es-ES/viewer.properties
@@ -0,0 +1,109 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+previous.title = Página anterior
+previous_label = Anterior
+next.title = Página siguiente
+next_label = Siguiente
+page_label = Página:
+page_of = de {{pageCount}}
+zoom_out.title = Reducir
+zoom_out_label = Reducir
+zoom_in.title = Aumentar
+zoom_in_label = Aumentar
+zoom.title = Tamaño
+presentation_mode.title = Cambiar al modo presentación
+presentation_mode_label = Modo presentación
+open_file.title = Abrir archivo
+open_file_label = Abrir
+print.title = Imprimir
+print_label = Imprimir
+download.title = Descargar
+download_label = Descargar
+bookmark.title = Vista actual (copiar o abrir en una nueva ventana)
+bookmark_label = Vista actual
+tools.title = Herramientas
+tools_label = Herramientas
+first_page.title = Ir a la primera página
+first_page.label = Ir a la primera página
+first_page_label = Ir a la primera página
+last_page.title = Ir a la última página
+last_page.label = Ir a la última página
+last_page_label = Ir a la última página
+page_rotate_cw.title = Rotar en sentido horario
+page_rotate_cw.label = Rotar en sentido horario
+page_rotate_cw_label = Rotar en sentido horario
+page_rotate_ccw.title = Rotar en sentido antihorario
+page_rotate_ccw.label = Rotar en sentido antihorario
+page_rotate_ccw_label = Rotar en sentido antihorario
+hand_tool_enable.title = Activar herramienta mano
+hand_tool_enable_label = Activar herramienta mano
+hand_tool_disable.title = Desactivar herramienta mano
+hand_tool_disable_label = Desactivar herramienta mano
+document_properties.title = Propiedades del documento…
+document_properties_label = Propiedades del documento…
+document_properties_file_name = Nombre de archivo:
+document_properties_file_size = Tamaño de archivo:
+document_properties_kb = {{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb = {{size_mb}} MB ({{size_b}} bytes)
+document_properties_title = TÃtulo:
+document_properties_author = Autor:
+document_properties_subject = Asunto:
+document_properties_keywords = Palabras clave:
+document_properties_creation_date = Fecha de creación:
+document_properties_modification_date = Fecha de modificación:
+document_properties_date_string = {{date}}, {{time}}
+document_properties_creator = Creador:
+document_properties_producer = Productor PDF:
+document_properties_version = Versión PDF:
+document_properties_page_count = Número de páginas:
+document_properties_close = Cerrar
+toggle_sidebar.title = Cambiar barra lateral
+toggle_sidebar_label = Cambiar barra lateral
+outline.title = Mostrar el esquema del documento
+outline_label = Esquema del documento
+attachments.title = Mostrar adjuntos
+attachments_label = Adjuntos
+thumbs.title = Mostrar miniaturas
+thumbs_label = Miniaturas
+findbar.title = Buscar en el documento
+findbar_label = Buscar
+thumb_page_title = Página {{page}}
+thumb_page_canvas = Miniatura de la página {{page}}
+find_label = Buscar:
+find_previous.title = Encontrar la anterior aparición de la frase
+find_previous_label = Anterior
+find_next.title = Encontrar la siguiente aparición de esta frase
+find_next_label = Siguiente
+find_highlight = Resaltar todos
+find_match_case_label = Coincidencia de mayús./minús.
+find_reached_top = Se alcanzó el inicio del documento, se continúa desde el final
+find_reached_bottom = Se alcanzó el final del documento, se continúa desde el inicio
+find_not_found = Frase no encontrada
+error_more_info = Más información
+error_less_info = Menos información
+error_close = Cerrar
+error_version_info = PDF.js v{{version}} (build: {{build}})
+error_message = Mensaje: {{message}}
+error_stack = Pila: {{stack}}
+error_file = Archivo: {{file}}
+error_line = LÃnea: {{line}}
+rendering_error = Ocurrió un error al renderizar la página.
+page_scale_width = Anchura de la página
+page_scale_fit = Ajuste de la página
+page_scale_auto = Tamaño automático
+page_scale_actual = Tamaño actual
+loading_error_indicator = Error
+loading_error = Ocurrió un error al cargar el PDF.
+invalid_file_error = Fichero PDF no válido o corrupto.
+missing_file_error = No hay fichero PDF.
+text_annotation_type.alt = [Anotación {{type}}]
+password_label = Introduzca la contraseña para abrir este archivo PDF.
+password_invalid = Contraseña no válida. Vuelva a intentarlo.
+password_ok = Aceptar
+password_cancel = Cancelar
+printing_not_supported = Advertencia: Imprimir no está totalmente soportado por este navegador.
+printing_not_ready = Advertencia: Este PDF no se ha cargado completamente para poder imprimirse.
+web_fonts_disabled = Las tipografÃas web están desactivadas: es imposible usar las tipografÃas PDF embebidas.
+document_colors_disabled = Los documentos PDF no tienen permitido usar sus propios colores: 'Permitir a las páginas elegir sus propios colores' está desactivado en el navegador.
diff --git a/static/pdf.js/locale/es-MX/viewer.properties b/static/pdf.js/locale/es-MX/viewer.properties
new file mode 100644
index 000000000..962d22dba
--- /dev/null
+++ b/static/pdf.js/locale/es-MX/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Página anterior
+previous_label=Anterior
+next.title=Página siguiente
+next_label=Siguiente
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Página:
+page_of=de {{pageCount}}
+
+zoom_out.title=Reducir
+zoom_out_label=Reducir
+zoom_in.title=Aumentar
+zoom_in_label=Aumentar
+zoom.title=Zoom
+presentation_mode.title=Cambiar al modo presentación
+presentation_mode_label=Modo presentación
+open_file.title=Abrir archivo
+open_file_label=Abrir
+print.title=Imprimir
+print_label=Imprimir
+download.title=Descargar
+download_label=Descargar
+bookmark.title=Vista actual (copia o abierta en ventana nueva)
+bookmark_label=Vista actual
+
+# Secondary toolbar and context menu
+tools.title=Herramientas
+tools_label=Herramientas
+first_page.title=Ir a la primera página
+first_page.label=Ir a la primera página
+first_page_label=Ir a la primera página
+last_page.title=Ir a la última página
+last_page.label=Ir a la última página
+last_page_label=Ir a la última página
+page_rotate_cw.title=Girar a la derecha
+page_rotate_cw.label=Girar a la derecha
+page_rotate_cw_label=Girar a la derecha
+page_rotate_ccw.title=Girar a la izquierda
+page_rotate_ccw.label=Girar a la izquierda
+page_rotate_ccw_label=Girar a la izquierda
+
+hand_tool_enable.title=Activar herramienta mano
+hand_tool_enable_label=Activar herramienta mano
+hand_tool_disable.title=Desactivar herramienta mano
+hand_tool_disable_label=Desactivar herramienta mano
+
+# Document properties dialog box
+document_properties.title=Propiedades del documento…
+document_properties_label=Propiedades del documento…
+document_properties_file_name=Nombre del archivo:
+document_properties_file_size=Tamaño del archivo:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=TÃtulo:
+document_properties_author=Autor:
+document_properties_subject=Asunto:
+document_properties_keywords=Palabras claves:
+document_properties_creation_date=Fecha de creación:
+document_properties_modification_date=Fecha de modificación:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creador:
+document_properties_producer=Productor PDF:
+document_properties_version=Versión PDF:
+document_properties_page_count=Número de páginas:
+document_properties_close=Cerrar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Cambiar barra lateral
+toggle_sidebar_label=Cambiar barra lateral
+outline.title=Mostrar esquema del documento
+outline_label=Esquema del documento
+attachments.title=Mostrar adjuntos
+attachments_label=Adjuntos
+thumbs.title=Mostrar miniaturas
+thumbs_label=Miniaturas
+findbar.title=Buscar en el documento
+findbar_label=Buscar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Página {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura de la página {{page}}
+
+# Find panel button title and messages
+find_label=Encontrar:
+find_previous.title=Ir a la anterior frase encontrada
+find_previous_label=Anterior
+find_next.title=Ir a la siguiente frase encontrada
+find_next_label=Siguiente
+find_highlight=Resaltar todo
+find_match_case_label=Coincidir con mayúsculas y minúsculas
+find_reached_top=Se alcanzó el inicio del documento, se buscará al final
+find_reached_bottom=Se alcanzó el final del documento, se buscará al inicio
+find_not_found=No se encontró la frase
+
+# Error panel labels
+error_more_info=Más información
+error_less_info=Menos información
+error_close=Cerrar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mensaje: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Archivo: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=LÃnea: {{line}}
+rendering_error=Un error ocurrió al renderizar la página.
+
+# Predefined zoom values
+page_scale_width=Ancho de página
+page_scale_fit=Ajustar página
+page_scale_auto=Zoom automático
+page_scale_actual=Tamaño real
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=Un error ocurrió al cargar el PDF.
+invalid_file_error=Archivo PDF invalido o dañado.
+missing_file_error=Archivo PDF no encontrado.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} anotación]
+password_label=Ingresa la contraseña para abrir este archivo PDF.
+password_invalid=Contraseña inválida. Por favor intenta de nuevo.
+password_ok=Aceptar
+password_cancel=Cancelar
+
+printing_not_supported=Advertencia: La impresión no esta completamente soportada por este navegador.
+printing_not_ready=Advertencia: El PDF no cargo completamente para impresión.
+web_fonts_disabled=Las fuentes web están desactivadas: es imposible usar las fuentes PDF embebidas.
+document_colors_disabled=Los documentos PDF no tienen permiso de usar sus propios colores: 'Permitir que las páginas elijan sus propios colores' esta desactivada en el navegador.
diff --git a/static/pdf.js/locale/et/viewer.properties b/static/pdf.js/locale/et/viewer.properties
new file mode 100644
index 000000000..89a4a92a5
--- /dev/null
+++ b/static/pdf.js/locale/et/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Eelmine lehekülg
+previous_label=Eelmine
+next.title=Järgmine lehekülg
+next_label=Järgmine
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Lehekülg:
+page_of=(kokku {{pageCount}})
+
+zoom_out.title=Vähenda
+zoom_out_label=Vähenda
+zoom_in.title=Suurenda
+zoom_in_label=Suurenda
+zoom.title=Suurendamine
+presentation_mode.title=Lülitu esitlusrežiimi
+presentation_mode_label=Esitlusrežiim
+open_file.title=Ava fail
+open_file_label=Ava
+print.title=Prindi
+print_label=Prindi
+download.title=Laadi alla
+download_label=Laadi alla
+bookmark.title=Praegune vaade (kopeeri või ava uues aknas)
+bookmark_label=Praegune vaade
+
+# Secondary toolbar and context menu
+tools.title=Tööriistad
+tools_label=Tööriistad
+first_page.title=Mine esimesele leheküljele
+first_page.label=Mine esimesele leheküljele
+first_page_label=Mine esimesele leheküljele
+last_page.title=Mine viimasele leheküljele
+last_page.label=Mine viimasele leheküljele
+last_page_label=Mine viimasele leheküljele
+page_rotate_cw.title=Pööra päripäeva
+page_rotate_cw.label=Pööra päripäeva
+page_rotate_cw_label=Pööra päripäeva
+page_rotate_ccw.title=Pööra vastupäeva
+page_rotate_ccw.label=Pööra vastupäeva
+page_rotate_ccw_label=Pööra vastupäeva
+
+hand_tool_enable.title=Luba sirvimine
+hand_tool_enable_label=Luba sirvimine
+hand_tool_disable.title=Keela sirvimine
+hand_tool_disable_label=Keela sirvimine
+
+# Document properties dialog box
+document_properties.title=Dokumendi omadused…
+document_properties_label=Dokumendi omadused…
+document_properties_file_name=Faili nimi:
+document_properties_file_size=Faili suurus:
+document_properties_kb={{size_kb}} KiB ({{size_b}} baiti)
+document_properties_mb={{size_mb}} MiB ({{size_b}} baiti)
+document_properties_title=Pealkiri:
+document_properties_author=Autor:
+document_properties_subject=Teema:
+document_properties_keywords=Märksõnad:
+document_properties_creation_date=Loodud:
+document_properties_modification_date=Muudetud:
+document_properties_date_string={{date}} {{time}}
+document_properties_creator=Looja:
+document_properties_producer=Generaator:
+document_properties_version=Generaatori versioon:
+document_properties_page_count=Lehekülgi:
+document_properties_close=Sulge
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Näita külgriba
+toggle_sidebar_label=Näita külgriba
+outline.title=Näita sisukorda
+outline_label=Näita sisukorda
+attachments.title=Näita manuseid
+attachments_label=Manused
+thumbs.title=Näita pisipilte
+thumbs_label=Pisipildid
+findbar.title=Otsi dokumendist
+findbar_label=Otsi
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title={{page}}. lehekülg
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}}. lehekülje pisipilt
+
+# Find panel button title and messages
+find_label=Otsi:
+find_previous.title=Otsi fraasi eelmine esinemiskoht
+find_previous_label=Eelmine
+find_next.title=Otsi fraasi järgmine esinemiskoht
+find_next_label=Järgmine
+find_highlight=Too kõik esile
+find_match_case_label=Tõstutundlik
+find_reached_top=Jõuti dokumendi algusesse, jätkati lõpust
+find_reached_bottom=Jõuti dokumendi lõppu, jätkati algusest
+find_not_found=Fraasi ei leitud
+
+# Error panel labels
+error_more_info=Rohkem teavet
+error_less_info=Vähem teavet
+error_close=Sulge
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Teade: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fail: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rida: {{line}}
+rendering_error=Lehe renderdamisel esines viga.
+
+# Predefined zoom values
+page_scale_width=Mahuta laiusele
+page_scale_fit=Mahuta leheküljele
+page_scale_auto=Automaatne suurendamine
+page_scale_actual=Tegelik suurus
+
+# Loading indicator messages
+loading_error_indicator=Viga
+loading_error=PDFi laadimisel esines viga.
+invalid_file_error=Vigane või rikutud PDF-fail.
+missing_file_error=PDF-fail puudub.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=PDF-faili avamiseks sisesta parool.
+password_invalid=Vigane parool. Palun proovi uuesti.
+password_ok=Sobib
+password_cancel=Loobu
+
+printing_not_supported=Hoiatus: printimine pole selle brauseri poolt täielikult toetatud.
+printing_not_ready=Hoiatus: PDF pole printimiseks täielikult laaditud.
+web_fonts_disabled=Veebifondid on keelatud: PDFiga kaasatud fonte pole võimalik kasutada.
+document_colors_disabled=PDF-dokumentidel pole oma värvide kasutamine lubatud: \'Veebilehtedel on lubatud kasutada oma värve\' on brauseris deaktiveeritud.
diff --git a/static/pdf.js/locale/eu/viewer.properties b/static/pdf.js/locale/eu/viewer.properties
new file mode 100644
index 000000000..0829055e7
--- /dev/null
+++ b/static/pdf.js/locale/eu/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Aurreko orria
+previous_label=Aurrekoa
+next.title=Hurrengo orria
+next_label=Hurrengoa
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Orria:
+page_of=/ {{pageCount}}
+
+zoom_out.title=Urrundu zooma
+zoom_out_label=Urrundu zooma
+zoom_in.title=Gerturatu zooma
+zoom_in_label=Gerturatu zooma
+zoom.title=Zooma
+presentation_mode.title=Aldatu aurkezpen modura
+presentation_mode_label=Arkezpen modua
+open_file.title=Ireki fitxategia
+open_file_label=Ireki
+print.title=Inprimatu
+print_label=Inprimatu
+download.title=Deskargatu
+download_label=Deskargatu
+bookmark.title=Uneko ikuspegia (kopiatu edo ireki leiho berrian)
+bookmark_label=Uneko ikuspegia
+
+# Secondary toolbar and context menu
+tools.title=Tresnak
+tools_label=Tresnak
+first_page.title=Joan lehen orrira
+first_page.label=Joan lehen orrira
+first_page_label=Joan lehen orrira
+last_page.title=Joan azken orrira
+last_page.label=Joan azken orrira
+last_page_label=Joan azken orrira
+page_rotate_cw.title=Biratu erlojuaren norantzan
+page_rotate_cw.label=Biratu erlojuaren norantzan
+page_rotate_cw_label=Biratu erlojuaren norantzan
+page_rotate_ccw.title=Biratu erlojuaren aurkako norantzan
+page_rotate_ccw.label=Biratu erlojuaren aurkako norantzan
+page_rotate_ccw_label=Biratu erlojuaren aurkako norantzan
+
+hand_tool_enable.title=Gaitu eskuaren tresna
+hand_tool_enable_label=Gaitu eskuaren tresna
+hand_tool_disable.title=Desgaitu eskuaren tresna
+hand_tool_disable_label=Desgaitu eskuaren tresna
+
+# Document properties dialog box
+document_properties.title=Dokumentuaren propietateak…
+document_properties_label=Dokumentuaren propietateak…
+document_properties_file_name=Fitxategi-izena:
+document_properties_file_size=Fitxategiaren tamaina:
+document_properties_kb={{size_kb}} KB ({{size_b}} byte)
+document_properties_mb={{size_mb}} MB ({{size_b}} byte)
+document_properties_title=Izenburua:
+document_properties_author=Egilea:
+document_properties_subject=Gaia:
+document_properties_keywords=Gako-hitzak:
+document_properties_creation_date=Sortze-data:
+document_properties_modification_date=Aldatze-data:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Sortzailea:
+document_properties_producer=PDFaren ekoizlea:
+document_properties_version=PDF bertsioa:
+document_properties_page_count=Orrialde kopurua:
+document_properties_close=Itxi
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Txandakatu alboko barra
+toggle_sidebar_label=Txandakatu alboko barra
+outline.title=Erakutsi dokumentuaren eskema
+outline_label=Dokumentuaren eskema
+attachments.title=Erakutsi eranskinak
+attachments_label=Eranskinak
+thumbs.title=Erakutsi koadro txikiak
+thumbs_label=Koadro txikiak
+findbar.title=Bilatu dokumentuan
+findbar_label=Bilatu
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title={{page}}. orria
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}}. orriaren koadro txikia
+
+# Find panel button title and messages
+find_label=Bilatu:
+find_previous.title=Bilatu esaldiaren aurreko parekatzea
+find_previous_label=Aurrekoa
+find_next.title=Bilatu esaldiaren hurrengo parekatzea
+find_next_label=Hurrengoa
+find_highlight=Nabarmendu guztia
+find_match_case_label=Bat etorri maiuskulekin/minuskulekin
+find_reached_top=Dokumentuaren hasierara heldu da, bukaeratik jarraitzen
+find_reached_bottom=Dokumentuaren bukaerara heldu da, hasieratik jarraitzen
+find_not_found=Esaldia ez da aurkitu
+
+# Error panel labels
+error_more_info=Informazio gehiago
+error_less_info=Informazio gutxiago
+error_close=Itxi
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (eraikuntza: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mezua: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fitxategia: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Lerroa: {{line}}
+rendering_error=Errorea gertatu da orria errendatzean.
+
+# Predefined zoom values
+page_scale_width=Orriaren zabalera
+page_scale_fit=Doitu orrira
+page_scale_auto=Zoom automatikoa
+page_scale_actual=Benetako tamaina
+
+# Loading indicator messages
+loading_error_indicator=Errorea
+loading_error=Errorea gertatu da PDFa kargatzean.
+invalid_file_error=PDF fitxategi baliogabe edo hondatua.
+missing_file_error=PDF fitxategia falta da.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} ohartarazpena]
+password_label=Idatzi PDF fitxategi hau irekitzeko pasahitza.
+password_invalid=Pasahitz baliogabea. Saiatu berriro mesedez.
+password_ok=Ados
+password_cancel=Utzi
+
+printing_not_supported=Abisua: inprimatzeko euskarria ez da erabatekoa nabigatzaile honetan.
+printing_not_ready=Abisua: PDFa ez dago erabat kargatuta inprimatzeko.
+web_fonts_disabled=Webeko letra-tipoak desgaituta daude: ezin dira kapsulatutako PDF letra-tipoak erabili.
+document_colors_disabled=PDF dokumentuek ez dute beraien koloreak erabiltzeko baimenik: 'Baimendu orriak beraien letra-tipoak aukeratzea' desaktibatuta dago nabigatzailean.
diff --git a/static/pdf.js/locale/fa/viewer.properties b/static/pdf.js/locale/fa/viewer.properties
index 8586490bd..062f2c2d9 100644
--- a/static/pdf.js/locale/fa/viewer.properties
+++ b/static/pdf.js/locale/fa/viewer.properties
@@ -1,4 +1,4 @@
-# Copyright 2013 Mozilla Foundation
+# Copyright 2012 Mozilla Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,9 +14,7 @@
# Main toolbar buttons (tooltips and alt text for images)
previous.title=صÙØÙ‡Ù” قبلی
-previous_label=قبلی
next.title=صÙØÙ‡Ù” بعدی
-next_label=بعدی
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
@@ -30,63 +28,39 @@ zoom_out_label=کوچک‌نمایی
zoom_in.title=بزرگ‌نمایی
zoom_in_label=بزرگ‌نمایی
zoom.title=زوم
-presentation_mode.title=تغییر وضع به Øالت نمایش
-presentation_mode_label=Øالت نمایش
-open_file.title=بازکردن پرونده
-open_file_label=بازکردن پرونده
+presentation_mode.title=تغییر به Øالت ارائه
+presentation_mode_label=Øالت ارائه
+open_file.title=باز کردن پرونده
+open_file_label=باز کردن
print.title=چاپ
print_label=چاپ
download.title=بارگیری
download_label=بارگیری
-bookmark.title=دید Ùعلی (رونوشت یا بازکردن در پنجرهٔ جدید)
-bookmark_label=دید Ùعلی
+bookmark.title=نمای Ùعلی (Ú©Ù¾ÛŒ کن، یا در پنجرۀ دیگری نشان بده)
+bookmark_label=نمای Ùعلی
# Secondary toolbar and context menu
-tools.title=ابزارها
-tools_label=ابزارها
-first_page.title=رÙتن به صÙØÙ‡Ù” اول
-first_page.label=رÙتن به صÙØÙ‡Ù” اول
-first_page_label=رÙتن به صÙØÙ‡Ù” اول
-last_page.title=رÙتن به صÙØÙ‡Ù” آخر
-last_page.label=رÙتن به صÙØÙ‡Ù” آخر
-last_page_label=رÙتن به صÙØÙ‡Ù” آخر
-page_rotate_cw.title=چرخش در جهت عقربه‌های ساعت
-page_rotate_cw.label=چرخش در جهت عقربه‌های ساعت
-page_rotate_cw_label=چرخش در جهت عقربه‌های ساعت
-page_rotate_ccw.title=چرخش در خلا٠جهت عقربه‌های ساعت
-page_rotate_ccw.label=چرخش در خلا٠جهت عقربه‌های ساعت
-page_rotate_ccw_label=چرخش در خلا٠جهت عقربه‌های ساعت
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=تغییر وضع نوار کناری
-toggle_sidebar_label=تغییر وضع نوار کناری
-outline.title=نمایش رئوس مطالب سند
-outline_label=رئوس مطالب سند
-thumbs.title=نمایش بندانگشتی‌ها
-thumbs_label=بندانگشتی‌ها
-findbar.title=یاÙتن در سند
-findbar_label=پیداکردن
+outline.title=نمایش Ø·Ø±Ø Ù†ÙˆØ´ØªØ§Ø±
+outline_label=Ø·Ø±Ø Ù†ÙˆØ´ØªØ§Ø±
+thumbs.title=نمایش تصاویر بندانگشتی
+thumbs_label=تصاویر بندانگشتی
+findbar_label=پیدا کردن
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
# number.
-thumb_page_title=صÙØÙ‡Ù” {{page}}
+thumb_page_title=صÙØÙ‡ {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=بندانگشتی صÙØÙ‡Ù” {{page}}
+thumb_page_canvas=تصویر بند‌ انگشتی صÙØÙ‡ {{page}}
# Find panel button title and messages
-find_label=پیداکردن:
-find_previous.title=یاÙتن رویداد قبلی عبارت
-find_previous_label=قبلی
-find_next.title=یاÙتن رویداد بعدی عبارت
-find_next_label=بعدی
-find_highlight=پررنگ‌کردن همه
-find_match_case_label=تطبیق بزرگی/Ú©ÙˆÚ†Ú©ÛŒ ØروÙ
-find_reached_top=به بالای سند رسید، ادامه‌یاÙته از زیر
-find_reached_bottom=به انتهای سند رسید، ادامه‌یاÙته از بالا
+find_previous.title=پیدا کردن رخداد قبلی عبارت
+find_next.title=پیدا کردن رخداد بعدی عبارت
find_not_found=عبارت پیدا نشد
# Error panel labels
@@ -95,40 +69,34 @@ error_less_info=اطلاعات کمتر
error_close=بستن
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=پی‌دی‌اÙ.جی‌اس نسخهٔ {{version}} (ساخت: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=پیغام: {{message}}
+error_message=پیام: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
-error_stack=پشته: {{stack}}
+error_stack=توده: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=پرونده: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=خط: {{line}}
-rendering_error=خطایی هنگام رندرکردن صÙØÙ‡ روی داد.
+error_line=سطر: {{line}}
+rendering_error=هنگام بارگیری صÙØÙ‡ خطایی رخ داد.
# Predefined zoom values
-page_scale_width=اندازهٔ صÙØÙ‡
-page_scale_fit=متناسب صÙØÙ‡
-page_scale_auto=زوم خودکار
-page_scale_actual=اندازهٔ Øقیقی
+page_scale_width=عرض صÙØÙ‡
+page_scale_fit=اندازه کردن صÙØÙ‡
+page_scale_auto=بزرگنمایی خودکار
+page_scale_actual=اندازه واقعی‌
# Loading indicator messages
loading_error_indicator=خطا
-loading_error=خطایی هنگامی بارگیری پی‌دی‌ا٠روی داد.
-invalid_file_error=پروندهٔ پی‌دی‌ا٠نامعتیر یا خراب شده.
-missing_file_error=پروندهٔ پی‌دی‌ا٠مÙقودشده.
+loading_error=هنگام بارگیری پرونده (PDF) خطایی رخ داد.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[گزارمان {{type}}]
-request_password=پی‌دی‌ا٠توسط یک گذرواژه Ù…ØاÙظت شده‌است:
-invalid_password=گذرواژهٔ نامعتبر.
+text_annotation_type.alt=[{{type}} Annotation]
+password_ok=تأیید
+password_cancel=انصراÙ
-printing_not_supported=اخطار: چاپ توسط این مرورگر به‌صورت کامل پشتبانی نشده‌است.
-printing_not_ready=اخطار: پی‌دی‌ا٠برای چاپ به‌طور کامل بار نشده‌است.
-web_fonts_disabled=قلم‌های وبی غیر Ùعال هستند: از قلم‌های توکار پی‌دی‌ا٠نتوانست استÙاده شود.
-document_colors_disabled=اسناد پی‌دی‌ا٠اجازه ندارند Ú©Ù‡ رنگ‌های خودشان را استÙاده کنند: «اجازهٔ انتخاب صÙØه‌ها برای انتخاب رنگ‌های خود» در مرورگر غیرÙعال شده‌است.
+printing_not_supported=هشدار: قابلیت چاپ به‌طور کامل در این مرورگر پشتیبانی نمی‌شود.
diff --git a/static/pdf.js/locale/ff/viewer.properties b/static/pdf.js/locale/ff/viewer.properties
new file mode 100644
index 000000000..9720c3eef
--- /dev/null
+++ b/static/pdf.js/locale/ff/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Hello Æennungo
+previous_label=ÆennuÉ—o
+next.title=Hello faango
+next_label=Yeeso
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Hello:
+page_of=e nder {{pageCount}}
+
+zoom_out.title=Lonngo WoÉ—É—a
+zoom_out_label=Lonngo WoÉ—É—a
+zoom_in.title=Lonngo Ara
+zoom_in_label=Lonngo Ara
+zoom.title=Lonngo
+presentation_mode.title=Faytu to Presentation Mode
+presentation_mode_label=Presentation Mode
+open_file.title=Uddit Fiilde
+open_file_label=Uddit
+print.title=Winndito
+print_label=Winndito
+download.title=Aawto
+download_label=Aawto
+bookmark.title=Jiytol gonangol (natto walla uddit e henorde)
+bookmark_label=Jiytol Gonangol
+
+# Secondary toolbar and context menu
+tools.title=KuutorÉ—e
+tools_label=KuutorÉ—e
+first_page.title=Yah to hello adanngo
+first_page.label=Yah to hello adanngo
+first_page_label=Yah to hello adanngo
+last_page.title=Yah to hello wattindiingo
+last_page.label=Yah to hello wattindiingo
+last_page_label=Yah to hello wattindiingo
+page_rotate_cw.title=Yiiltu Faya Ñaamo
+page_rotate_cw.label=Yiiltu Faya Ñaamo
+page_rotate_cw_label=Yiiltu Faya Ñaamo
+page_rotate_ccw.title=Yiiltu Faya Nano
+page_rotate_ccw.label=Yiiltu Faya Nano
+page_rotate_ccw_label=Yiiltu Faya Nano
+
+hand_tool_enable.title=Hurmin kuutorgal junngo
+hand_tool_enable_label=Hurmin kuutorgal junngo
+hand_tool_disable.title=DaaÆ´ kuutorgal junngo
+hand_tool_disable_label=DaaÆ´ kuutorgal junngo
+
+# Document properties dialog box
+document_properties.title=Keeroraaɗi Winndannde…
+document_properties_label=Keeroraaɗi Winndannde…
+document_properties_file_name=Innde fiilde:
+document_properties_file_size=Æetol fiilde:
+document_properties_kb={{size_kb}} KB ({{size_b}} bite)
+document_properties_mb={{size_mb}} MB ({{size_b}} bite)
+document_properties_title=Tiitoonde:
+document_properties_author=BinnduÉ—o:
+document_properties_subject=Toɓɓere:
+document_properties_keywords=Kelmekele jiytirÉ—e:
+document_properties_creation_date=Ñalnde Sosaa:
+document_properties_modification_date=Ñalnde Waylaa:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=CosÉ—o:
+document_properties_producer=PaggiiÉ—o PDF:
+document_properties_version=Yamre PDF:
+document_properties_page_count=Limoore Kelle:
+document_properties_close=Uddu
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Toggilo Palal Sawndo
+toggle_sidebar_label=Toggilo Palal Sawndo
+outline.title=Hollu Toɓɓe Fiilannde
+outline_label=Toɓɓe Fiilannde
+attachments.title=Hollu ÆŠisanÉ—e
+attachments_label=ÆŠisanÉ—e
+thumbs.title=Hollu Dooɓe
+thumbs_label=Dooɓe
+findbar.title=Yiylo e fiilannde
+findbar_label=Yiytu
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Hello {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Dooɓre Hello {{page}}
+
+# Find panel button title and messages
+find_label=Yiytu:
+find_previous.title=Yiylo cilol É“ennugol konngol ngol
+find_previous_label=ÆennuÉ—o
+find_next.title=Yiylo cilol garowol konngol ngol
+find_next_label=Yeeso
+find_highlight=Jalbin fof
+find_match_case_label=Jaaɓnu darnde
+find_reached_top=Heɓii fuɗɗorde fiilannde, jokku faya les
+find_reached_bottom=Heɓii hoore fiilannde, jokku faya les
+find_not_found=Konngi njiyataa
+
+# Error panel labels
+error_more_info=Æeydu Humpito
+error_less_info=Ustu Humpito
+error_close=Uddu
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Æatakuure: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fiilde: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Gorol: {{line}}
+rendering_error=Juumre waɗii tuma nde yoŋkittoo hello.
+
+# Predefined zoom values
+page_scale_width=Njaajeendi Hello
+page_scale_fit=KeÆ´eendi Hello
+page_scale_auto=Loongorde Jaajol
+page_scale_actual=Æetol Jaati
+
+# Loading indicator messages
+loading_error_indicator=Juumre
+loading_error=Juumre waÉ—ii tuma nde loowata PDF oo.
+invalid_file_error=Fiilde PDF moÆ´Æ´aani walla jiibii.
+missing_file_error=Fiilde PDF ena Å‹akki.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Siiftannde]
+password_label=Naatu finnde ngam uddite ndee fiilde PDF.
+password_invalid=Finnde moÆ´Æ´aani. TiiÉ—no eto kadi.
+password_ok=OK
+password_cancel=Haaytu
+
+printing_not_supported=Reentino: Winnditagol tammbitaaka no feewi e ndee wanngorde.
+printing_not_ready=Reentino: PDF oo loowaaki haa timmi ngam winnditagol.
+web_fonts_disabled=Ponte geese ko daaÆ´aaÉ—e: horiima huutoraade ponte PDF coomtoraaÉ—e.
+document_colors_disabled=PiilanÉ—e PDF njamiraaka yoo kuutoro goobuuji mum'en keeriiÉ—i: 'Yamir kello yoo kuutoro goobuuki keeriiÉ—i' koko daaÆ´aa e wanngorde ndee.
diff --git a/static/pdf.js/locale/fi/viewer.properties b/static/pdf.js/locale/fi/viewer.properties
index 560c948eb..78327d107 100644
--- a/static/pdf.js/locale/fi/viewer.properties
+++ b/static/pdf.js/locale/fi/viewer.properties
@@ -1,4 +1,4 @@
-# Copyright 2012 Mozilla Foundation
+# Copyright 2012 Mozilla Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -25,12 +25,12 @@ next_label=Seuraava
page_label=Sivu:
page_of=/ {{pageCount}}
-zoom_out.title=Suurenna
-zoom_out_label=Suurenna
-zoom_in.title=Pienennä
-zoom_in_label=Pienennä
-zoom.title=Sivun suurennus
-presentation_mode.title=Esitystila
+zoom_out.title=Loitonna
+zoom_out_label=Loitonna
+zoom_in.title=Lähennä
+zoom_in_label=Lähennä
+zoom.title=Suurennus
+presentation_mode.title=Siirry esitystilaan
presentation_mode_label=Esitystila
open_file.title=Avaa tiedosto
open_file_label=Avaa
@@ -38,33 +38,62 @@ print.title=Tulosta
print_label=Tulosta
download.title=Lataa
download_label=Lataa
-bookmark.title=Nykyinen näkymä (kopioi tai avaa uuteen ikkunaan)
-bookmark_label=Nykyinen näkymä
+bookmark.title=Avoin ikkuna (kopioi tai avaa uuteen ikkunaan)
+bookmark_label=Avoin ikkuna
# Secondary toolbar and context menu
-first_page.title=Ensimmäinen sivu
-first_page.label=Ensimmäinen sivu
-first_page_label=Ensimmäinen sivu
-last_page.title=Viimeinen sivu
-last_page.label=Viimeinen sivu
-last_page_label=Viimeinen sivu
-page_rotate_cw.title=Kierrä myötäpäivään
-page_rotate_cw.label=Kierrä myötäpäivään
-page_rotate_cw_label=Kierrä myötäpäivään
-page_rotate_ccw.title=Kierrä vastapäivään
-page_rotate_ccw.label=Kierrä vastapäivään
-page_rotate_ccw_label=Kierrä vastapäivään
+tools.title=Tools
+tools_label=Tools
+first_page.title=Siirry ensimmäiselle sivulle
+first_page.label=Siirry ensimmäiselle sivulle
+first_page_label=Siirry ensimmäiselle sivulle
+last_page.title=Siirry viimeiselle sivulle
+last_page.label=Siirry viimeiselle sivulle
+last_page_label=Siirry viimeiselle sivulle
+page_rotate_cw.title=Kierrä oikealle
+page_rotate_cw.label=Kierrä oikealle
+page_rotate_cw_label=Kierrä oikealle
+page_rotate_ccw.title=Kierrä vasemmalle
+page_rotate_ccw.label=Kierrä vasemmalle
+page_rotate_ccw_label=Kierrä vasemmalle
+
+hand_tool_enable.title=Käytä käsityökalua
+hand_tool_enable_label=Käytä käsityökalua
+hand_tool_disable.title=Poista käsityökalu käytöstä
+hand_tool_disable_label=Poista käsityökalu käytöstä
+
+# Document properties dialog box
+document_properties.title=Dokumentin ominaisuudet…
+document_properties_label=Dokumentin ominaisuudet…
+document_properties_file_name=Tiedostonimi:
+document_properties_file_size=Tiedoston koko:
+document_properties_kb={{size_kb}} kt ({{size_b}} tavua)
+document_properties_mb={{size_mb}} Mt ({{size_b}} tavua)
+document_properties_title=Otsikko:
+document_properties_author=Tekijä:
+document_properties_subject=Aihe:
+document_properties_keywords=Avainsanat:
+document_properties_creation_date=Luomispäivämäärä:
+document_properties_modification_date=Muokkauspäivämäärä:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Luoja:
+document_properties_producer=PDF-tuottaja:
+document_properties_version=PDF-versio:
+document_properties_page_count=Sivujen määrä:
+document_properties_close=Sulje
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Vaihda sivunäkymä
-toggle_sidebar_label=Vaihda sivunäkymä
-outline.title=Näytä asiakirjan jäsennys
-outline_label=Asiakirjan jäsennys
-thumbs.title=Näytä esikatselukuvat
-thumbs_label=Esikatselukuvat
-findbar.title=Etsi asiakirjasta
+toggle_sidebar.title=Näytä/piilota sivupaneeli
+toggle_sidebar_label=Näytä/piilota sivupaneeli
+outline.title=Näytä dokumentin rakenne
+outline_label=Dokumentin rakenne
+attachments.title=Näytä liitteet
+attachments_label=Liitteet
+thumbs.title=Näytä pienoiskuvat
+thumbs_label=Pienoiskuvat
+findbar.title=Etsi dokumentista
findbar_label=Etsi
# Thumbnails panel item (tooltip and alt text for images)
@@ -73,57 +102,62 @@ findbar_label=Etsi
thumb_page_title=Sivu {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=Sivun {{page}} esikatselukuva
+thumb_page_canvas=Pienoiskuva sivusta {{page}}
# Find panel button title and messages
-find_label=Etsi
-find_previous.title=Etsi edellinen
+find_label=Etsi:
+find_previous.title=Etsi hakusanan edellinen osuma
find_previous_label=Edellinen
-find_next.title=Etsi seuraava
+find_next.title=Etsi hakusanan seuraava osuma
find_next_label=Seuraava
-find_highlight=Korosta kaikki hakutulokset
-find_match_case_label=Hae täysin samanlaisia
-find_reached_top=Asiakirjan alku saavutettiin, jatkettiin lopusta
-find_reached_bottom=Asiakirjan loppu saavutettiin, jatkettiin alusta
-find_not_found=Ei löytynyt
+find_highlight=Korosta kaikki
+find_match_case_label=Huomioi kirjainkoko
+find_reached_top=Päästiin dokumentin alkuun, jatketaan lopusta
+find_reached_bottom=Päästiin dokumentin loppuun, continued from top
+find_not_found=Hakusanaa ei löytynyt
# Error panel labels
-error_more_info=Enemmän tietoa
-error_less_info=Vähemmän tietoa
+error_more_info=Lisätietoja
+error_less_info=Lisätietoja
error_close=Sulje
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (rakennus: {{build}})
+error_version_info=PDF.js v{{version}} (kooste: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=Viesti: {{message}}
+error_message=Virheilmoitus: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
-error_stack=Kutsupino: {{stack}}
+error_stack=Pino: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Tiedosto: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Rivi: {{line}}
-rendering_error=Virhe on tapahtunut sivua mallintaessa.
+rendering_error=Tapahtui virhe piirrettäessä sivua.
# Predefined zoom values
page_scale_width=Sivun leveys
-page_scale_fit=Sivun sovitus
-page_scale_auto=Automaatinen sivun suurennus
+page_scale_fit=Koko sivu
+page_scale_auto=Automaattinen suurennus
page_scale_actual=Todellinen koko
# Loading indicator messages
loading_error_indicator=Virhe
-loading_error=Virhe on tapahtunut PDF:ää ladattaessa.
-invalid_file_error=Virheellinen tai vioittunut PDF tiedosto.
-missing_file_error=PDF tiedostoa ei löytynyt.
+loading_error=Tapahtui virhe ladattaessa PDF-tiedostoa.
+invalid_file_error=Virheellinen tai vioittunut PDF-tiedosto.
+missing_file_error=Puuttuva PDF-tiedosto.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[{{type}} Selite]
-request_password=PDF on salasanasuojattu:
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=Kirjoita PDF-tiedoston salasana.
+password_invalid=Virheellinen salasana. Yritä uudestaan.
+password_ok=OK
+password_cancel=Peruuta
-printing_not_supported=Varoitus: Tämä selain ei täysin tue tulostusta.
-web_fonts_disabled=Web fontit ovat poissa käytöstä: upotettuja PDF fontteja ei voida käyttää.
+printing_not_supported=Varoitus: Selain ei tue kaikkia tulostustapoja.
+printing_not_ready=Varoitus: PDF-tiedosto ei ole vielä latautunut kokonaan, eikä sitä voi vielä tulostaa.
+web_fonts_disabled=Verkkosivujen omat kirjasinlajit on estetty: ei voida käyttää upotettuja PDF-kirjasinlajeja.
+document_colors_disabled=PDF-dokumenttien ei ole sallittua käyttää omia värejään: Asetusta "Sivut saavat käyttää omia värejään oletusten sijaan" ei ole valittu selaimen asetuksissa.
diff --git a/static/pdf.js/locale/fr/viewer.properties b/static/pdf.js/locale/fr/viewer.properties
index bbfc6162f..41d1860cf 100644
--- a/static/pdf.js/locale/fr/viewer.properties
+++ b/static/pdf.js/locale/fr/viewer.properties
@@ -32,8 +32,8 @@ zoom_in_label=Zoom avant
zoom.title=Zoom
presentation_mode.title=Basculer en mode présentation
presentation_mode_label=Mode présentation
-open_file.title=Ouvrir un fichier
-open_file_label=Ouvrir
+open_file.title=Ouvrir le fichier
+open_file_label=Ouvrir le fichier
print.title=Imprimer
print_label=Imprimer
download.title=Télécharger
@@ -42,6 +42,8 @@ bookmark.title=Affichage courant (copier ou ouvrir dans une nouvelle fenêtre)
bookmark_label=Affichage actuel
# Secondary toolbar and context menu
+tools.title=Outils
+tools_label=Outils
first_page.title=Aller à la première page
first_page.label=Aller à la première page
first_page_label=Aller à la première page
@@ -62,6 +64,8 @@ toggle_sidebar.title=Afficher/Masquer le panneau latéral
toggle_sidebar_label=Afficher/Masquer le panneau latéral
outline.title=Afficher les signets
outline_label=Signets du document
+attachments.title=Afficher les pièces jointes
+attachments_label=Pièces jointes
thumbs.title=Afficher les vignettes
thumbs_label=Vignettes
findbar.title=Rechercher dans le document
@@ -75,6 +79,31 @@ thumb_page_title=Page {{page}}
# number.
thumb_page_canvas=Vignette de la page {{page}}
+hand_tool_enable.title=Activer l'outil main
+hand_tool_enable_label=Activer l'outil main
+hand_tool_disable.title=Désactiver l'outil main
+hand_tool_disable_label=Désactiver l'outil main
+
+# Document properties dialog box
+document_properties.title=Propriétés du document…
+document_properties_label=Propriétés du document…
+document_properties_file_name=Nom du fichier :
+document_properties_file_size=Taille du fichier :
+document_properties_kb={{size_kb}}Â Ko ({{size_b}} octets)
+document_properties_mb={{size_mb}}Â Mo ({{size_b}} octets)
+document_properties_title=Titre :
+document_properties_author=Auteur :
+document_properties_subject=Sujet :
+document_properties_keywords=Mots-clés :
+document_properties_creation_date=Date de création :
+document_properties_modification_date=Modifié le :
+document_properties_date_string={{date}} Ã {{time}}
+document_properties_creator=Créé par :
+document_properties_producer=Outil de conversion PDFÂ :
+document_properties_version=Version PDFÂ :
+document_properties_page_count=Nombre de pages :
+document_properties_close=Fermer
+
# Find panel button title and messages
find_label=Rechercher :
find_previous.title=Trouver l'occurrence précédente de la phrase
@@ -118,13 +147,17 @@ loading_error=Une erreur s'est produite lors du chargement du fichier PDF.
invalid_file_error=Fichier PDF invalide ou corrompu.
missing_file_error=Fichier PDF manquant.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
text_annotation_type.alt=[Annotation {{type}}]
-request_password=Le PDF est protégé par un mot de passe :
+password_label=Veuillez saisir le mot de passe pour ouvrir ce fichier PDF.
+password_invalid=Mot de passe incorrect. Veuillez réessayer.
+password_ok=OK
+password_cancel=Annuler
printing_not_supported=Attention : l'impression n'est pas totalement prise en charge par ce navigateur.
printing_not_ready=Attention : le PDF n'est pas entièrement chargé pour pouvoir l'imprimer.
web_fonts_disabled=Les polices web sont désactivées : impossible d'utiliser les polices intégrées au PDF.
+document_colors_disabled=Les documents PDF ne peuvent pas utiliser leurs propres couleurs : « Autoriser les pages web à utiliser leurs propres couleurs » est désactivé dans le navigateur.
diff --git a/static/pdf.js/locale/fy-NL/viewer.properties b/static/pdf.js/locale/fy-NL/viewer.properties
new file mode 100644
index 000000000..69c8d0bc1
--- /dev/null
+++ b/static/pdf.js/locale/fy-NL/viewer.properties
@@ -0,0 +1,169 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Foarige side
+previous_label=Foarige
+next.title=Folgjende side
+next_label=Folgjende
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=side:
+page_of=fan {{pageCount}}
+
+zoom_out.title=Utzoome
+zoom_out_label=Utzoome
+zoom_in.title=Ynzoome
+zoom_in_label=Ynzoome
+zoom.title=Zoome
+print.title=Ofdrukke
+print_label=Ofdrukke
+presentation_mode.title=Wikselje nei presintaasjemoadus
+presentation_mode_label=Presintaasjemoadus
+open_file.title=Bestân iepenje
+open_file_label=Iepenje
+download.title=Ynlade
+download_label=Ynlade
+bookmark.title=Aktuele finster (kopiearje of iepenje yn nij finster)
+bookmark_label=Aktuele finster
+
+# Secondary toolbar and context menu
+tools.title=Ark
+tools_label=Ark
+first_page.title=Gean nei earste side
+first_page.label=Gean nei earste side
+first_page_label=Gean nei earste side
+last_page.title=Gean nei lêste side
+last_page.label=Gean nei lêste side
+last_page_label=Gean nei lêste v
+page_rotate_cw.title=Rjochtsom draaie
+page_rotate_cw.label=Rjochtsom draaie
+page_rotate_cw_label=Rjochtsom draaie
+page_rotate_ccw.title=Linksom draaie
+page_rotate_ccw.label=Linksom draaie
+page_rotate_ccw_label=Linksom draaie
+
+hand_tool_enable.title=Hânark ynskeakelje
+hand_tool_enable_label=Hânark ynskeakelje
+hand_tool_disable.title=Hânark úyskeakelje
+hand_tool_disable_label=Hânark úyskeakelje
+
+# Document properties dialog box
+document_properties.title=Dokuminteigenskippen…
+document_properties_label=Dokuminteigenskippen…
+document_properties_file_name=Bestânsnamme:
+document_properties_file_size=Bestânsgrutte:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Titel:
+document_properties_author=Auteur:
+document_properties_subject=Underwerp:
+document_properties_keywords=Kaaiwurden:
+document_properties_creation_date=Oanmaakdatum:
+document_properties_modification_date=Bewurkingsdatum:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Makker:
+document_properties_producer=PDF-makker:
+document_properties_version=PDF-ferzje:
+document_properties_page_count=Siden:
+document_properties_close=Slute
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Sidebalke yn-/útskeakelje
+toggle_sidebar_label=Sidebalke yn-/útskeakelje
+outline.title=Dokumint ynhâldsopjefte toane
+outline_label=Dokumint ynhâldsopjefte
+attachments.title=Bylagen toane
+attachments_label=Bylagen
+thumbs.title=Foarbylden toane
+thumbs_label=Foarbylden
+findbar.title=Sykje yn dokumint
+findbar_label=Sykje
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Side {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Foarbyld fan side {{page}}
+
+# Context menu
+first_page.label=Nei earste side gean
+last_page.label=Nei lêste side gean
+page_rotate_cw.label=Rjochtsom draaie
+page_rotate_ccw.label=Linksom draaie
+
+# Find panel button title and messages
+find_label=Sykje:
+find_previous.title=It foarige foarkommen fan de tekst sykje
+find_previous_label=Foarige
+find_next.title=It folgjende foarkommen fan de tekst sykje
+find_next_label=Folgjende
+find_highlight=Alles markearje
+find_match_case_label=Haadlettergefoelich
+find_reached_top=Boppekant fan dokumint berikt, trochgien fanôf ûnderkant
+find_reached_bottom=Ein fan dokumint berikt, trochgien fanôf boppekant
+find_not_found=Tekst net fûn
+
+# Error panel labels
+error_more_info=Mear ynformaasje
+error_less_info=Minder ynformaasje
+error_close=Slute
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Berjocht: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Bestân: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rigel: {{line}}
+rendering_error=Der is in flater bard by it renderjen fan de side.
+
+# Predefined zoom values
+page_scale_width=Sidebreedte
+page_scale_fit=Hiele side
+page_scale_auto=Automatysk zoome
+page_scale_actual=Wurklike grutte
+
+# Loading indicator messages
+loading_error_indicator=Flater
+loading_error=Der is in flater bard by it laden fan de PDF.
+invalid_file_error=Ynfalide of korruptearre PDF-bestân.
+missing_file_error=PDF-bestân ûntbrekt.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=Jou it wachtwurd om dit PDF-bestân te iepenjen.
+password_invalid=Ferkeard wachtwurd. Probearje opnij.
+password_ok=OK
+password_cancel=Annulearje
+
+printing_not_supported=Warning: Printing is net folslein stipe troch dizze browser.
+printing_not_ready=Warning: PDF is net folslein laden om ôf te drukken.
+web_fonts_disabled=Weblettertypen binne útskeakele: gebrûk fan ynsluten PDF-lettertypen is net mooglik.
+document_colors_disabled=PDF-dokuminten binne net tastien om har eigen kleuren te brûken: ‘Siden tastean har eigen kleuren te kiezen’ is útskeakele yn de browser.
diff --git a/static/pdf.js/locale/ga-IE/viewer.properties b/static/pdf.js/locale/ga-IE/viewer.properties
new file mode 100644
index 000000000..66c48760f
--- /dev/null
+++ b/static/pdf.js/locale/ga-IE/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=An Leathanach Roimhe Seo
+previous_label=Roimhe Seo
+next.title=An Chéad Leathanach Eile
+next_label=Ar Aghaidh
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Leathanach:
+page_of=as {{pageCount}}
+
+zoom_out.title=Súmáil Amach
+zoom_out_label=Súmáil Amach
+zoom_in.title=Súmáil Isteach
+zoom_in_label=Súmáil Isteach
+zoom.title=Súmáil
+presentation_mode.title=Úsáid an Mód Láithreoireachta
+presentation_mode_label=Mód Láithreoireachta
+open_file.title=Oscail Comhad
+open_file_label=Oscail
+print.title=Priontáil
+print_label=Priontáil
+download.title=Ãosluchtaigh
+download_label=Ãosluchtaigh
+bookmark.title=An t-amharc reatha (cóipeáil nó oscail i bhfuinneog nua)
+bookmark_label=An tAmharc Reatha
+
+# Secondary toolbar and context menu
+tools.title=UirlisÃ
+tools_label=UirlisÃ
+first_page.title=Go dtà an chéad leathanach
+first_page.label=Go dtà an chéad leathanach
+first_page_label=Go dtà an chéad leathanach
+last_page.title=Go dtà an leathanach deiridh
+last_page.label=Go dtà an leathanach deiridh
+last_page_label=Go dtà an leathanach deiridh
+page_rotate_cw.title=Rothlaigh ar deiseal
+page_rotate_cw.label=Rothlaigh ar deiseal
+page_rotate_cw_label=Rothlaigh ar deiseal
+page_rotate_ccw.title=Rothlaigh ar tuathal
+page_rotate_ccw.label=Rothlaigh ar tuathal
+page_rotate_ccw_label=Rothlaigh ar tuathal
+
+hand_tool_enable.title=Cumasaigh uirlis láimhe
+hand_tool_enable_label=Cumasaigh uirlis láimhe
+hand_tool_disable.title=DÃchumasaigh uirlis láimhe
+hand_tool_disable_label=DÃchumasaigh uirlis láimhe
+
+# Document properties dialog box
+document_properties.title=AirÃonna na Cáipéise…
+document_properties_label=AirÃonna na Cáipéise…
+document_properties_file_name=Ainm an chomhaid:
+document_properties_file_size=Méid an chomhaid:
+document_properties_kb={{size_kb}} kB ({{size_b}} beart)
+document_properties_mb={{size_mb}} MB ({{size_b}} beart)
+document_properties_title=Teideal:
+document_properties_author=Údar:
+document_properties_subject=Ãbhar:
+document_properties_keywords=Eochairfhocail:
+document_properties_creation_date=Dáta Cruthaithe:
+document_properties_modification_date=Dáta Athraithe:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Cruthaitheoir:
+document_properties_producer=Cruthaitheoir an PDF:
+document_properties_version=Leagan PDF:
+document_properties_page_count=LÃon Leathanach:
+document_properties_close=Dún
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Scoránaigh an Barra Taoibh
+toggle_sidebar_label=Scoránaigh an Barra Taoibh
+outline.title=Taispeáin Creatlach na Cáipéise
+outline_label=Creatlach na Cáipéise
+attachments.title=Taispeáin Iatáin
+attachments_label=Iatáin
+thumbs.title=Taispeáin Mionsamhlacha
+thumbs_label=Mionsamhlacha
+findbar.title=Aimsigh sa Cháipéis
+findbar_label=Aimsigh
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Leathanach {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Mionsamhail Leathanaigh {{page}}
+
+# Find panel button title and messages
+find_label=Aimsigh:
+find_previous.title=Aimsigh an sampla roimhe seo den nath seo
+find_previous_label=Roimhe seo
+find_next.title=Aimsigh an chéad sampla eile den nath sin
+find_next_label=Ar aghaidh
+find_highlight=Aibhsigh uile
+find_match_case_label=CásÃogair
+find_reached_top=Ag barr na cáipéise, ag leanúint ón mbun
+find_reached_bottom=Ag bun na cáipéise, ag leanúint ón mbarr
+find_not_found=AbairtÃn gan aimsiú
+
+# Error panel labels
+error_more_info=Tuilleadh Eolais
+error_less_info=NÃos Lú Eolais
+error_close=Dún
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Teachtaireacht: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Cruach: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Comhad: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=LÃne: {{line}}
+rendering_error=Tharla earráid agus an leathanach á leagan amach.
+
+# Predefined zoom values
+page_scale_width=Leithead Leathanaigh
+page_scale_fit=Laghdaigh go dtà an Leathanach
+page_scale_auto=Súmáil UathoibrÃoch
+page_scale_actual=FÃormhéid
+
+# Loading indicator messages
+loading_error_indicator=Earráid
+loading_error=Tharla earráid agus an cháipéis PDF á luchtú.
+invalid_file_error=Comhad neamhbhailà nó truaillithe PDF.
+missing_file_error=Comhad PDF ar iarraidh.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anótáil {{type}}]
+password_label=Cuir an focal faire isteach chun an comhad PDF seo a oscailt.
+password_invalid=Focal faire mÃcheart. Déan iarracht eile.
+password_ok=OK
+password_cancel=Cealaigh
+
+printing_not_supported=Rabhadh: Nà thacaÃonn an brabhsálaà le priontáil go hiomlán.
+printing_not_ready=Rabhadh: Nà féidir an PDF a phriontáil go dtà go mbeidh an cháipéis iomlán luchtaithe.
+web_fonts_disabled=Tá clófhoirne Gréasáin dÃchumasaithe: nà féidir clófhoirne leabaithe PDF a úsáid.
+document_colors_disabled=NÃl cead ag cáipéisà PDF a ndathanna féin a roghnú; tá 'Tabhair cead do leathanaigh a ndathanna féin a roghnú' dÃchumasaithe sa mbrabhsálaÃ.
diff --git a/static/pdf.js/locale/gd/viewer.properties b/static/pdf.js/locale/gd/viewer.properties
new file mode 100644
index 000000000..f535f0660
--- /dev/null
+++ b/static/pdf.js/locale/gd/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=An duilleag roimhe
+previous_label=Air ais
+next.title=An ath-dhuilleag
+next_label=Air adhart
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Duilleag:
+page_of=Ã {{pageCount}}
+
+zoom_out.title=Sùm a-mach
+zoom_out_label=Sùm a-mach
+zoom_in.title=Sùm a-steach
+zoom_in_label=Sùm a-steach
+zoom.title=Sùm
+presentation_mode.title=Gearr leum dhan mhodh taisbeanaidh
+presentation_mode_label=Am modh taisbeanaidh
+open_file.title=Fosgail faidhle
+open_file_label=Fosgail
+print.title=Clò-bhuail
+print_label=Clò-bhuail
+download.title=Luchdaich a-nuas
+download_label=Luchdaich a-nuas
+bookmark.title=An sealladh là ithreach (dèan lethbhreac no fosgail e ann an uinneag ùr)
+bookmark_label=An sealladh là ithreach
+
+# Secondary toolbar and context menu
+tools.title=Innealan
+tools_label=Innealan
+first_page.title=Rach gun chiad duilleag
+first_page.label=Rach gun chiad duilleag
+first_page_label=Rach gun chiad duilleag
+last_page.title=Rach gun duilleag mu dheireadh
+last_page.label=Rach gun duilleag mu dheireadh
+last_page_label=Rach gun duilleag mu dheireadh
+page_rotate_cw.title=Cuairtich gu deiseil
+page_rotate_cw.label=Cuairtich gu deiseil
+page_rotate_cw_label=Cuairtich gu deiseil
+page_rotate_ccw.title=Cuairtich gu tuathail
+page_rotate_ccw.label=Cuairtich gu tuathail
+page_rotate_ccw_label=Cuairtich gu tuathail
+
+hand_tool_enable.title=Cuir inneal na là imhe an comas
+hand_tool_enable_label=Cuir inneal na là imhe an comas
+hand_tool_disable.title=Cuir inneal na là imhe à comas
+hand_tool_disable_label=Cuir à comas inneal na là imhe
+
+# Document properties dialog box
+document_properties.title=Roghainnean na sgrìobhainne…
+document_properties_label=Roghainnean na sgrìobhainne…
+document_properties_file_name=Ainm an fhaidhle:
+document_properties_file_size=Meud an fhaidhle:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Tiotal:
+document_properties_author=Ùghdar:
+document_properties_subject=Cuspair:
+document_properties_keywords=Faclan-luirg:
+document_properties_creation_date=Latha a chruthachaidh:
+document_properties_modification_date=Latha atharrachaidh:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Cruthadair:
+document_properties_producer=Saothraiche a' PDF:
+document_properties_version=Tionndadh a' PDF:
+document_properties_page_count=Àireamh de dhuilleagan:
+document_properties_close=Dùin
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Toglaich am bà r-taoibh
+toggle_sidebar_label=Toglaich am bà r-taoibh
+outline.title=Seall an sgrìobhainn far loidhne
+outline_label=Oir-loidhne na sgrìobhainne
+attachments.title=Seall na ceanglachain
+attachments_label=Ceanglachain
+thumbs.title=Seall na dealbhagan
+thumbs_label=Dealbhagan
+findbar.title=Lorg san sgrìobhainn
+findbar_label=Lorg
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Duilleag a {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Dealbhag duilleag a {{page}}
+
+# Find panel button title and messages
+find_label=Lorg:
+find_previous.title=Lorg là thair roimhe na h-abairt seo
+find_previous_label=Air ais
+find_next.title=Lorg ath-là thair na h-abairt seo
+find_next_label=Air adhart
+find_highlight=Soillsich a h-uile
+find_match_case_label=Aire do litrichean mòra is beaga
+find_reached_top=RÃ inig sinn barr na duilleige, a' leantainn air adhart o bhonn na duilleige
+find_reached_bottom=RÃ inig sinn bonn na duilleige, a' leantainn air adhart o bharr na duilleige
+find_not_found=Cha deach an abairt a lorg
+
+# Error panel labels
+error_more_info=Barrachd fiosrachaidh
+error_less_info=Nas lugha de dh'fhiosrachadh
+error_close=Dùin
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Teachdaireachd: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stac: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Faidhle: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Loidhne: {{line}}
+rendering_error=Thachair mearachd rè reandaradh na duilleige.
+
+# Predefined zoom values
+page_scale_width=Leud na duilleige
+page_scale_fit=Freagair ri meud na duilleige
+page_scale_auto=Sùm fèin-obrachail
+page_scale_actual=Am fìor-mheud
+
+# Loading indicator messages
+loading_error_indicator=Mearachd
+loading_error=Thachair mearachd rè luchdadh a' PDF.
+invalid_file_error=Faidhle PDF a tha mì-dhligheach no coirbte.
+missing_file_error=Faidhle PDF a tha a dhìth.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Nòtachadh {{type}}]
+password_label=Cuir a-steach am facal-faire gus am faidhle PDF seo fhosgladh.
+password_invalid=Tha am facal-faire cearr. Nach fheuch thu ris a-rithist?
+password_ok=Ceart ma-tha
+password_cancel=Sguir dheth
+
+printing_not_supported=Rabhadh: Chan eil am brabhsair seo a' cur là n-taic ri clò-bhualadh.
+printing_not_ready=Rabhadh: Cha deach am PDF a luchdadh gu tur airson clò-bhualadh.
+web_fonts_disabled=Tha cruthan-clò lìn à comas: Chan urrainn dhuinn cruthan-clò PDF leabaichte a chleachdadh.
+document_colors_disabled=Chan fhaod sgrìobhainnean PDF na dathan aca fhèin a chleachdadh: Tha "Leig le duilleagan na dathan aca fhèin a chleachdadh" à comas sa bhrabhsair.
diff --git a/static/pdf.js/locale/gl/viewer.properties b/static/pdf.js/locale/gl/viewer.properties
new file mode 100644
index 000000000..08729fee6
--- /dev/null
+++ b/static/pdf.js/locale/gl/viewer.properties
@@ -0,0 +1,124 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Páxina anterior
+previous_label=Anterior
+next.title=Seguinte páxina
+next_label=Seguinte
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Páxina:
+page_of=de {{pageCount}}
+
+zoom_out.title=Reducir
+zoom_out_label=Reducir
+zoom_in.title=Ampliar
+zoom_in_label=Ampliar
+zoom.title=Zoom
+print.title=Imprimir
+print_label=Imprimir
+presentation_mode.title=Cambiar ao modo presentación
+presentation_mode_label=Modo presentación
+open_file.title=Abrir ficheiro
+open_file_label=Abrir
+download.title=Descargar
+download_label=Descargar
+bookmark.title=Vista actual (copiar ou abrir nunha nova xanela)
+bookmark_label=Vista actual
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Amosar/agochar a barra lateral
+toggle_sidebar_label=Amosar/agochar a barra lateral
+outline.title=Amosar esquema do documento
+outline_label=Esquema do documento
+thumbs.title=Amosar miniaturas
+thumbs_label=Miniaturas
+findbar.title=Atopar no documento
+findbar_label=Atopar
+
+# Document outline messages
+no_outline=Ningún esquema dispoñÃbel
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Páxina {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura da páxina {{page}}
+
+# Context menu
+first_page.label=Ir á primeira páxina
+last_page.label=Ir á última páxina
+page_rotate_cw.label=Rotar no sentido das agullas do reloxo
+page_rotate_ccw.label=Rotar no sentido contrario ás agullas do reloxo
+
+# Find panel button title and messages
+find_label=Atopar:
+find_previous.title=Atopar a anterior aparición da frase
+find_previous_label=Anterior
+find_next.title=Atopar a seguinte aparición da frase
+find_next_label=Seguinte
+find_highlight=Realzar todo
+find_match_case_label=Diferenciar maiúsculas de minúsculas
+find_reached_top=Chegouse ao inicio do documento, continuar desde o final
+find_reached_bottom=Chegouse ao final do documento, continuar desde o inicio
+find_not_found=Non se atopou a frase
+
+# Error panel labels
+error_more_info=Máis información
+error_less_info=Menos información
+error_close=Pechar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (Identificador da compilación: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mensaxe: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Ficheiro: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Liña: {{line}}
+rendering_error=Produciuse un erro ao representar a páxina.
+
+# Predefined zoom values
+page_scale_width=Largura da páxina
+page_scale_fit=Axuste de páxina
+page_scale_auto=Zoom automático
+page_scale_actual=Tamaño actual
+
+# Loading indicator messages
+loading_error_indicator=Erro
+loading_error=Produciuse un erro ao cargar o PDF.
+invalid_file_error=Ficheiro PDF danado ou incorrecto.
+missing_file_error=Falta o ficheiro PDF.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type=[Anotación {{type}}]
+request_password=O PDF está protexido por un contrasinal:
+
+printing_not_supported=Aviso: A impresión non é compatÃbel de todo con este navegador.
+web_fonts_disabled=Desactiváronse as fontes web: foi imposÃbel usar as fontes incrustadas no PDF.
diff --git a/static/pdf.js/locale/gu-IN/viewer.properties b/static/pdf.js/locale/gu-IN/viewer.properties
new file mode 100644
index 000000000..1e58d3fe3
--- /dev/null
+++ b/static/pdf.js/locale/gu-IN/viewer.properties
@@ -0,0 +1,149 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=પહેલાનૠપાનà«àª‚
+previous_label=પહેલાનà«
+next.title=આગળનૠપાનà«àª‚
+ next_label=આગળનà«àª‚
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=પાનà«àª‚:
+page_of={{pageCount}} નà«àª‚
+zoom_out.title=મોટૠકરો
+zoom_out_label=મોટૠકરો
+zoom_in.title=નાનà«àª‚ કરો
+zoom_in_label=નાનà«àª‚ કરો
+zoom.title=નાનà«àª‚ મોટૠકરો
+print.title=છાપો
+print_label=છારો
+open_file.title=ફાઇલ ખોલો
+open_file_label=ખોલો
+download.title=ડાઉનલોડ
+download_label=ડાઉનલોડ
+bookmark.title=વરà«àª¤àª®àª¾àª¨ દૃશà«àª¯ (નવી વિનà«àª¡à«‹àª®àª¾àª‚ નકલ કરો અથવા ખોલો)
+bookmark_label=વરà«àª¤àª®àª¾àª¨ દૃશà«àª¯
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+outline.title=દસà«àª¤àª¾àªµà«‡àªœ રૂપરેખા બતાવો
+outline_label=દસà«àª¤àª¾àªµà«‡àªœ રૂપરેખા
+thumbs.title=થંબનેલà«àª¸ બતાવો
+thumbs_label=થંબનેલà«àª¸
+
+# Document outline messages
+
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=પાનà«àª‚ {{page}}
+
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=પાનાં {{page}} નà«àª‚ થંબનેલà«àª¸
+# Error panel labels
+error_more_info=વધારે જાણકારી
+error_less_info=ઓછી જાણકારી
+error_close=બંધ કરો
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=સંદેશો: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=સà«àªŸà«‡àª•: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ફાઇલ: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=વાકà«àª¯: {{line}}
+rendering_error=àªà«‚લ ઉદà«àªàªµà«€ જà«àª¯àª¾àª°à«‡ પાનાંનૠરેનà«àª¡ કરી રહà«àª¯àª¾ હોય.
+# Predefined zoom values
+page_scale_width=પાનાની પહોળાઇ
+page_scale_fit=પાનà«àª‚ બંધબેસતà«
+page_scale_auto=આપમેળે નાનà«àª‚મોટૠકરો
+page_scale_actual=ચોકà«àª•àª¸ માપ
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+
+loading_error_indicator=àªà«‚લ
+loading_error=àªà«‚લ ઉદà«àªàªµà«€ જà«àª¯àª¾àª°à«‡ PDF ને લાવી રહà«àª¯àª¾ હોય.
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{[type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+
+printing_not_supported=ચેતવણી: છાપવાનà«àª‚ આ બà«àª°àª¾àª‰àªàª° દà«àª¦àª¾àª°àª¾ સંપૂરà«àª£àªªàª£à«‡ આધારàªà«‚ત નથી.
+
+error_version_info=PDF.js v{{version}} (build: {{build}})
+find_highlight=બધૠપà«àª°àª•àª¾àª¶àª¿àª¤ કરો
+find_label=શોધો:
+find_match_case_label=કેસ બંધબેસાડો
+find_next.title=શબà«àª¦àª¸àª®à«‚હની આગળની ઘટનાને શોધો
+find_next_label=આગળનà«àª‚
+find_not_found=શબà«àª¦àª¸àª®à«‚હ મળà«àª¯à« નથી
+find_previous.title=શબà«àª¦àª¸àª®à«‚હની પાછલી ઘટનાને શોધો
+find_previous_label=પહેલાંનà«
+find_reached_bottom=દસà«àª¤àª¾àªµà«‡àªœàª¨àª¾àª‚ અંતે પહોંચી ગયા, ઉપરથી ચાલૠકરેલ હતà«
+find_reached_top=દસà«àª¤àª¾àªµà«‡àªœàª¨àª¾àª‚ ટોચે પહોંચી ગયા, તળિયેથી ચાલૠકરેલ હતà«
+findbar.title=દસà«àª¤àª¾àªµà«‡àªœàª®àª¾àª‚ શોધો
+findbar_label=શોધો
+first_page.label=પહેલાં પાનામાં જાવ
+invalid_file_error=અયોગà«àª¯ અથવા àªàª¾àª‚ગેલ PDF ફાઇલ.
+last_page.label=છેલà«àª²àª¾ પાનામાં જાવ
+missing_file_error=ગà«àª® થયેલ PDF ફાઇલ.
+page_rotate_ccw.label=ઘડિયાળનાં કાંટાની ઉલટી દિશામાં ફેરવો
+page_rotate_cw.label=ઘડિયાળનાં કાંટાની જેમ ફેરવો
+presentation_mode.title=રજૂઆત સà«àª¥àª¿àª¤àª¿àª®àª¾àª‚ જાવ
+presentation_mode_label=રજૂઆત સà«àª¥àª¿àª¤àª¿
+printing_not_ready=Warning: PDF ઠછાપવા માટે સંપૂરà«àª£àªªàª£à«‡ લાવેલ છે.
+toggle_sidebar.title=ટૉગલ બાજà«àªªàªŸà«àªŸà«€
+toggle_sidebar_label=ટૉગલ બાજà«àªªàªŸà«àªŸà«€
+web_fonts_disabled=વેબ ફોનà«àªŸ નિષà«àª•à«àª°àª¿àª¯ થયેલ છે: àªàª®à«àª¬à«‡àª¡ થયેલ PDF ફોનà«àªŸàª¨à«‡ વાપરવાનà«àª‚ અસમરà«àª¥.
+document_colors_disabled=PDF દસà«àª¤àª¾àªµà«‡àªœà«‹ તેનાં પોતાના રંગોને વાપરવા પરવાનગી આપતા નથી: 'તેનાં પોતાનાં રંગોને પસંદ કરવા માટે પાનાંને પરવાનગી આપો' બà«àª°àª¾àª‰àªàª°àª®àª¾àª‚ નિષà«àª•à«àª°àª¿àª¯ થયેલ છે.
+text_annotation_type.alt=[{{type}} Annotation]
+
+attachments.title=જોડાણોને બતાવો
+attachments_label=જોડાણો
+document_properties_author=લેખક:
+document_properties_close=બંધ કરો
+document_properties_creation_date=નિરà«àª®àª¾àª£ તારીખ:
+document_properties_creator=નિરà«àª®àª¾àª¤àª¾:
+document_properties_date_string={{date}}, {{time}}
+document_properties_file_name=ફાઇલ નામ:
+document_properties_file_size=ફાઇલ માપ:
+document_properties_kb={{size_kb}} KB ({{size_b}} બાઇટ)
+document_properties_keywords=કિવરà«àª¡:
+document_properties_label=દસà«àª¤àª¾àªµà«‡àªœ ગà«àª£àª§àª°à«àª®à«‹â€¦
+document_properties_mb={{size_mb}} MB ({{size_b}} બાઇટ)
+document_properties_modification_date=ફેરફાર તારીખ:
+document_properties_page_count=પાનાં ગણતરી:
+document_properties_producer=PDF નિરà«àª®àª¾àª¤àª¾:
+document_properties_subject=વિષય:
+document_properties_title=શીરà«àª·àª•:
+first_page.title=પà«àª°àª¥àª® પાનાં પર જાવ
+first_page_label=પà«àª°àª¥àª® પાનાં પર જાવ
+hand_tool_disable.title=હાથનાં સાધનને નિષà«àª•à«àª°àª¿àª¯ કરો
+hand_tool_disable_label=હાથનાં સાધનને નિષà«àª•à«àª°àª¿àª¯ કરો
+hand_tool_enable.title=હાથનાં સાધનને સકà«àª°àª¿àª¯ કરો
+hand_tool_enable_label=હાથનાં સાધનને સકà«àª°àª¿àª¯ કરો
+last_page.title=છેલà«àª²àª¾ પાનાં પર જાવ
+last_page_label=છેલà«àª²àª¾ પાનાં પર જાવ
+page_rotate_ccw.title=ઘડિયાળનાં કાંટાની વિરà«àª¦à«àª¦ ફેરવો
+page_rotate_ccw_label=ઘડિયાળનાં કાંટાની વિરà«àª¦à«àª¦ ફેરવો
+page_rotate_cw.title=ઘડિયાળનાં કાંટા તરફ ફેરવો
+page_rotate_cw_label=ઘડિયાળનાં કાંટા તરફ ફેરવો
+password_cancel=રદ કરો
+password_invalid=અયોગà«àª¯ પાસવરà«àª¡. મહેરબાની કરીને ફરી પà«àª°àª¯àª¤à«àª¨ કરો.
+password_label=આ PDF ફાઇલને ખોલવા પાસવરà«àª¡àª¨à«‡ દાખલ કરો.
+password_ok=બરાબર
+tools.title=સાધનો
+tools_label=સાધનો
+
+document_properties_version=PDF આવૃતà«àª¤àª¿:
+document_properties.title=દસà«àª¤àª¾àªµà«‡àªœ ગà«àª£àª§àª°à«àª®à«‹â€¦
+
diff --git a/static/pdf.js/locale/he/viewer.properties b/static/pdf.js/locale/he/viewer.properties
index 38f280c0d..078d401ab 100644
--- a/static/pdf.js/locale/he/viewer.properties
+++ b/static/pdf.js/locale/he/viewer.properties
@@ -1,59 +1,150 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-bookmark.title=דף × ×•×›×—×™ (העתקה ×ו פתיחה בחלון חדש)
+# Main toolbar buttons (tooltips and alt text for images)
previous.title=דף קוד×
-next.title=דף הב×
-print.title=הדפסה
-download.title=הורדה
-zoom_out.title=התרחקות
-zoom_in.title=התקרבות
-error_more_info=יותר מידע
-error_less_info=פחות מידע
-error_close=סגירה
-error_build=×‘× ×™×™×ª PDF.JSâ€: {{build}}
-error_message=הודעה: {{message}}
-error_stack=×ž×—×¡× ×™×ª: {{stack}}
-error_file=קובץ: {{file}}
-error_line=שורה: {{line}}
-page_scale_width=רוחב דף
-page_scale_fit=גודל דף
-page_scale_auto=התקרבות ×וטומטית
-page_scale_actual=גודל ×מיתי
-toggle_slider.title=מתג החלקה
-thumbs.title=הצגת ×ª×ž×•× ×•×ª ממוזערות
-outline.title=הצגת מת×ר מסמך
-loading=×‘×˜×¢×™× ×”... {{percent}}%
-loading_error_indicator=שגי××”
-loading_error=×ירעה שגי××” בעת ×˜×¢×™× ×ª קובץ PDF.
-rendering_error=×ירעה שגי××” בעת עיבוד הדף.
-page_label=דף:
-page_of=מתוך {{pageCount}}
-open_file.title=פתיחת קובץ
-text_annotation_type.alt=[{{type}} Annotation]
-toggle_slider_label=מתג החלקה
-thumbs_label=×ª×ž×•× ×•×ª ממוזערות
-outline_label=מת×ר מסמך
-bookmark_label=תצוגה × ×•×›×—×™×ª
previous_label=קוד×
+next.title=דף הב×
next_label=הב×
-print_label=הדפסה
-download_label=הורדה
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=עמוד:
+page_of=מתוך {{pageCount}}
+
+zoom_out.title=התרחקות
zoom_out_label=התרחקות
+zoom_in.title=התקרבות
zoom_in_label=התקרבות
zoom.title=מרחק מתצוגה
-thumb_page_title=דף {{page}}
-thumb_page_canvas=×ª×ž×•× ×” ממוזערת של דף {{page}}
-request_password=קובץ PDF מוגן בססמה:
+presentation_mode.title=מעבר למצב מצגת
+presentation_mode_label=מצב מצגת
+open_file.title=פתיחת קובץ
open_file_label=פתיחה
+print.title=הדפסה
+print_label=הדפסה
+download.title=הורדה
+download_label=הורדה
+bookmark.title=תצוגה × ×•×›×—×™×ª (העתקה ×ו פתיחה בחלון חדש)
+bookmark_label=תצוגה × ×•×›×—×™×ª
+
+# Secondary toolbar and context menu
+tools.title=כלי×
+tools_label=כלי×
+first_page.title=מעבר לעמוד הר×שון
+first_page.label=מעבר לעמוד הר×שון
+first_page_label=מעבר לעמוד הר×שון
+last_page.title=מעבר לעמוד ×”×חרון
+last_page.label=מעבר לעמוד ×”×חרון
+last_page_label=מעבר לעמוד ×”×חרון
+page_rotate_cw.title=הטיה ×¢× ×›×™×•×•×Ÿ השעון
+page_rotate_cw.label=הטיה ×¢× ×›×™×•×•×Ÿ השעון
+page_rotate_cw_label=הטיה ×¢× ×›×™×•×•×Ÿ השעון
+page_rotate_ccw.title=הטיה ×›× ×’×“ כיוון השעון
+page_rotate_ccw.label=הטיה ×›× ×’×“ כיוון השעון
+page_rotate_ccw_label=הטיה ×›× ×’×“ כיוון השעון
+
+hand_tool_enable.title=הפעלת כלי היד
+hand_tool_enable_label=הפעלת כלי היד
+hand_tool_disable.title=× ×˜×¨×•×œ כלי היד
+hand_tool_disable_label=× ×˜×¨×•×œ כלי היד
+
+# Document properties dialog box
+document_properties.title=מ××¤×™×™× ×™ מסמך…
+document_properties_label=מ××¤×™×™× ×™ מסמך…
+document_properties_file_name=×©× ×§×•×‘×¥:
+document_properties_file_size=גודל הקובץ:
+document_properties_kb={{size_kb}} ק״ב ({{size_b}} בתי×)
+document_properties_mb={{size_mb}} מ״ב ({{size_b}} בתי×)
+document_properties_title=כותרת:
+document_properties_author=מחבר:
+document_properties_subject=× ×•×©×:
+document_properties_keywords=מילות מפתח:
+document_properties_creation_date=ת×ריך יצירה:
+document_properties_modification_date=ת×ריך ×©×™× ×•×™:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=יוצר:
+document_properties_producer=יצרן PDF:
+document_properties_version=גרסת PDF:
+document_properties_page_count=מספר דפי×:
+document_properties_close=סגירה
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=הצגה/הסתרה של סרגל הצד
+toggle_sidebar_label=הצגה/הסתרה של סרגל הצד
+outline.title=הצגת מת×ר מסמך
+outline_label=מת×ר מסמך
+thumbs.title=הצגת תצוגה מקדימה
+thumbs_label=תצוגה מקדימה
+findbar.title=חיפוש במסמך
+findbar_label=חיפוש
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=עמוד {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=תצוגה מקדימה של עמוד {{page}}
+
+# Find panel button title and messages
+find_label=חיפוש:
+find_previous.title=חיפוש מופע ×§×•×“× ×©×œ הביטוי
+find_previous_label=קוד×
+find_next.title=חיפוש המופע ×”×‘× ×©×œ הביטוי
+find_next_label=הב×
+find_highlight=הדגשת הכול
+find_match_case_label=הת×מת ×ותיות
+find_reached_top=×”×’×™×¢ לר×ש הדף, ממשיך מלמטה
+find_reached_bottom=הגיע לסוף הדף, ממשיך מלמעלה
+find_not_found=ביטוי ×œ× × ×ž×¦×
+
+# Error panel labels
+error_more_info=מידע × ×•×¡×£
+error_less_info=פחות מידע
+error_close=סגירה
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js גרסה {{version}} (×‘× ×™×™×”: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=הודעה: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=תוכן ×ž×—×¡× ×™×ª: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=קובץ: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=שורה: {{line}}
+rendering_error=×ירעה שגי××” בעת עיבוד הדף.
+
+# Predefined zoom values
+page_scale_width=רוחב העמוד
+page_scale_fit=הת×מה לעמוד
+page_scale_auto=מרחק מתצוגה ×וטומטי
+page_scale_actual=גודל ×מתי
+
+# Loading indicator messages
+loading_error_indicator=שגי××”
+loading_error=×ירעה שגי××” בעת ×˜×¢×™× ×ª ×”Ö¾PDF.
+invalid_file_error=קובץ PDF ×¤×’×•× ×ו ×œ× ×ª×§×™×Ÿ.
+missing_file_error=קובץ PDF חסר.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[הערת {{type}}]
+password_label=× × ×œ×”×›× ×™×¡ ×ת הססמה לפתיחת קובץ PDF ×–×”.
+password_invalid=ססמה שגויה. × × ×œ× ×¡×•×ª ×©× ×™×ª.
+password_ok=×ישור
+password_cancel=ביטול
+
+printing_not_supported=×זהרה: הדפסה ××™× ×” × ×ª×ž×›×ª במלו××” בדפדפן ×–×”.
+printing_not_ready=×זהרה: ×”Ö¾PDF ×œ× × ×™×ª×Ÿ לחלוטין עד מצב שמ×פשר הדפסה.
+web_fonts_disabled=×’×•×¤× ×™ רשת ×ž× ×•×˜×¨×œ×™×: ×œ× × ×™×ª×Ÿ להשתמש ×‘×’×•×¤× ×™ PDF מוטבעי×.
+document_colors_disabled=מסמכי PDF ×œ× ×™×›×•×œ×™× ×œ×”×©×ª×ž×© ×‘×¦×‘×¢×™× ×ž×©×œ×”×: ×”×פשרות \\'ל×פשר ×œ×¢×ž×•×“×™× ×œ×‘×—×•×¨ ×¦×‘×¢×™× ×ž×©×œ×”×\\' ××™× ×” פעילה בדפדפן.
\ No newline at end of file
diff --git a/static/pdf.js/locale/hi-IN/viewer.properties b/static/pdf.js/locale/hi-IN/viewer.properties
new file mode 100644
index 000000000..0c476c921
--- /dev/null
+++ b/static/pdf.js/locale/hi-IN/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=पिछला पृषà¥à¤
+previous_label=पिछला
+next.title=अगला पृषà¥à¤
+next_label=आगे
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=पृषà¥à¤ :
+page_of={{pageCount}} का
+
+zoom_out.title=छोटा करें
+zoom_out_label=छोटा करें
+zoom_in.title=बड़ा करें
+zoom_in_label=बड़ा करें
+zoom.title=बड़ा-छोटा करें
+presentation_mode.title=पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¤¿ अवसà¥à¤¥à¤¾ में जाà¤à¤
+presentation_mode_label=पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¤¿ अवसà¥à¤¥à¤¾
+open_file.title=फ़ाइल खोलें
+open_file_label=खोलें
+print.title=छापें
+print_label=छापें
+download.title=डाउनलोड
+download_label=डाउनलोड
+bookmark.title=मौजूदा दृशà¥à¤¯ (नठविंडो में नक़ल लें या खोलें)
+bookmark_label=मौजूदा दृशà¥à¤¯
+
+# Secondary toolbar and context menu
+tools.title=औज़ार
+tools_label=औज़ार
+first_page.title=पà¥à¤°à¤¥à¤® पृषà¥à¤ पर जाà¤à¤
+first_page.label=पà¥à¤°à¤¥à¤® पृषà¥à¤ पर जाà¤à¤
+first_page_label=पà¥à¤°à¤¥à¤® पृषà¥à¤ पर जाà¤à¤
+last_page.title=अंतिम पृषà¥à¤ पर जाà¤à¤
+last_page.label=अंतिम पृषà¥à¤ पर जाà¤à¤
+last_page_label=अंतिम पृषà¥à¤ पर जाà¤à¤
+page_rotate_cw.title=घड़ी की दिशा में घà¥à¤®à¤¾à¤à¤
+page_rotate_cw.label=घड़ी की दिशा में घà¥à¤®à¤¾à¤à¤
+page_rotate_cw_label=घड़ी की दिशा में घà¥à¤®à¤¾à¤à¤
+page_rotate_ccw.title=घड़ी की दिशा से उलà¥à¤Ÿà¤¾ घà¥à¤®à¤¾à¤à¤
+page_rotate_ccw.label=घड़ी की दिशा से उलà¥à¤Ÿà¤¾ घà¥à¤®à¤¾à¤à¤
+page_rotate_ccw_label=घड़ी की दिशा से उलà¥à¤Ÿà¤¾ घà¥à¤®à¤¾à¤à¤
+
+hand_tool_enable.title=हाथ औजार सकà¥à¤°à¤¿à¤¯ करें
+hand_tool_enable_label=हाथ औजार सकà¥à¤°à¤¿à¤¯ करें
+hand_tool_disable.title=हाथ औजार निषà¥à¤•à¥à¤°à¤¿à¤¯ करना
+hand_tool_disable_label=हाथ औजार निषà¥à¤•à¥à¤°à¤¿à¤¯ करना
+
+# Document properties dialog box
+document_properties.title=दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ विशेषता...
+document_properties_label=दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ विशेषता...
+document_properties_file_name=फ़ाइल नाम:
+document_properties_file_size=फाइल आकारः
+document_properties_kb={{size_kb}} KB ({{size_b}} बाइट)
+document_properties_mb={{size_mb}} MB ({{size_b}} बाइट)
+document_properties_title=शीरà¥à¤·à¤•:
+document_properties_author=लेखकः
+document_properties_subject=विषय:
+document_properties_keywords=कà¥à¤‚जी-शबà¥à¤¦:
+document_properties_creation_date=निरà¥à¤®à¤¾à¤£ दिनांक:
+document_properties_modification_date=संशोधन दिनांक:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=निरà¥à¤®à¤¾à¤¤à¤¾:
+document_properties_producer=PDF उतà¥à¤ªà¤¾à¤¦à¤•:
+document_properties_version=PDF संसà¥à¤•à¤°à¤£:
+document_properties_page_count=पृषà¥à¤ गिनती:
+document_properties_close=बंद करें
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=सà¥à¤²à¤¾à¤‡à¤¡à¤° टॉगल करें
+toggle_sidebar_label=सà¥à¤²à¤¾à¤‡à¤¡à¤° टॉगल करें
+outline.title=दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ आउटलाइन दिखाà¤à¤
+outline_label=दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ आउटलाइन
+attachments.title=संलगà¥à¤¨à¤• दिखायें
+attachments_label=संलगà¥à¤¨à¤•
+thumbs.title=लघà¥à¤›à¤µà¤¿à¤¯à¤¾à¤ दिखाà¤à¤
+thumbs_label=लघॠछवि
+findbar.title=दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ में ढूà¤à¤¢à¤¼à¥‡à¤‚
+findbar_label=ढूà¤à¤¢à¤¼à¥‡à¤‚
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=पृषà¥à¤ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=पृषà¥à¤ {{page}} की लघà¥-छवि
+
+# Find panel button title and messages
+find_label=ढूंढें:
+find_previous.title=वाकà¥à¤¯à¤¾à¤‚श की पिछली उपसà¥à¤¥à¤¿à¤¤à¤¿ ढूà¤à¤¢à¤¼à¥‡à¤‚
+find_previous_label=पिछला
+find_next.title=वाकà¥à¤¯à¤¾à¤‚श की अगली उपसà¥à¤¥à¤¿à¤¤à¤¿ ढूà¤à¤¢à¤¼à¥‡à¤‚
+find_next_label=आगे
+find_highlight=सà¤à¥€ आलोकित करें
+find_match_case_label=मिलान सà¥à¤¥à¤¿à¤¤à¤¿
+find_reached_top=पृषà¥à¤ के ऊपर पहà¥à¤‚च गया, नीचे से जारी रखें
+find_reached_bottom=पृषà¥à¤ के नीचे में जा पहà¥à¤à¤šà¤¾, ऊपर से जारी
+find_not_found=वाकà¥à¤¯à¤¾à¤‚श नहीं मिला
+
+# Error panel labels
+error_more_info=अधिक सूचना
+error_less_info=कम सूचना
+error_close=बंद करें
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=संदेश: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=सà¥à¤Ÿà¥ˆà¤•: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=फ़ाइल: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=पंकà¥à¤¤à¤¿: {{line}}
+rendering_error=पृषà¥à¤ रेंडरिंग के दौरान तà¥à¤°à¥à¤Ÿà¤¿ आई.
+
+# Predefined zoom values
+page_scale_width=पृषà¥à¤ चौड़ाई
+page_scale_fit=पृषà¥à¤ फिट
+page_scale_auto=सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ जूम
+page_scale_actual=वासà¥à¤¤à¤µà¤¿à¤• आकार
+
+# Loading indicator messages
+loading_error_indicator=तà¥à¤°à¥à¤Ÿà¤¿
+loading_error=पीडीà¤à¤« लोड करते समय à¤à¤• तà¥à¤°à¥à¤Ÿà¤¿ हà¥à¤ˆ.
+invalid_file_error=अमानà¥à¤¯ या à¤à¥à¤°à¤·à¥à¤Ÿ PDF फ़ाइल.
+missing_file_error=अनà¥à¤ªà¤¸à¥à¤¥à¤¿à¤¤ PDF फ़ाइल.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=इस पीडीà¤à¤« फ़ाइल को खोलने के लिठकृपया कूटशबà¥à¤¦ à¤à¤°à¥‡à¤‚.
+password_invalid=अवैध कूटशबà¥à¤¦, कृपया फिर कोशिश करें.
+password_ok=ठीक
+password_cancel=रदà¥à¤¦ करें
+
+printing_not_supported=चेतावनी: इस बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤° पर छपाई पूरी तरह से समरà¥à¤¥à¤¿à¤¤ नहीं है.
+printing_not_ready=चेतावनी: पीडीà¤à¤« छपाई के लिठपूरी तरह से लोड नहीं है.
+web_fonts_disabled=वेब फॉनà¥à¤Ÿà¥à¤¸ निषà¥à¤•à¥à¤°à¤¿à¤¯ हैं: अंतःसà¥à¤¥à¤¾à¤ªà¤¿à¤¤ PDF फॉनà¥à¤Ÿà¤¸ के उपयोग में असमरà¥à¤¥.
+document_colors_disabled=PDF दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤¼ उनके अपने रंग को उपयोग करने के लिठअनà¥à¤®à¤¤à¤¿ पà¥à¤°à¤¾à¤ªà¥à¤¤ नहीं है: 'पृषà¥à¤ ों को उनके अपने रंग को चà¥à¤¨à¤¨à¥‡ के लिठसà¥à¤µà¥€à¤•à¥ƒà¤¤à¤¿ दें कि वह उस बà¥à¤°à¤¾à¤‰à¤œà¤¼à¤° में निषà¥à¤•à¥à¤°à¤¿à¤¯ है.
diff --git a/static/pdf.js/locale/hr/viewer.properties b/static/pdf.js/locale/hr/viewer.properties
new file mode 100644
index 000000000..9c829b3eb
--- /dev/null
+++ b/static/pdf.js/locale/hr/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Prethodna stranica
+previous_label=Prethodna
+next.title=Iduća stranica
+next_label=Iduća
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Stranica:
+page_of=od {{pageCount}}
+
+zoom_out.title=Uvećaj
+zoom_out_label=Smanji
+zoom_in.title=Uvaćaj
+zoom_in_label=Smanji
+zoom.title=Uvećanje
+presentation_mode.title=Prebaci u prezentacijski naÄin rada
+presentation_mode_label=Prezentacijski naÄin rada
+open_file.title=Otvori datoteku
+open_file_label=Otvori
+print.title=Ispis
+print_label=Ispis
+download.title=Preuzmi
+download_label=Preuzmi
+bookmark.title=Trenutni prikaz (kopiraj ili otvori u novom prozoru)
+bookmark_label=Trenutni prikaz
+
+# Secondary toolbar and context menu
+tools.title=Alati
+tools_label=Alati
+first_page.title=Idi na prvu stranicu
+first_page.label=Idi na prvu stranicu
+first_page_label=Idi na prvu stranicu
+last_page.title=Idi na posljednju stranicu
+last_page.label=Idi na posljednju stranicu
+last_page_label=Idi na posljednju stranicu
+page_rotate_cw.title=Rotiraj u smjeru kazaljke na satu
+page_rotate_cw.label=Rotiraj u smjeru kazaljke na satu
+page_rotate_cw_label=Rotiraj u smjeru kazaljke na satu
+page_rotate_ccw.title=Rotiraj obrnutno od smjera kazaljke na satu
+page_rotate_ccw.label=Rotiraj obrnutno od smjera kazaljke na satu
+page_rotate_ccw_label=Rotiraj obrnutno od smjera kazaljke na satu
+
+hand_tool_enable.title=Omogući ruÄni alat
+hand_tool_enable_label=Omogući ruÄni alat
+hand_tool_disable.title=Onemogući ruÄni alat
+hand_tool_disable_label=Onemogući ruÄni alat
+
+# Document properties dialog box
+document_properties.title=Svojstva dokumenta...
+document_properties_label=Svojstva dokumenta...
+document_properties_file_name=Naziv datoteke:
+document_properties_file_size=VeliÄina datoteke:
+document_properties_kb={{size_kb}} KB ({{size_b}} bajtova)
+document_properties_mb={{size_mb}} MB ({{size_b}} bajtova)
+document_properties_title=Naslov:
+document_properties_author=Autor:
+document_properties_subject=Predmet:
+document_properties_keywords=KljuÄne rijeÄi:
+document_properties_creation_date=Datum stvaranja:
+document_properties_modification_date=Datum promjene:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Stvaralac:
+document_properties_producer=PDF stvaratelj:
+document_properties_version=PDF inaÄica:
+document_properties_page_count=Broj stranica:
+document_properties_close=Zatvori
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Prikaži/sakrij boÄnu traku
+toggle_sidebar_label=Prikaži/sakrij boÄnu traku
+outline.title=Prikaži obris dokumenta
+outline_label=Obris dokumenta
+attachments.title=Prikaži privitke
+attachments_label=Privitci
+thumbs.title=Prikaži sliÄice
+thumbs_label=SliÄice
+findbar.title=Traži u dokumentu
+findbar_label=Traži
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Stranica {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=SliÄica stranice {{page}}
+
+# Find panel button title and messages
+find_label=Traži:
+find_previous.title=Pronađi prethodno javljanje ovog izraza
+find_previous_label=Prethodno
+find_next.title=Pronađi iduće javljanje ovog izraza
+find_next_label=Iduće
+find_highlight=Istankni sve
+find_match_case_label=SluÄaj podudaranja
+find_reached_top=Dosegnut vrh dokumenta, nastavak od dna
+find_reached_bottom=Dosegnut vrh dokumenta, nastavak od vrha
+find_not_found=Izraz nije pronađen
+
+# Error panel labels
+error_more_info=Više informacija
+error_less_info=Manje informacija
+error_close=Zatvori
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Poruka: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stog: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Datoteka: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Redak: {{line}}
+rendering_error=Došlo je do greške prilikom iscrtavanja stranice.
+
+# Predefined zoom values
+page_scale_width=Å irina stranice
+page_scale_fit=Pristajanje stranici
+page_scale_auto=Automatsko uvećanje
+page_scale_actual=Prava veliÄina
+
+# Loading indicator messages
+loading_error_indicator=Greška
+loading_error=DoÅ¡lo je do greÅ¡ke pri uÄitavanju PDF-a.
+invalid_file_error=Kriva ili oštećena PDF datoteka.
+missing_file_error=Nedostaje PDF datoteka.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Bilješka]
+password_label=Upišite lozinku da biste otvorili ovu PDF datoteku.
+password_invalid=Neispravna lozinka. Pokušajte ponovo.
+password_ok=U redu
+password_cancel=Odustani
+
+printing_not_supported=Upozorenje: Ispisivanje nije potpuno podržano u ovom pregledniku.
+printing_not_ready=Upozorenje: PDF nije u potpunosti uÄitan za ispis.
+web_fonts_disabled=Web fontovi su onemogućeni: nije moguće koristiti umetnute PDF fontove.
+document_colors_disabled=PDF dokumenti nemaju dopuštene koristiti vlastite boje: opcija 'Dopusti stranicama da koriste vlastite boje' je deaktivirana.
diff --git a/static/pdf.js/locale/hu/viewer.properties b/static/pdf.js/locale/hu/viewer.properties
new file mode 100644
index 000000000..b7a6973a2
--- /dev/null
+++ b/static/pdf.js/locale/hu/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Előző oldal
+previous_label=Előző
+next.title=Következő oldal
+next_label=Tovább
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Oldal:
+page_of=összesen: {{pageCount}}
+
+zoom_out.title=KicsinyÃtés
+zoom_out_label=KicsinyÃtés
+zoom_in.title=NagyÃtás
+zoom_in_label=NagyÃtás
+zoom.title=NagyÃtás
+presentation_mode.title=Váltás bemutató módba
+presentation_mode_label=Bemutató mód
+open_file.title=Fájl megnyitása
+open_file_label=Megnyitás
+print.title=Nyomtatás
+print_label=Nyomtatás
+download.title=Letöltés
+download_label=Letöltés
+bookmark.title=Jelenlegi nézet (másolás vagy megnyitás új ablakban)
+bookmark_label=Aktuális nézet
+
+# Secondary toolbar and context menu
+tools.title=Eszközök
+tools_label=Eszközök
+first_page.title=Ugrás az első oldalra
+first_page.label=Ugrás az első oldalra
+first_page_label=Ugrás az első oldalra
+last_page.title=Ugrás az utolsó oldalra
+last_page.label=Ugrás az utolsó oldalra
+last_page_label=Ugrás az utolsó oldalra
+page_rotate_cw.title=Forgatás az óramutató járásával egyezően
+page_rotate_cw.label=Forgatás az óramutató járásával egyezően
+page_rotate_cw_label=Forgatás az óramutató járásával egyezően
+page_rotate_ccw.title=Forgatás az óramutató járásával ellentétesen
+page_rotate_ccw.label=Forgatás az óramutató járásával ellentétesen
+page_rotate_ccw_label=Forgatás az óramutató járásával ellentétesen
+
+hand_tool_enable.title=Kéz eszköz bekapcsolása
+hand_tool_enable_label=Kéz eszköz bekapcsolása
+hand_tool_disable.title=Kéz eszköz kikapcsolása
+hand_tool_disable_label=Kéz eszköz kikapcsolása
+
+# Document properties dialog box
+document_properties.title=Dokumentum tulajdonságai…
+document_properties_label=Dokumentum tulajdonságai…
+document_properties_file_name=Fájlnév:
+document_properties_file_size=Fájlméret:
+document_properties_kb={{size_kb}} KB ({{size_b}} bájt)
+document_properties_mb={{size_mb}} MB ({{size_b}} bájt)
+document_properties_title=CÃm:
+document_properties_author=Szerző:
+document_properties_subject=Tárgy:
+document_properties_keywords=Kulcsszavak:
+document_properties_creation_date=Létrehozás dátuma:
+document_properties_modification_date=MódosÃtás dátuma:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Létrehozta:
+document_properties_producer=PDF előállÃtó:
+document_properties_version=PDF verzió:
+document_properties_page_count=Oldalszám:
+document_properties_close=Bezárás
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Oldalsáv be/ki
+toggle_sidebar_label=Oldalsáv be/ki
+outline.title=Dokumentumvázlat megjelenÃtése
+outline_label=Dokumentumvázlat
+attachments.title=Mellékletek megjelenÃtése
+attachments_label=Van melléklet
+thumbs.title=Bélyegképek megjelenÃtése
+thumbs_label=Bélyegképek
+findbar.title=Keresés a dokumentumban
+findbar_label=Keresés
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title={{page}}. oldal
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}}. oldal bélyegképe
+
+# Find panel button title and messages
+find_label=Keresés:
+find_previous.title=A kifejezés előző előfordulásának keresése
+find_previous_label=Előző
+find_next.title=A kifejezés következő előfordulásának keresése
+find_next_label=Tovább
+find_highlight=Összes kiemelése
+find_match_case_label=Kis- és nagybetűk megkülönböztetése
+find_reached_top=A dokumentum eleje elérve, folytatás a végétől
+find_reached_bottom=A dokumentum vége elérve, folytatás az elejétől
+find_not_found=A kifejezés nem található
+
+# Error panel labels
+error_more_info=További információ
+error_less_info=Kevesebb információ
+error_close=Bezárás
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Ãœzenet: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Nyomkövetés: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fájl: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Sor: {{line}}
+rendering_error=Hiba történt az oldal feldolgozása közben.
+
+# Predefined zoom values
+page_scale_width=Oldalszélesség
+page_scale_fit=Teljes oldal
+page_scale_auto=Automatikus nagyÃtás
+page_scale_actual=Valódi méret
+
+# Loading indicator messages
+loading_error_indicator=Hiba
+loading_error=Hiba történt a PDF betöltésekor.
+invalid_file_error=Érvénytelen vagy sérült PDF fájl.
+missing_file_error=Hiányzó PDF fájl.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} megjegyzés]
+password_label=Adja meg a jelszót a PDF fájl megnyitásához.
+password_invalid=Helytelen jelszó. Próbálja újra.
+password_ok=OK
+password_cancel=Mégse
+
+printing_not_supported=Figyelmeztetés: Ez a böngésző nem teljesen támogatja a nyomtatást.
+printing_not_ready=Figyelmeztetés: A PDF nincs teljesen betöltve a nyomtatáshoz.
+web_fonts_disabled=Webes betűkészletek letiltva: nem használhatók a beágyazott PDF betűkészletek.
+document_colors_disabled=A PDF dokumentumok nem használhatják saját szÃneiket: „Az oldalak a saját maguk által kiválasztott szÃneket használhatják†beállÃtás ki van kapcsolva a böngészÅ‘ben.
diff --git a/static/pdf.js/locale/hy-AM/viewer.properties b/static/pdf.js/locale/hy-AM/viewer.properties
new file mode 100644
index 000000000..eda49756f
--- /dev/null
+++ b/static/pdf.js/locale/hy-AM/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Õ†Õ¡ÕÕ¸Ö€Õ¤ Õ§Õ»Õ¨
+previous_label=Õ†Õ¡ÕÕ¸Ö€Õ¤Õ¨
+next.title=Õ€Õ¡Õ»Õ¸Ö€Õ¤ Õ§Õ»Õ¨
+next_label=Õ€Õ¡Õ»Õ¸Ö€Õ¤Õ¨
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Ô·Õ».
+page_of={{pageCount}}-Õ«Ö
+
+zoom_out.title=Õ“Õ¸Ö„Ö€Õ¡ÖÕ¶Õ¥Õ¬
+zoom_out_label=Õ“Õ¸Ö„Ö€Õ¡ÖÕ¶Õ¥Õ¬
+zoom_in.title=Ô½Õ¸Õ·Õ¸Ö€Õ¡ÖÕ¶Õ¥Õ¬
+zoom_in_label=Ô½Õ¸Õ·Õ¸Ö€Õ¡ÖÕ¶Õ¥Õ¬
+zoom.title=Õ„Õ¡Õ½Õ·Õ¿Õ¡Õ¢Õ¨\u0020
+presentation_mode.title=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ†Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯Õ«Õ¶
+presentation_mode_label=Õ†Õ¥Ö€Õ¯Õ¡ÕµÕ¡ÖÕ´Õ¡Õ¶ Õ¥Õ²Õ¡Õ¶Õ¡Õ¯
+open_file.title=Ô²Õ¡ÖÕ¥Õ¬ Õ–Õ¡ÕµÕ¬
+open_file_label=Ô²Õ¡ÖÕ¥Õ¬
+print.title=ÕÕºÕ¥Õ¬
+print_label=ÕÕºÕ¥Õ¬
+download.title=Ô²Õ¥Õ¼Õ¶Õ¥Õ¬
+download_label=Ô²Õ¥Õ¼Õ¶Õ¥Õ¬
+bookmark.title=Ô¸Õ¶Õ©Õ¡ÖÕ«Õ¯ Õ¿Õ¥Õ½Ö„Õ¸Õ¾ (ÕºÕ¡Õ¿Õ³Õ¥Õ¶Õ¥Õ¬ Õ¯Õ¡Õ´ Õ¢Õ¡ÖÕ¥Õ¬ Õ¶Õ¸Ö€ ÕºÕ¡Õ¿Õ¸Ö‚Õ°Õ¡Õ¶Õ¸Ö‚Õ´)
+bookmark_label=Ô¸Õ¶Õ©Õ¡ÖÕ«Õ¯ Õ¿Õ¥Õ½Ö„Õ¨
+
+# Secondary toolbar and context menu
+tools.title=Ô³Õ¸Ö€Õ®Õ«Ö„Õ¶Õ¥Ö€
+tools_label=Ô³Õ¸Ö€Õ®Õ«Ö„Õ¶Õ¥Ö€
+first_page.title=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ¡Õ¼Õ¡Õ»Õ«Õ¶ Õ§Õ»Õ«Õ¶
+first_page.label=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ¡Õ¼Õ¡Õ»Õ«Õ¶ Õ§Õ»Õ«Õ¶
+first_page_label=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ¡Õ¼Õ¡Õ»Õ«Õ¶ Õ§Õ»Õ«Õ¶
+last_page.title=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ¾Õ¥Ö€Õ»Õ«Õ¶ Õ§Õ»Õ«Õ¶
+last_page.label=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ¾Õ¥Ö€Õ»Õ«Õ¶ Õ§Õ»Õ«Õ¶
+last_page_label=Ô±Õ¶ÖÕ¶Õ¥Õ¬ Õ¾Õ¥Ö€Õ»Õ«Õ¶ Õ§Õ»Õ«Õ¶
+page_rotate_cw.title=ÕŠÕ¿Õ¿Õ¥Õ¬ Õ¨Õ½Õ¿ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ«
+page_rotate_cw.label=ÕŠÕ¿Õ¿Õ¥Õ¬ Õ¨Õ½Õ¿ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ«
+page_rotate_cw_label=ÕŠÕ¿Õ¿Õ¥Õ¬ Õ¨Õ½Õ¿ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ«
+page_rotate_ccw.title=ÕŠÕ¿Õ¿Õ¥Õ¬ Õ°Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ«
+page_rotate_ccw.label=ÕŠÕ¿Õ¿Õ¥Õ¬ Õ°Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ«
+page_rotate_ccw_label=ÕŠÕ¿Õ¿Õ¥Õ¬ Õ°Õ¡Õ¯Õ¡Õ¼Õ¡Õ¯ ÕªÕ¡Õ´Õ¡ÖÕ¸Ö‚ÕµÖÕ« Õ½Õ¬Õ¡Ö„Õ«
+
+hand_tool_enable.title=Õ„Õ«Õ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Õ¼Ö„Õ« Õ£Õ¸Ö€Õ®Õ«Ö„Õ¨
+hand_tool_enable_label=Õ„Õ«Õ¡ÖÕ¶Õ¥Õ¬ Õ±Õ¥Õ¼Ö„Õ« Õ£Õ¸Ö€Õ®Õ«Ö„Õ¨
+hand_tool_disable.title=Ô±Õ¶Õ»Õ¡Õ¿Õ¥Õ¬ Õ±Õ¥Õ¼Ö„Õ« Õ£Õ¸Ö€Õ®Õ«Ö„Õ¨
+hand_tool_disable_label=Ô±Õ†Õ»Õ¡Õ¿Õ¥Õ¬ Õ±Õ¥Õ¼Ö„Õ« Õ£Õ¸Ö€Õ®Õ«Ö„Õ¨
+
+# Document properties dialog box
+document_properties.title=Õ“Õ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ°Õ¡Õ¿Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨...
+document_properties_label=Õ“Õ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ°Õ¡Õ¿Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¶Õ¥Ö€Õ¨...
+document_properties_file_name=Õ–Õ¡ÕµÕ¬Õ« Õ¡Õ¶Õ¸Ö‚Õ¶Õ¨.
+document_properties_file_size=Õ–Õ¡ÕµÕ¬Õ« Õ¹Õ¡ÖƒÕ¨.
+document_properties_kb={{size_kb}} Ô¿Ô² ({{size_b}} Õ¢Õ¡ÕµÕ©)
+document_properties_mb={{size_mb}} Õ„Ô² ({{size_b}} Õ¢Õ¡ÕµÕ©)
+document_properties_title=ÕŽÕ¥Ö€Õ¶Õ¡Õ£Õ«Ö€.
+document_properties_author=Հեղինակ․
+document_properties_subject=ÕŽÕ¥Ö€Õ¶Õ¡Õ£Õ«Ö€.
+document_properties_keywords=Õ€Õ«Õ´Õ¶Õ¡Õ¢Õ¡Õ¼.
+document_properties_creation_date=ÕÕ¿Õ¥Õ²Õ®Õ¥Õ¬Õ¸Ö‚ Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨.
+document_properties_modification_date=Õ“Õ¸ÖƒÕ¸ÕÕ¥Õ¬Õ¸Ö‚ Õ¡Õ´Õ½Õ¡Õ©Õ«Õ¾Õ¨.
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ÕÕ¿Õ¥Õ²Õ®Õ¸Õ².
+document_properties_producer=PDF-Õ« Õ°Õ¥Õ²Õ«Õ¶Õ¡Õ¯Õ¨.
+document_properties_version=PDF-Õ« Õ¿Õ¡Ö€Õ¢Õ¥Ö€Õ¡Õ¯Õ¨.
+document_properties_page_count=Ô·Õ»Õ¥Ö€Õ« Ö„Õ¡Õ¶Õ¡Õ¯Õ¨.
+document_properties_close=Õ“Õ¡Õ¯Õ¥Õ¬
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Ô²Õ¡ÖÕ¥Õ¬/Õ“Õ¡Õ¯Õ¥Õ¬ Ô¿Õ¸Õ²Õ¡ÕµÕ«Õ¶ Õ¾Õ¡Õ°Õ¡Õ¶Õ¡Õ¯Õ¨
+toggle_sidebar_label=Ô²Õ¡ÖÕ¥Õ¬/Õ“Õ¡Õ¯Õ¥Õ¬ Ô¿Õ¸Õ²Õ¡ÕµÕ«Õ¶ Õ¾Õ¡Õ°Õ¡Õ¶Õ¡Õ¯Õ¨
+outline.title=Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨
+outline_label=Õ“Õ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ¢Õ¸Õ¾Õ¡Õ¶Õ¤Õ¡Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨
+attachments.title=Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ¯ÖÕ¸Ö€Õ¤Õ¶Õ¥Ö€Õ¨
+attachments_label=Ô¿ÖÕ¸Ö€Õ¤Õ¶Õ¥Ö€
+thumbs.title=Õ‘Õ¸Ö‚ÖÕ¡Õ¤Ö€Õ¥Õ¬ Õ„Õ¡Õ¶Ö€Õ¡ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¨
+thumbs_label=Õ„Õ¡Õ¶Ö€Õ¡ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¨
+findbar.title=Ô³Õ¿Õ¶Õ¥Õ¬ ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ¸Ö‚Õ´
+findbar_label=Õ“Õ¶Õ¿Ö€Õ¥Õ¬
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Ô·Õ»Õ¨ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Ô·Õ»Õ« Õ´Õ¡Õ¶Ö€Õ¡ÕºÕ¡Õ¿Õ¯Õ¥Ö€Õ¨ {{page}}
+
+# Find panel button title and messages
+find_label=Ô³Õ¿Õ¶Õ¥Õ¬`
+find_previous.title=Ô³Õ¿Õ¶Õ¥Õ¬ Õ¡Õ¶Ö€Õ¡Õ°Õ¡ÕµÕ¿Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ¶Õ¡ÕÕ¸Ö€Õ¤ Õ°Õ¡Õ¶Õ¤Õ«ÕºÕ¸Ö‚Õ´Õ¨
+find_previous_label=Õ†Õ¡ÕÕ¸Ö€Õ¤Õ¨
+find_next.title=Ô³Õ¿Õ«Ö€ Õ¡Ö€Õ¿Õ¡Õ°Õ¡ÕµÕ¿Õ¸Ö‚Õ©ÕµÕ¡Õ¶ Õ°Õ¡Õ»Õ¸Ö€Õ¤ Õ°Õ¡Õ¶Õ¤Õ«ÕºÕ¸Ö‚Õ´Õ¨
+find_next_label=Õ€Õ¡Õ»Õ¸Ö€Õ¤Õ¨
+find_highlight=Õ†Õ·Õ¡Õ£Õ®Õ¥Õ¬ Ô²Õ¸Õ¬Õ¸Ö€Õ¨
+find_match_case_label=Õ„Õ¥Õ®(ÖƒÕ¸Ö„Ö€)Õ¡Õ¿Õ¡Õ¼ Õ°Õ¡Õ·Õ¾Õ« Õ¡Õ¼Õ¶Õ¥Õ¬
+find_reached_top=Õ€Õ¡Õ½Õ¥Õ¬ Õ¥Ö„ ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ¾Õ¥Ö€Ö‡Õ«Õ¶, Õ¯Õ·Õ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¾Õ« Õ¶Õ¥Ö€Ö„Ö‡Õ«Ö
+find_reached_bottom=Õ€Õ¡Õ½Õ¥Õ¬ Õ¥Ö„ ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ« Õ¾Õ¥Ö€Õ»Õ«Õ¶, Õ¯Õ·Õ¡Ö€Õ¸Ö‚Õ¶Õ¡Õ¯Õ¾Õ« Õ¾Õ¥Ö€Ö‡Õ«Ö
+find_not_found=Ô±Ö€Õ¿Õ¡Õ°Õ¡ÕµÕ¿Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨ Õ¹Õ£Õ¿Õ¶Õ¾Õ¥Ö
+
+# Error panel labels
+error_more_info=Ô±Õ¾Õ¥Õ¬Õ« Õ·Õ¡Õ¿ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶
+error_less_info=Õ”Õ«Õ¹ Õ¿Õ¥Õ²Õ¥Õ¯Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶
+error_close=Õ“Õ¡Õ¯Õ¥Õ¬
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (Õ¯Õ¡Õ¼Õ¸Ö‚ÖÕ¸Ö‚Õ´Õ¨. {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Ô³Ö€Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶Õ¨. {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Õ‡Õ¥Õ²Õ». {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Õ–Õ¡ÕµÕ¬. {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=ÕÕ¸Õ²Õ¨. {{line}}
+rendering_error=ÕÕÕ¡Õ¬Õ Õ§Õ»Õ¨ Õ½Õ¿Õ¥Õ²Õ®Õ¥Õ¬Õ«Õ½:
+
+# Predefined zoom values
+page_scale_width=Ô·Õ»Õ« Õ¬Õ¡ÕµÕ¶Ö„Õ¨
+page_scale_fit=ÕÕ£Õ¥Õ¬ Õ§Õ»Õ¨
+page_scale_auto=Ô»Õ¶Ö„Õ¶Õ¡Õ·ÕÕ¡Õ¿
+page_scale_actual=Ô»Ö€Õ¡Õ¯Õ¡Õ¶ Õ¹Õ¡ÖƒÕ¨
+
+# Loading indicator messages
+loading_error_indicator=ÕÕÕ¡Õ¬
+loading_error=ÕÕÕ¡Õ¬Õ PDF Ö†Õ¡ÕµÕ¬Õ¨ Õ¢Õ¡ÖÕ¥Õ¬Õ«Õ½Ö‰
+invalid_file_error=ÕÕÕ¡Õ¬ Õ¯Õ¡Õ´ Õ¢Õ¶Õ¡Õ½Õ¾Õ¡Õ® PDF Ö†Õ¡ÕµÕ¬:
+missing_file_error=PDF Ö†Õ¡ÕµÕ¬Õ¨ Õ¢Õ¡ÖÕ¡Õ¯Õ¡ÕµÕ¸Ö‚Õ´ Õ§:
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Ô¾Õ¡Õ¶Õ¸Õ©Õ¸Ö‚Õ©ÕµÕ¸Ö‚Õ¶]
+password_label=Õ„Õ¸Ö‚Õ¿Ö„Õ¡Õ£Ö€Õ¥Ö„ PDF-Õ« Õ£Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨:
+password_invalid=Ô³Õ¡Õ²Õ¿Õ¶Õ¡Õ¢Õ¡Õ¼Õ¨ Õ½ÕÕ¡Õ¬ Õ§: Ô¿Ö€Õ¯Õ«Õ¶ ÖƒÕ¸Ö€Õ±Õ¥Ö„:
+password_ok=Ô¼Ô±ÕŽ
+password_cancel=Õ‰Õ¥Õ²Õ¡Ö€Õ¯Õ¥Õ¬
+
+printing_not_supported=Ô¶Õ£Õ¸Ö‚Õ·Õ¡ÖÕ¸Ö‚Õ´. ÕÕºÕ¥Õ¬Õ¨ Õ¡Õ´Õ¢Õ¸Õ²Õ»Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢ Õ¹Õ« Õ¡Õ»Õ¡Õ¯ÖÕ¾Õ¸Ö‚Õ´ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ« Õ¯Õ¸Õ²Õ´Õ«ÖÖ‰
+printing_not_ready=Ô¶Õ£Õ¸Ö‚Õ·Õ¡ÖÕ¸Ö‚Õ´. PDF-Õ¨ Õ¡Õ´Õ¢Õ¸Õ²Õ»Õ¸Ö‚Õ©ÕµÕ¡Õ´Õ¢ Õ¹Õ« Õ¢Õ¥Õ¼Õ¶Õ¡Õ¾Õ¸Ö€Õ¾Õ¥Õ¬ Õ¿ÕºÕ¥Õ¬Õ¸Ö‚ Õ°Õ¡Õ´Õ¡Ö€:
+web_fonts_disabled=ÕŽÕ¥Õ¢-Õ¿Õ¡Õ¼Õ¡Õ¿Õ¥Õ½Õ¡Õ¯Õ¶Õ¥Ö€Õ¨ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ¥Õ¶. Õ°Õ¶Õ¡Ö€Õ¡Õ¾Õ¸Ö€ Õ¹Õ§ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ¶Õ¥Ö€Õ¯Õ¡Õ¼Õ¸Ö‚ÖÕ¾Õ¡Õ® PDF Õ¿Õ¡Õ¼Õ¡Õ¿Õ¥Õ½Õ¡Õ¯Õ¶Õ¥Ö€Õ¨:
+document_colors_disabled=PDF ÖƒÕ¡Õ½Õ¿Õ¡Õ©Õ²Õ©Õ¥Ö€Õ«Õ¶ Õ©Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¾Õ¡Õ® Õ¹Õ§ Ö…Õ£Õ¿Õ¡Õ£Õ¸Ö€Õ®Õ¥Õ¬ Õ«Ö€Õ¥Õ¶Ö Õ½Õ¥ÖƒÕ¡Õ¯Õ¡Õ¶ Õ£Õ¸Ö‚ÕµÕ¶Õ¥Ö€Õ¨: 'Ô¹Õ¸Ö‚ÕµÕ¬Õ¡Õ¿Ö€Õ¥Õ¬ Õ§Õ»Õ¥Ö€Õ«Õ¶ Õ¨Õ¶Õ¿Ö€Õ¥Õ¬ Õ«Ö€Õ¥Õ¶Ö Õ½Õ¥ÖƒÕ¡Õ¯Õ¡Õ¶ Õ£Õ¸Ö‚ÕµÕ¶Õ¥Ö€Õ¨' Õ¨Õ¶Õ¿Ö€Õ¡Õ¶Ö„Õ¨ Õ¡Õ¶Õ»Õ¡Õ¿Õ¾Õ¡Õ® Õ§ Õ¤Õ«Õ¿Õ¡Ö€Õ¯Õ«Õ¹Õ¸Ö‚Õ´:
diff --git a/static/pdf.js/locale/id/viewer.properties b/static/pdf.js/locale/id/viewer.properties
new file mode 100644
index 000000000..698a2ba11
--- /dev/null
+++ b/static/pdf.js/locale/id/viewer.properties
@@ -0,0 +1,169 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Laman Sebelumnya
+previous_label=Sebelumnya
+next.title=Laman Selanjutnya
+next_label=Selanjutnya
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Laman:
+page_of=dari {{pageCount}}
+
+zoom_out.title=Perkecil
+zoom_out_label=Perkecil
+zoom_in.title=Perbesar
+zoom_in_label=Perbesar
+zoom.title=Perbesaran
+print.title=Cetak
+print_label=Cetak
+presentation_mode.title=Ganti ke Mode Presentasi
+presentation_mode_label=Mode Presentasi
+open_file.title=Buka Berkas
+open_file_label=Buka
+download.title=Unduh
+download_label=Unduh
+bookmark.title=Tampilan Sekarang (salin atau buka di jendela baru)
+bookmark_label=Tampilan Sekarang
+
+# Secondary toolbar and context menu
+tools.title=Alat
+tools_label=Alat
+first_page.title=Buka Halaman Pertama
+first_page.label=Buka Halaman Pertama
+first_page_label=Buka Halaman Pertama
+last_page.title=Buka Halaman Terakhir
+last_page.label=Buka Halaman Terakhir
+last_page_label=Buka Halaman Terakhir
+page_rotate_cw.title=Putar Searah Jarum Jam
+page_rotate_cw.label=Putar Searah Jarum Jam
+page_rotate_cw_label=Putar Searah Jarum Jam
+page_rotate_ccw.title=Putar Berlawanan Arah Jarum Jam
+page_rotate_ccw.label=Putar Berlawanan Arah Jarum Jam
+page_rotate_ccw_label=Putar Berlawanan Arah Jarum Jam
+
+hand_tool_enable.title=Aktifkan alat tangan
+hand_tool_enable_label=Aktifkan alat tangan
+hand_tool_disable.title=Nonaktifkan alat tangan
+hand_tool_disable_label=Nonaktifkan alat tangan
+
+# Document properties dialog box
+document_properties.title=Properti Dokumen…
+document_properties_label=Properti Dokumen…
+document_properties_file_name=Nama berkas:
+document_properties_file_size=Ukuran berkas:
+document_properties_kb={{size_kb}} KB ({{size_b}} byte)
+document_properties_mb={{size_mb}} MB ({{size_b}} byte)
+document_properties_title=Judul:
+document_properties_author=Penyusun:
+document_properties_subject=Subjek:
+document_properties_keywords=Kata Kunci:
+document_properties_creation_date=Tanggal Dibuat:
+document_properties_modification_date=Tanggal Dimodifikasi:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Pembuat:
+document_properties_producer=Pemroduksi PDF:
+document_properties_version=Versi PDF:
+document_properties_page_count=Jumlah Halaman:
+document_properties_close=Tutup
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Aktif/Nonaktifkan Bilah Samping
+toggle_sidebar_label=Aktif/Nonaktifkan Bilah Samping
+outline.title=Buka Kerangka Dokumen
+outline_label=Kerangka Dokumen
+attachments.title=Tampilkan Lampiran
+attachments_label=Lampiran
+thumbs.title=Tampilkan Miniatur
+thumbs_label=Miniatur
+findbar.title=Temukan di Dokumen
+findbar_label=Temukan
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Laman {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatur Laman {{page}}
+
+# Context menu
+first_page.label=Ke Halaman Pertama
+last_page.label=Ke Halaman Terakhir
+page_rotate_cw.label=Putar Searah Jarum Jam
+page_rotate_ccw.label=Putar Berlawanan Arah Jarum Jam
+
+# Find panel button title and messages
+find_label=Temukan:
+find_previous.title=Temukan kata sebelumnya
+find_previous_label=Sebelumnya
+find_next.title=Temukan lebih lanjut
+find_next_label=Selanjutnya
+find_highlight=Sorot semu&anya
+find_match_case_label=Cocokkan BESAR/kecil
+find_reached_top=Sampai di awal dokumen, dilanjutkan dari bawah
+find_reached_bottom=Sampai di akhir dokumen, dilanjutkan dari atas
+find_not_found=Frasa tidak ditemukan
+
+# Error panel labels
+error_more_info=Lebih Banyak Informasi
+error_less_info=Lebih Sedikit Informasi
+error_close=Tutup
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Pesan: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Berkas: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Baris: {{line}}
+rendering_error=Galat terjadi saat merender laman.
+
+# Predefined zoom values
+page_scale_width=Lebar Laman
+page_scale_fit=Muat Laman
+page_scale_auto=Perbesaran Otomatis
+page_scale_actual=Ukuran Asli
+
+# Loading indicator messages
+loading_error_indicator=Galat
+loading_error=Galat terjadi saat memuat PDF.
+invalid_file_error=Berkas PDF tidak valid atau rusak.
+missing_file_error=Berkas PDF tidak ada.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotasi {{type}}]
+password_label=Masukkan sandi untuk membuka berkas PDF ini.
+password_invalid=Sandi tidak valid. Silakan coba lagi.
+password_ok=Oke
+password_cancel=Batal
+
+printing_not_supported=Peringatan: Pencetakan tidak didukung secara lengkap pada peramban ini.
+printing_not_ready=Peringatan: Berkas PDF masih belum dimuat secara lengkap untuk dapat dicetak.
+web_fonts_disabled=Font web dinonaktifkan: tidak dapat menggunakan font PDF yang tersemat.
+document_colors_disabled=Dokumen PDF tidak diizinkan untuk menggunakan warnanya sendiri karena setelan \'Izinkan laman memilih warna sendiri\’ dinonaktifkan pada pengaturan.
diff --git a/static/pdf.js/locale/is/viewer.properties b/static/pdf.js/locale/is/viewer.properties
new file mode 100644
index 000000000..9c81b24c9
--- /dev/null
+++ b/static/pdf.js/locale/is/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Fyrri sÃða
+previous_label=Fyrri
+next.title=Næsta sÃða
+next_label=Næsti
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=SÃða:
+page_of=af {{pageCount}}
+
+zoom_out.title=Minnka
+zoom_out_label=Minnka
+zoom_in.title=Stækka
+zoom_in_label=Stækka
+zoom.title=Aðdráttur
+presentation_mode.title=Skipta yfir á kynningarham
+presentation_mode_label=Kynningarhamur
+open_file.title=Opna skrá
+open_file_label=Opna
+print.title=Prenta
+print_label=Prenta
+download.title=Hala niður
+download_label=Hala niður
+bookmark.title=Núverandi sýn (afritaðu eða opnaðu à nýjum glugga)
+bookmark_label=Núverandi sýn
+
+# Secondary toolbar and context menu
+tools.title=Verkfæri
+tools_label=Verkfæri
+first_page.title=Fara á fyrstu sÃðu
+first_page.label=Fara á fyrstu sÃðu
+first_page_label=Fara á fyrstu sÃðu
+last_page.title=Fara á sÃðustu sÃðu
+last_page.label=Fara á sÃðustu sÃðu
+last_page_label=Fara á sÃðustu sÃðu
+page_rotate_cw.title=Snúa réttsælis
+page_rotate_cw.label=Snúa réttsælis
+page_rotate_cw_label=Snúa réttsælis
+page_rotate_ccw.title=Snúa rangsælis
+page_rotate_ccw.label=Snúa rangsælis
+page_rotate_ccw_label=Snúa rangsælis
+
+hand_tool_enable.title=Virkja handarverkfæri
+hand_tool_enable_label=Virkja handarverkfæri
+hand_tool_disable.title=Gera handarverkfæri óvirkt
+hand_tool_disable_label=Gera handarverkfæri óvirkt
+
+# Document properties dialog box
+document_properties.title=Eiginleikar skjals…
+document_properties_label=Eiginleikar skjals…
+document_properties_file_name=Skráarnafn:
+document_properties_file_size=Skrárstærð:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Titill:
+document_properties_author=Hönnuður:
+document_properties_subject=Efni:
+document_properties_keywords=Stikkorð:
+document_properties_creation_date=Búið til:
+document_properties_modification_date=Dags breytingar:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Höfundur:
+document_properties_producer=PDF framleiðandi:
+document_properties_version=PDF útgáfa:
+document_properties_page_count=BlaðsÃðufjöldi:
+document_properties_close=Loka
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=VÃxla hliðslá
+toggle_sidebar_label=VÃxla hliðslá
+outline.title=Sýna efniskipan skjals
+outline_label=Efnisskipan skjals
+attachments.title=Sýna viðhengi
+attachments_label=Viðhengi
+thumbs.title=Sýna smámyndir
+thumbs_label=Smámyndir
+findbar.title=Leita à skjali
+findbar_label=Leita
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=SÃða {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Smámynd af sÃðu {{page}}
+
+# Find panel button title and messages
+find_label=Leita:
+find_previous.title=Leita að fyrra tilfelli þessara orða
+find_previous_label=Fyrri
+find_next.title=Leita að næsta tilfelli þessara orða
+find_next_label=Næsti
+find_highlight=Lita allt
+find_match_case_label=Passa við stafstöðu
+find_reached_top=Náði efst à skjal, held áfram neðst
+find_reached_bottom=Náði enda skjals, held áfram efst
+find_not_found=Fann ekki orðið
+
+# Error panel labels
+error_more_info=Meiri upplýsingar
+error_less_info=Minni upplýsingar
+error_close=Loka
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Skilaboð: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stafli: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Skrá: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=LÃna: {{line}}
+rendering_error=Upp kom villa við að birta sÃðuna.
+
+# Predefined zoom values
+page_scale_width=SÃðubreidd
+page_scale_fit=Passa á sÃðu
+page_scale_auto=Sjálfvirkur aðdráttur
+page_scale_actual=Raunstærð
+
+# Loading indicator messages
+loading_error_indicator=Villa
+loading_error=Villa kom upp við að hlaða inn PDF.
+invalid_file_error=Ógild eða skemmd PDF skrá.
+missing_file_error=Vantar PDF skrá.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Skýring]
+password_label=Sláðu inn lykilorð til að opna þessa PDF skrá.
+password_invalid=Ógilt lykilorð. Reyndu aftur.
+password_ok=Ã lagi
+password_cancel=Hætta við
+
+printing_not_supported=Aðvörun: Prentun er ekki með fyllilegan stuðning á þessum vafra.
+printing_not_ready=Aðvörun: Ekki er búið að hlaða inn allri PDF skránni fyrir prentun.
+web_fonts_disabled=Vef leturgerðir eru óvirkar: get ekki notað innbyggðar PDF leturgerðir.
+document_colors_disabled=PDF skjöl hafa ekki leyfi til að nota sÃna eigin liti: 'Leyfa sÃðum að velja eigin liti' er óvirkt à vafranum.
diff --git a/static/pdf.js/locale/it/viewer.properties b/static/pdf.js/locale/it/viewer.properties
index a9311d7e9..7457e2164 100644
--- a/static/pdf.js/locale/it/viewer.properties
+++ b/static/pdf.js/locale/it/viewer.properties
@@ -1,44 +1,109 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-bookmark.title=Visualizzazione corrente (copia o apri in una nuova finestra)
-previous.title=Precedente
-next.title=Successiva
-print.title=Stampa
-download.title=Download
-zoom_out.title=Riduci Zoom
-zoom_in.title=Aumenta Zoom
-error_more_info=Più Informazioni
-error_less_info=Meno Informazioni
-error_close=Chiudi
-error_build=PDF.JS Build: {{build}}
-error_message=Messaggio: {{message}}
-error_stack=Stack: {{stack}}
-error_file=File: {{file}}
-error_line=Linea: {{line}}
-page_scale_width=Adatta alla Larghezza
-page_scale_fit=Adatta alla Pagina
-page_scale_auto=Zoom Automatico
-page_scale_actual=Dimensione Attuale
-toggle_slider.title=Visualizza Riquadro Laterale
-thumbs.title=Mostra Miniature
-outline.title=Mostra Indice Documento
-loading=Caricamento... {{percent}}%
-loading_error_indicator=Errore
-loading_error=È accaduto un errore durante il caricamento del PDF.
-rendering_error=È accaduto un errore durante il rendering della pagina.
-page_label=Pagina:
-page_of=di {{pageCount}}
-open_file.title=Apri File
-text_annotation_type.alt=[{{type}} Annotazione]
\ No newline at end of file
+previous.title = Pagina precedente
+previous_label = Precedente
+next.title = Pagina successiva
+next_label = Successiva
+page_label = Pagina:
+page_of = di {{pageCount}}
+zoom_out.title = Riduci zoom
+zoom_out_label = Riduci zoom
+zoom_in.title = Aumenta zoom
+zoom_in_label = Aumenta zoom
+zoom.title = Zoom
+presentation_mode.title = Passa alla modalità presentazione
+presentation_mode_label = Modalità presentazione
+open_file.title = Apri file
+open_file_label = Apri file
+print.title = Stampa
+print_label = Stampa
+download.title = Scarica questo documento
+download_label = Download
+bookmark.title = Visualizzazione corrente (copia o apri in una nuova finestra)
+bookmark_label = Visualizzazione corrente
+tools.title = Strumenti
+tools_label = Strumenti
+first_page.title = Vai alla prima pagina
+first_page.label = Vai alla prima pagina
+first_page_label = Vai alla prima pagina
+last_page.title = Vai all’ultima pagina
+last_page.label = Vai all’ultima pagina
+last_page_label = Vai all’ultima pagina
+page_rotate_cw.title = Ruota in senso orario
+page_rotate_cw.label = Ruota in senso orario
+page_rotate_cw_label = Ruota in senso orario
+page_rotate_ccw.title = Ruota in senso antiorario
+page_rotate_ccw.label = Ruota in senso antiorario
+page_rotate_ccw_label = Ruota in senso antiorario
+hand_tool_enable.title = Attiva strumento mano
+hand_tool_enable_label = Attiva strumento mano
+hand_tool_disable.title = Disattiva strumento mano
+hand_tool_disable_label = Disattiva strumento mano
+document_properties.title = Proprietà del documento…
+document_properties_label = Proprietà del documento…
+document_properties_file_name = Nome file:
+document_properties_file_size = Dimensione file:
+document_properties_kb = {{size_kb}} kB ({{size_b}} byte)
+document_properties_mb = {{size_kb}} MB ({{size_b}} byte)
+document_properties_title = Titolo:
+document_properties_author = Autore:
+document_properties_subject = Oggetto:
+document_properties_keywords = Parole chiave:
+document_properties_creation_date = Data creazione:
+document_properties_modification_date = Data modifica:
+document_properties_date_string = {{date}}, {{time}}
+document_properties_creator = Autore originale:
+document_properties_producer = Produttore PDF:
+document_properties_version = Versione PDF:
+document_properties_page_count = Conteggio pagine:
+document_properties_close = Chiudi
+toggle_sidebar.title = Attiva/disattiva barra laterale
+toggle_sidebar_label = Attiva/disattiva barra laterale
+outline.title = Visualizza la struttura del documento
+outline_label = Struttura documento
+attachments.title = Visualizza allegati
+attachments_label = Allegati
+thumbs.title = Mostra le miniature
+thumbs_label = Miniature
+findbar.title = Trova nel documento
+findbar_label = Trova
+thumb_page_title = Pagina {{page}}
+thumb_page_canvas = Miniatura della pagina {{page}}
+find_label = Trova:
+find_previous.title = Trova l’occorrenza precedente del testo da cercare
+find_previous_label = Precedente
+find_next.title = Trova l’occorrenza successiva del testo da cercare
+find_next_label = Successivo
+find_highlight = Evidenzia
+find_match_case_label = Maiuscole/minuscole
+find_reached_top = Raggiunto l’inizio della pagina, continua dalla fine
+find_reached_bottom = Raggiunta la fine della pagina, continua dall’inizio
+find_not_found = Testo non trovato
+error_more_info = Più informazioni
+error_less_info = Meno informazioni
+error_close = Chiudi
+error_version_info = PDF.js v{{version}} (build: {{build}})
+error_message = Messaggio: {{message}}
+error_stack = Stack: {{stack}}
+error_file = File: {{file}}
+error_line = Riga: {{line}}
+rendering_error = Si è verificato un errore durante il rendering della pagina.
+page_scale_width = Larghezza pagina
+page_scale_fit = Adatta a una pagina
+page_scale_auto = Zoom automatico
+page_scale_actual = Dimensioni effettive
+loading_error_indicator = Errore
+loading_error = Si è verificato un errore durante il caricamento del PDF.
+invalid_file_error = File PDF non valido o danneggiato.
+missing_file_error = File PDF non disponibile.
+text_annotation_type.alt = [Annotazione: {{type}}]
+password_label = Inserire la password per aprire questo file PDF.
+password_invalid = Password non corretta. Riprovare.
+password_ok = OK
+password_cancel = Annulla
+printing_not_supported = Attenzione: la stampa non è completamente supportata da questo browser.
+printing_not_ready = Attenzione: il PDF non è ancora stato caricato completamente per la stampa.
+web_fonts_disabled = I web font risultano disattivati: impossibile utilizzare i caratteri inclusi nel PDF.
+document_colors_disabled = Non è possibile per i documenti PDF utilizzare i propri colori: l’opzione del browser “Permetti alle pagine di scegliere i propri colori invece di quelli impostati†è disattivata.
diff --git a/static/pdf.js/locale/ja/viewer.properties b/static/pdf.js/locale/ja/viewer.properties
index 3b35bbdf3..40e21849c 100644
--- a/static/pdf.js/locale/ja/viewer.properties
+++ b/static/pdf.js/locale/ja/viewer.properties
@@ -1,141 +1,163 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
-
-# Main toolbar buttons (tooltips and alt text for images)
-previous.title=å‰ã®ãƒšãƒ¼ã‚¸
-previous_label=å‰ã¸
-next.title=次ã®ãƒšãƒ¼ã‚¸
-next_label=次ã¸
-
-# LOCALIZATION NOTE (page_label, page_of):
-# These strings are concatenated to form the "Page: X of Y" string.
-# Do not translate "{{pageCount}}", it will be substituted with a number
-# representing the total number of pages.
-page_label=ページ:
-page_of=/ {{pageCount}}
-
-zoom_out.title=縮å°
-zoom_out_label=縮å°
-zoom_in.title=拡大
-zoom_in_label=拡大
-zoom.title=ズーãƒ
-presentation_mode.title=プレゼンテーションモードã«åˆ‡ã‚Šæ›¿ãˆã¾ã™
-presentation_mode_label=プレゼンテーションモード
-open_file.title=ファイルを開ã
-open_file_label=é–‹ã
-print.title=å°åˆ·
-print_label=å°åˆ·
-download.title=ダウンãƒãƒ¼ãƒ‰
-download_label=ダウンãƒãƒ¼ãƒ‰
-bookmark.title=ç¾åœ¨ã®ãƒ“ューをブックマーク
-bookmark_label=ç¾åœ¨ã®ãƒ“ューをブックマーク
-
-# Secondary toolbar and context menu
-tools.title=ツール
-tools_label=ツール
-first_page.title=最åˆã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
-first_page.label=最åˆã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
-first_page_label=最åˆã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
-last_page.title=最後ã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
-last_page.label=最後ã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
-last_page_label=最後ã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
-page_rotate_cw.title=å³å›žè»¢
-page_rotate_cw.label=å³å›žè»¢
-page_rotate_cw_label=å³å›žè»¢
-page_rotate_ccw.title=左回転
-page_rotate_ccw.label=左回転
-page_rotate_ccw_label=左回転
-
-hand_tool_enable.title=手ã®ã²ã‚‰ãƒ„ールを有効ã«ã™ã‚‹
-hand_tool_enable_label=手ã®ã²ã‚‰ãƒ„ールを有効ã«ã™ã‚‹
-hand_tool_disable.title=手ã®ã²ã‚‰ãƒ„ールを無効ã«ã™ã‚‹
-hand_tool_disable_label=手ã®ã²ã‚‰ãƒ„ールを無効ã«ã™ã‚‹
-
-# Tooltips and alt text for side panel toolbar buttons
-# (the _label strings are alt text for the buttons, the .title strings are
-# tooltips)
-toggle_sidebar.title=サイドãƒãƒ¼ã®åˆ‡ã‚Šæ›¿ãˆ
-toggle_sidebar_label=サイドãƒãƒ¼ã®åˆ‡ã‚Šæ›¿ãˆ
-outline.title=文書ã®ç›®æ¬¡
-outline_label=文書ã®ç›®æ¬¡
-thumbs.title=縮å°ç‰ˆ
-thumbs_label=縮å°ç‰ˆ
-findbar.title=検索
-findbar_label=検索
-
-# Thumbnails panel item (tooltip and alt text for images)
-# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
-# number.
-thumb_page_title={{page}} ページ
-# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
-# number.
-thumb_page_canvas=ページã®ç¸®å°ç‰ˆ {{page}}
-
-# Find panel button title and messages
-find_label=検索:
-find_previous.title=指定文å—列ã«ä¸€è‡´ã™ã‚‹ 1 ã¤å‰ã®éƒ¨åˆ†ã‚’検索ã—ã¾ã™
-find_previous_label=å‰ã¸
-find_next.title=指定文å—列ã«ä¸€è‡´ã™ã‚‹æ¬¡ã®éƒ¨åˆ†ã‚’検索ã—ã¾ã™
-find_next_label=次ã¸
-find_highlight=ã™ã¹ã¦å¼·èª¿è¡¨ç¤º
-find_match_case_label=大文å—/å°æ–‡å—を区別
-find_reached_top=文書先é ã¾ã§æ¤œç´¢ã—ãŸã®ã§æœ«å°¾ã«æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã—ãŸã€‚
-find_reached_bottom=文書末尾ã¾ã§æ¤œç´¢ã—ãŸã®ã§å…ˆé ã«æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã—ãŸã€‚
-find_not_found=見ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚
-
-# Error panel labels
-error_more_info=è©³ç´°æƒ…å ±
-error_less_info=è©³ç´°æƒ…å ±ã®éžè¡¨ç¤º
-error_close=é–‰ã˜ã‚‹
-# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
-# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (ビルド: {{build}})
-# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
-# english string describing the error.
-error_message=メッセージ: {{message}}
-# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
-# trace.
-error_stack=スタック: {{stack}}
-# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
-error_file=ファイル: {{file}}
-# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=ライン: {{line}}
-rendering_error=ページã®ãƒ¬ãƒ³ãƒ€ãƒªãƒ³ã‚°ä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ
-
-# Predefined zoom values
-page_scale_width=å¹…ã«åˆã‚ã›ã‚‹
-page_scale_fit=ページã®ã‚µã‚¤ã‚ºã«åˆã‚ã›ã‚‹
-page_scale_auto=自動ズーãƒ
-page_scale_actual=実際ã®ã‚µã‚¤ã‚º
-
-# Loading indicator messages
-loading_error_indicator=エラー
-loading_error=PDF ã®èªã¿è¾¼ã¿ä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ
-invalid_file_error=無効ã¾ãŸã¯ç ´æã—㟠PDF ファイル
-missing_file_error=PDF ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。
-
-# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
-# "{{type}}" will be replaced with an annotation type from a list defined in
-# the PDF spec (32000-1:2008 Table 169 – Annotation types).
-# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[{{type}} 注釈]
-password_label=ã“ã® PDF ファイルを開ããŸã‚ã®ãƒ‘スワードを入力ã—ã¦ãã ã•ã„。
-password_invalid=無効ãªãƒ‘スワードã§ã™ã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。
-password_ok=OK
-password_cancel=ã‚ャンセル
-
-printing_not_supported=è¦å‘Šï¼šã“ã®ãƒ–ラウザã§ã¯å°åˆ·ãŒå®Œå…¨ã«ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“
-printing_not_ready=è¦å‘Šï¼šPDF ã‚’å°åˆ·ã™ã‚‹ãŸã‚ã®èªã¿è¾¼ã¿ãŒçµ‚了ã—ã¦ã„ã¾ã›ã‚“
-web_fonts_disabled=Web フォントãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™: 埋ã‚è¾¼ã¾ã‚ŒãŸ PDF ã®ãƒ•ã‚©ãƒ³ãƒˆã‚’使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“
-document_colors_disabled=PDF文書ã¯ã€Web ページãŒæŒ‡å®šã—ãŸé…色を使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“: \'Web ページãŒæŒ‡å®šã—ãŸé…色\' ã¯ãƒ–ラウザã§ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=å‰ã®ãƒšãƒ¼ã‚¸
+previous_label=å‰ã¸
+next.title=次ã®ãƒšãƒ¼ã‚¸
+next_label=次ã¸
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=ページ:
+page_of=/ {{pageCount}}
+
+zoom_out.title=縮å°
+zoom_out_label=縮å°
+zoom_in.title=拡大
+zoom_in_label=拡大
+zoom.title=拡大/縮å°
+presentation_mode.title=プレゼンテーションモードã«åˆ‡ã‚Šæ›¿ãˆã¾ã™
+presentation_mode_label=プレゼンテーションモード
+open_file.title=ファイルを開ã
+open_file_label=é–‹ã
+print.title=å°åˆ·
+print_label=å°åˆ·
+download.title=ダウンãƒãƒ¼ãƒ‰
+download_label=ダウンãƒãƒ¼ãƒ‰
+bookmark.title=ç¾åœ¨ã®ãƒ“ューをブックマーク
+bookmark_label=ç¾åœ¨ã®ãƒ“ューをブックマーク
+
+# Secondary toolbar and context menu
+tools.title=ツール
+tools_label=ツール
+first_page.title=最åˆã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
+first_page.label=最åˆã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
+first_page_label=最åˆã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
+last_page.title=最後ã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
+last_page.label=最後ã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
+last_page_label=最後ã®ãƒšãƒ¼ã‚¸ã¸ç§»å‹•
+page_rotate_cw.title=å³å›žè»¢
+page_rotate_cw.label=å³å›žè»¢
+page_rotate_cw_label=å³å›žè»¢
+page_rotate_ccw.title=左回転
+page_rotate_ccw.label=左回転
+page_rotate_ccw_label=左回転
+
+hand_tool_enable.title=手ã®ã²ã‚‰ãƒ„ールを有効ã«ã™ã‚‹
+hand_tool_enable_label=手ã®ã²ã‚‰ãƒ„ールを有効ã«ã™ã‚‹
+hand_tool_disable.title=手ã®ã²ã‚‰ãƒ„ールを無効ã«ã™ã‚‹
+hand_tool_disable_label=手ã®ã²ã‚‰ãƒ„ールを無効ã«ã™ã‚‹
+
+# Document properties dialog box
+document_properties.title=文書ã®ãƒ—ãƒãƒ‘ティ...
+document_properties_label=文書ã®ãƒ—ãƒãƒ‘ティ...
+document_properties_file_name=ファイルå:
+document_properties_file_size=ファイルサイズ:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=タイトル:
+document_properties_author=作æˆè€…:
+document_properties_subject=件å:
+document_properties_keywords=ã‚ーワード:
+document_properties_creation_date=作æˆæ—¥:
+document_properties_modification_date=æ›´æ–°æ—¥:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=アプリケーション:
+document_properties_producer=PDF 変æ›:
+document_properties_version=PDF ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³:
+document_properties_page_count=ページ数:
+document_properties_close=é–‰ã˜ã‚‹
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=サイドãƒãƒ¼ã®åˆ‡ã‚Šæ›¿ãˆ
+toggle_sidebar_label=サイドãƒãƒ¼ã®åˆ‡ã‚Šæ›¿ãˆ
+outline.title=文書ã®ç›®æ¬¡
+outline_label=文書ã®ç›®æ¬¡
+attachments.title=添付ファイル
+attachments_label=添付ファイル
+thumbs.title=縮å°ç‰ˆ
+thumbs_label=縮å°ç‰ˆ
+findbar.title=検索
+findbar_label=検索
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title={{page}} ページ
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=ページã®ç¸®å°ç‰ˆ {{page}}
+
+# Find panel button title and messages
+find_label=検索:
+find_previous.title=指定文å—列ã«ä¸€è‡´ã™ã‚‹ 1 ã¤å‰ã®éƒ¨åˆ†ã‚’検索ã—ã¾ã™
+find_previous_label=å‰ã¸
+find_next.title=指定文å—列ã«ä¸€è‡´ã™ã‚‹æ¬¡ã®éƒ¨åˆ†ã‚’検索ã—ã¾ã™
+find_next_label=次ã¸
+find_highlight=ã™ã¹ã¦å¼·èª¿è¡¨ç¤º
+find_match_case_label=大文å—/å°æ–‡å—を区別
+find_reached_top=文書先é ã¾ã§æ¤œç´¢ã—ãŸã®ã§æœ«å°¾ã«æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã—ãŸã€‚
+find_reached_bottom=文書末尾ã¾ã§æ¤œç´¢ã—ãŸã®ã§å…ˆé ã«æˆ»ã£ã¦æ¤œç´¢ã—ã¾ã—ãŸã€‚
+find_not_found=見ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚
+
+# Error panel labels
+error_more_info=è©³ç´°æƒ…å ±
+error_less_info=è©³ç´°æƒ…å ±ã®éžè¡¨ç¤º
+error_close=é–‰ã˜ã‚‹
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (ビルド: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=メッセージ: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=スタック: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ファイル: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=ライン: {{line}}
+rendering_error=ページã®ãƒ¬ãƒ³ãƒ€ãƒªãƒ³ã‚°ä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ
+
+# Predefined zoom values
+page_scale_width=å¹…ã«åˆã‚ã›ã‚‹
+page_scale_fit=ページã®ã‚µã‚¤ã‚ºã«åˆã‚ã›ã‚‹
+page_scale_auto=自動ズーãƒ
+page_scale_actual=実際ã®ã‚µã‚¤ã‚º
+
+# Loading indicator messages
+loading_error_indicator=エラー
+loading_error=PDF ã®èªã¿è¾¼ã¿ä¸ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ
+invalid_file_error=無効ã¾ãŸã¯ç ´æã—㟠PDF ファイル
+missing_file_error=PDF ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} 注釈]
+password_label=ã“ã® PDF ファイルを開ããŸã‚ã®ãƒ‘スワードを入力ã—ã¦ãã ã•ã„。
+password_invalid=無効ãªãƒ‘スワードã§ã™ã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。
+password_ok=OK
+password_cancel=ã‚ャンセル
+
+printing_not_supported=è¦å‘Š: ã“ã®ãƒ–ラウザã§ã¯å°åˆ·ãŒå®Œå…¨ã«ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“
+printing_not_ready=è¦å‘Š: PDF ã‚’å°åˆ·ã™ã‚‹ãŸã‚ã®èªã¿è¾¼ã¿ãŒçµ‚了ã—ã¦ã„ã¾ã›ã‚“
+web_fonts_disabled=Web フォントãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™: 埋ã‚è¾¼ã¾ã‚ŒãŸ PDF ã®ãƒ•ã‚©ãƒ³ãƒˆã‚’使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“
+document_colors_disabled=PDF 文書ã¯ã€Web ページãŒæŒ‡å®šã—ãŸé…色を使用ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“: \'Web ページãŒæŒ‡å®šã—ãŸé…色\' ã¯ãƒ–ラウザã§ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚
diff --git a/static/pdf.js/locale/ka/viewer.properties b/static/pdf.js/locale/ka/viewer.properties
new file mode 100644
index 000000000..f6c68f50f
--- /dev/null
+++ b/static/pdf.js/locale/ka/viewer.properties
@@ -0,0 +1,124 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=წინრგვერდი
+previous_label=წინáƒ
+next.title=შემდეგი გვერდი
+next_label=შემდეგი
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=გვერდი:
+page_of=of {{pageCount}}
+
+zoom_out.title=შემცირებáƒ
+zoom_out_label=გáƒáƒ–რდáƒ
+zoom_in.title=შემცირებáƒ
+zoom_in_label=შემცირებáƒ
+zoom.title=მáƒáƒ¡áƒ¨áƒ¢áƒáƒ‘ი
+print.title=áƒáƒ›áƒáƒ‘ეáƒáƒ“ვáƒ
+print_label=áƒáƒ›áƒáƒ‘ეáƒáƒ“ვáƒ
+presentation_mode.title=გáƒáƒ“áƒáƒ თვრპრეზენტáƒáƒªáƒ˜áƒ˜áƒ¡ რეჟიმზე
+presentation_mode_label=პრეზენტáƒáƒªáƒ˜áƒ˜áƒ¡ რეჟიმი
+open_file.title=ფáƒáƒ˜áƒšáƒ˜áƒ¡ გáƒáƒ®áƒ¡áƒœáƒ
+open_file_label=გáƒáƒ®áƒ¡áƒœáƒ
+download.title=ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ თვáƒ
+download_label=ჩáƒáƒ›áƒáƒ¢áƒ•áƒ˜áƒ თვáƒ
+bookmark.title=მიმდინáƒáƒ ე ხედი (áƒáƒ¡áƒšáƒ˜ áƒáƒœ გáƒáƒ®áƒ¡áƒœáƒ áƒáƒ®áƒáƒš სáƒáƒ კმელში)
+bookmark_label=მიმდინáƒáƒ ე ხედი
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=სტენდის ჩვენებáƒ/დáƒáƒ›áƒáƒšáƒ•áƒ
+toggle_sidebar_label=სტენდის ჩვენებáƒ/დáƒáƒ›áƒáƒšáƒ•áƒ
+outline.title=დáƒáƒ™áƒ£áƒ›áƒ”ნტის სქემის ჩვენებáƒ
+outline_label=დáƒáƒ™áƒ£áƒ›áƒ”ნტის სქემáƒ
+thumbs.title=მინიáƒáƒ¢áƒ£áƒ ების ჩვენებáƒ
+thumbs_label=მინიáƒáƒ¢áƒ£áƒ ები
+findbar.title=პáƒáƒ•áƒœáƒ დáƒáƒ™áƒ£áƒ›áƒ”ნტში
+findbar_label=პáƒáƒ•áƒœáƒ
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=გვერდი {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=მინიáƒáƒ¢áƒ£áƒ რგვერდისთვის {{page}}
+
+# Context menu
+first_page.label=გáƒáƒ“áƒáƒ¡áƒ•áƒšáƒ პირველ გვერდზე
+last_page.label=გáƒáƒ“áƒáƒ¡áƒ•áƒšáƒ ბáƒáƒšáƒ გვერდზე
+page_rotate_cw.label=დáƒáƒ¢áƒ იáƒáƒšáƒ”ბáƒ
+page_rotate_ccw.label=უკუდáƒáƒ¢áƒ იáƒáƒšáƒ”ბáƒ
+
+# Find panel button title and messages
+find_label=პáƒáƒ•áƒœáƒ:
+find_previous.title=კáƒáƒœáƒ¢áƒ”ქსტის წინრთáƒáƒœáƒ®áƒ•áƒ”დრის პáƒáƒ•áƒœáƒ
+find_previous_label=წინáƒ
+find_next.title=კáƒáƒœáƒ¢áƒ”ქსტის შემდეგი თáƒáƒœáƒ®áƒ•áƒ”დრის პáƒáƒ•áƒœáƒ
+find_next_label=შემდეგი
+find_highlight=ყველáƒáƒ¡ გáƒáƒ›áƒáƒ§áƒáƒ¤áƒ
+find_match_case_label=მთáƒáƒ•áƒ ულის გáƒáƒ—ვáƒáƒšáƒ˜áƒ¡áƒ¬áƒ˜áƒœáƒ”ბით
+find_reached_top=დáƒáƒ™áƒ£áƒ›áƒ”ნტის თáƒáƒ•áƒ˜, გრძელდებრდáƒáƒ™áƒ£áƒ›áƒ”ნტის ბáƒáƒšáƒáƒ“áƒáƒœ
+find_reached_bottom=დáƒáƒ™áƒ£áƒ›áƒ”ნტის ბáƒáƒšáƒ, გრძელდებრდáƒáƒ™áƒ£áƒ›áƒ”ნტის თáƒáƒ•áƒ˜áƒ“áƒáƒœ
+find_not_found=კáƒáƒœáƒ¢áƒ”ქსტი ვერმáƒáƒ˜áƒ«áƒ”ბნáƒ
+
+# Error panel labels
+error_more_info=დეტáƒáƒšáƒ”ბის ჩვენებáƒ
+error_less_info=დეტáƒáƒšáƒ”ბის დáƒáƒ›áƒáƒšáƒ•áƒ
+error_close=დáƒáƒ®áƒ£áƒ ვáƒ
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (áƒáƒ’ებáƒ: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=გზáƒáƒ•áƒœáƒ˜áƒšáƒ˜: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=მáƒáƒ˜áƒ“ი: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ფáƒáƒ˜áƒšáƒ˜: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=სტრიქáƒáƒœáƒ˜: {{line}}
+rendering_error=შეცდáƒáƒ›áƒ გვერდის áƒáƒ¡áƒáƒ®áƒ•áƒ˜áƒ¡áƒáƒ¡.
+
+# Predefined zoom values
+page_scale_width=გვერდის სიგáƒáƒœáƒ”ზე
+page_scale_fit=გვერდის შევსებáƒ
+page_scale_auto=თვითმáƒáƒ¡áƒ¨áƒ¢áƒáƒ‘ი
+page_scale_actual=რეáƒáƒšáƒ£áƒ ი ზáƒáƒ›áƒ
+
+# Loading indicator messages
+loading_error_indicator=შეცდáƒáƒ›áƒ
+loading_error=შეცდáƒáƒ›áƒ PDF ფáƒáƒ˜áƒšáƒ˜áƒ¡ ჩáƒáƒ¢áƒ•áƒ˜áƒ თვისáƒáƒ¡.
+invalid_file_error=უმáƒáƒ თებლრáƒáƒœ დáƒáƒ–იáƒáƒœáƒ”ბული PDF ფáƒáƒ˜áƒšáƒ˜.
+missing_file_error=მცდáƒáƒ ი PDF ფáƒáƒ˜áƒšáƒ˜.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} áƒáƒœáƒáƒ¢áƒáƒªáƒ˜áƒ]
+request_password=PDF დáƒáƒªáƒ£áƒšáƒ˜áƒ პáƒáƒ áƒáƒšáƒ˜áƒ—:
+invalid_password=პáƒáƒ áƒáƒšáƒ˜ მცდáƒáƒ იáƒ.
+
+printing_not_supported=გáƒáƒ¤áƒ თხილებáƒ: áƒáƒ› ბრáƒáƒ£áƒ–ერში áƒáƒ›áƒáƒ‘ეáƒáƒ“ვის მხáƒáƒ დáƒáƒáƒ”რრáƒáƒ áƒáƒ¡áƒ ულირ.
+printing_not_ready=გáƒáƒ¤áƒ თხილებáƒ: PDF ფáƒáƒ˜áƒšáƒ˜ áƒáƒ›áƒáƒ¡áƒáƒ‘ეáƒáƒ“áƒáƒ“ სრულáƒáƒ“ áƒáƒ ჩáƒáƒ¢áƒ•áƒ˜áƒ თულáƒ.
+web_fonts_disabled=ვებ შრიფტები áƒáƒ›áƒáƒ თულიáƒ: ჩáƒáƒ“გმული PDF შრიფტებით სáƒáƒ გებლáƒáƒ‘რვერხერხდებáƒ.
+document_colors_disabled=PDF დáƒáƒ™áƒ£áƒ›áƒ”ნტებს ეკრძáƒáƒšáƒ”ბáƒáƒ— სáƒáƒ™áƒ£áƒ—áƒáƒ ი ფერების გáƒáƒ›áƒáƒ§áƒ”ნებáƒ: ბრáƒáƒ£áƒ–ერში áƒáƒ›áƒáƒ თულირპáƒáƒ áƒáƒ›áƒ”ტრი - «გვერდებისთვის სáƒáƒ™áƒ£áƒ—áƒáƒ ი ფერებით სáƒáƒ გებლáƒáƒ‘ის უფლებáƒÂ».
diff --git a/static/pdf.js/locale/kk/viewer.properties b/static/pdf.js/locale/kk/viewer.properties
new file mode 100644
index 000000000..7d02ae599
--- /dev/null
+++ b/static/pdf.js/locale/kk/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Ðлдыңғы парақ
+previous_label=ÐлдыңғыÑÑ‹
+next.title=КелеÑÑ– парақ
+next_label=КелеÑÑ–
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Парақ:
+page_of={{pageCount}} ішінен
+
+zoom_out.title=Кішірейту
+zoom_out_label=Кішірейту
+zoom_in.title=Үлкейту
+zoom_in_label=Үлкейту
+zoom.title=МаÑштаб
+presentation_mode.title=ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ñ–Ð½Ðµ ауыÑу
+presentation_mode_label=ÐŸÑ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ñ–
+open_file.title=Файлды ашу
+open_file_label=Ðшу
+print.title=БаÑпаға шығару
+print_label=БаÑпаға шығару
+download.title=Жүктеп алу
+download_label=Жүктеп алу
+bookmark.title=Ðғымдағы ÐºÓ©Ñ€Ñ–Ð½Ñ–Ñ (көшіру не жаңа терезеде ашу)
+bookmark_label=Ðғымдағы көрініÑ
+
+# Secondary toolbar and context menu
+tools.title=Саймандар
+tools_label=Саймандар
+first_page.title=Ðлғашқы параққа өту
+first_page.label=Ðлғашқы параққа өту
+first_page_label=Ðлғашқы параққа өту
+last_page.title=Соңғы параққа өту
+last_page.label=Соңғы параққа өту
+last_page_label=Соңғы параққа өту
+page_rotate_cw.title=Сағат тілі бағытымен айналдыру
+page_rotate_cw.label=Сағат тілі бағытымен бұру
+page_rotate_cw_label=Сағат тілі бағытымен бұру
+page_rotate_ccw.title=Сағат тілі бағытына қарÑÑ‹ бұру
+page_rotate_ccw.label=Сағат тілі бағытына қарÑÑ‹ бұру
+page_rotate_ccw_label=Сағат тілі бағытына қарÑÑ‹ бұру
+
+hand_tool_enable.title=Қол Ñайманын Ñ–Ñке қоÑу
+hand_tool_enable_label=Қол Ñайманын Ñ–Ñке қоÑу
+hand_tool_disable.title=Қол Ñайманын Ñөндіру
+hand_tool_disable_label=Қол Ñайманын Ñөндіру
+
+# Document properties dialog box
+document_properties.title=Құжат қаÑиеттері…
+document_properties_label=Құжат қаÑиеттері…
+document_properties_file_name=Файл аты:
+document_properties_file_size=Файл өлшемі:
+document_properties_kb={{size_kb}} КБ ({{size_b}} байт)
+document_properties_mb={{size_mb}} МБ ({{size_b}} байт)
+document_properties_title=Тақырыбы...
+document_properties_author=Ðвторы:
+document_properties_subject=Тақырыбы:
+document_properties_keywords=Кілт Ñөздер:
+document_properties_creation_date=ЖаÑалған күні:
+document_properties_modification_date=Түзету күні:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ЖаÑаған:
+document_properties_producer=PDF өндірген:
+document_properties_version=PDF нұÑқаÑÑ‹:
+document_properties_page_count=Беттер Ñаны:
+document_properties_close=Жабу
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Бүйір панелін көрÑету/жаÑыру
+toggle_sidebar_label=Бүйір панелін көрÑету/жаÑыру
+outline.title=Құжат құрамаÑын көрÑету
+outline_label=Құжат құрамаÑÑ‹
+attachments.title=Салынымдарды көрÑету
+attachments_label=Салынымдар
+thumbs.title=Кіші көрініÑтерді көрÑету
+thumbs_label=Кіші көрініÑтер
+findbar.title=Құжаттан табу
+findbar_label=Табу
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title={{page}} парағы
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}} парағы үшін кіші көрініÑÑ–
+
+# Find panel button title and messages
+find_label=Табу:
+find_previous.title=ОÑÑ‹ Ñөздердің мәтіннен алдыңғы кездеÑуін табу
+find_previous_label=ÐлдыңғыÑÑ‹
+find_next.title=ОÑÑ‹ Ñөздердің мәтіннен келеÑÑ– кездеÑуін табу
+find_next_label=КелеÑÑ–
+find_highlight=Барлығын Ñ‚Ò¯Ñпен ерекшелеу
+find_match_case_label=РегиÑтрді еÑкеру
+find_reached_top=Құжаттың баÑына жеттік, Ñоңынан баÑтап жалғаÑтырамыз
+find_reached_bottom=Құжаттың Ñоңына жеттік, баÑынан баÑтап жалғаÑтырамыз
+find_not_found=Сөз(дер) табылмады
+
+# Error panel labels
+error_more_info=Көбірек ақпарат
+error_less_info=Ðзырақ ақпарат
+error_close=Жабу
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (жинақ: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Хабарлама: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Стек: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Файл: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Жол: {{line}}
+rendering_error=Парақты өңдеу кезінде қате кетті.
+
+# Predefined zoom values
+page_scale_width=Парақ ені
+page_scale_fit=Парақты Ñыйдыру
+page_scale_auto=ÐвтомаÑштабтау
+page_scale_actual=Ðақты өлшемі
+
+# Loading indicator messages
+loading_error_indicator=Қате
+loading_error=PDF жүктеу кезінде қате кетті.
+invalid_file_error=Зақымдалған немеÑе қате PDF файл.
+missing_file_error=PDF файлы жоқ.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} аңдатпаÑÑ‹]
+password_label=Бұл PDF файлын ашу үшін парольді енгізіңіз.
+password_invalid=Пароль Ð´Ò±Ñ€Ñ‹Ñ ÐµÐ¼ÐµÑ. Қайталап көріңіз.
+password_ok=ОК
+password_cancel=Ð‘Ð°Ñ Ñ‚Ð°Ñ€Ñ‚Ñƒ
+
+printing_not_supported=ЕÑкерту: БаÑпаға шығаруды бұл браузер толығымен қолдамайды.
+printing_not_ready=ЕÑкерту: БаÑпаға шығару үшін, бұл PDF толығымен жүктеліп алынбады.
+web_fonts_disabled=Веб қаріптері Ñөндірілген: құрамына енгізілген PDF қаріптерін қолдану мүмкін емеÑ.
+document_colors_disabled=PDF құжаттарына өздік Ñ‚Ò¯Ñтерді қолдану Ñ€Ò±Ò›Ñат етілмеген: бұл браузерде 'Веб-Ñайттарға өздерінің Ñ‚Ò¯Ñтерін қолдануға Ñ€Ò±Ò›Ñат беру' мүмкіндігі Ñөндірулі тұр.
diff --git a/static/pdf.js/locale/km/viewer.properties b/static/pdf.js/locale/km/viewer.properties
new file mode 100644
index 000000000..45acd63cf
--- /dev/null
+++ b/static/pdf.js/locale/km/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=ទំពáŸážšâ€‹áž˜áž»áž“
+previous_label=មុន
+next.title=ទំពáŸážšâ€‹áž”ន្ទាប់
+next_label=បន្ទាប់
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=ទំពáŸážšÂ ៖
+page_of=នៃ {{pageCount}}
+
+zoom_out.title=​បង្រួម
+zoom_out_label=​បង្រួម
+zoom_in.title=​ពង្រីក
+zoom_in_label=​ពង្រីក
+zoom.title=ពង្រីក
+presentation_mode.title=ប្ដូរ​ទៅ​របៀប​បទ​បង្ហាញ
+presentation_mode_label=របៀប​បទ​បង្ហាញ
+open_file.title=បើក​ឯកសារ
+open_file_label=បើក
+print.title=បោះពុម្ព
+print_label=បោះពុម្ព
+download.title=ទាញ​យក
+download_label=ទាញ​យក
+bookmark.title=ទិដ្ឋភាព​បច្ចុប្បន្ន (ចម្លង ឬ​បើក​នៅ​ក្នុង​បង្អួច​ážáŸ’មី)
+bookmark_label=ទិដ្ឋភាព​បច្ចុប្បន្ន
+
+# Secondary toolbar and context menu
+tools.title=ឧបករណáŸ
+tools_label=ឧបករណáŸ
+first_page.title=ទៅកាន់​ទំពáŸážšâ€‹ážŠáŸ†áž”ូង​
+first_page.label=ទៅកាន់​ទំពáŸážšâ€‹ážŠáŸ†áž”ូង​
+first_page_label=ទៅកាន់​ទំពáŸážšâ€‹ážŠáŸ†áž”ូង​
+last_page.title=ទៅកាន់​ទំពáŸážšâ€‹áž…ុងក្រោយ​
+last_page.label=ទៅកាន់​ទំពáŸážšâ€‹áž…ុងក្រោយ​
+last_page_label=ទៅកាន់​ទំពáŸážšâ€‹áž…ុងក្រោយ
+page_rotate_cw.title=បង្វិល​ស្រប​ទ្រនិច​នាឡិកា
+page_rotate_cw.label=បង្វិល​ស្រប​ទ្រនិច​នាឡិកា
+page_rotate_cw_label=បង្វិល​ស្រប​ទ្រនិច​នាឡិកា
+page_rotate_ccw.title=បង្វិល​ច្រាស​ទ្រនិច​នាឡិកា​​
+page_rotate_ccw.label=បង្វិល​ច្រាស​ទ្រនិច​នាឡិកា​​
+page_rotate_ccw_label=បង្វិល​ច្រាស​ទ្រនិច​នាឡិកា​​
+
+hand_tool_enable.title=បើក​ឧបករណáŸâ€‹ážŠáŸ„យ​ដៃ
+hand_tool_enable_label=បើក​ឧបករណáŸâ€‹ážŠáŸ„យ​ដៃ
+hand_tool_disable.title=បិទ​ឧបករណáŸâ€‹áž”្រើ​ដៃ
+hand_tool_disable_label=បិទ​ឧបករណáŸâ€‹áž”្រើ​ដៃ
+
+# Document properties dialog box
+document_properties.title=លក្ážážŽâ€‹ážŸáž˜áŸ’áž”ážáŸ’ážáž·â€‹áž¯áž€ážŸáž¶ážšâ€¦
+document_properties_label=លក្ážážŽâ€‹ážŸáž˜áŸ’áž”ážáŸ’ážáž·â€‹áž¯áž€ážŸáž¶ážšâ€¦
+document_properties_file_name=ឈ្មោះ​ឯកសារ៖
+document_properties_file_size=ទំហំ​ឯកសារ៖
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=ចំណងជើង ៖
+document_properties_author=អ្នក​និពន្ធ៖
+document_properties_subject=ប្រធានបទ៖
+document_properties_keywords=ពាក្យ​គន្លឹះ៖
+document_properties_creation_date=កាលបរិច្ឆáŸáž‘​បង្កើážáŸ–
+document_properties_modification_date=កាលបរិច្ឆáŸáž‘​កែប្រែ៖
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=អ្នក​បង្កើážáŸ–
+document_properties_producer=កម្មវិធី​បង្កើហPDF ៖
+document_properties_version=កំណែ PDF ៖
+document_properties_page_count=ចំនួន​ទំពáŸážšáŸ–
+document_properties_close=បិទ
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=បិទ/បើក​គ្រាប់​រំកិល
+toggle_sidebar_label=បិទ/បើក​គ្រាប់​រំកិល
+outline.title=បង្ហាញ​គ្រោង​ឯកសារ
+outline_label=គ្រោង​ឯកសារ
+attachments.title=បង្ហាញ​ឯកសារ​ភ្ជាប់
+attachments_label=ឯកសារ​ភ្ជាប់
+thumbs.title=បង្ហាញ​រូបភាព​ážáž¼áž…ៗ
+thumbs_label=រួបភាព​ážáž¼áž…ៗ
+findbar.title=រក​នៅ​ក្នុង​ឯកសារ
+findbar_label=រក
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=ទំពáŸážš {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=រូបភាព​ážáž¼áž…​របស់​ទំពáŸážš {{page}}
+
+# Find panel button title and messages
+find_label=រក ៖
+find_previous.title=រក​ពាក្យ ឬ​ឃ្លា​ដែល​បាន​ជួប​មុន
+find_previous_label=មុន
+find_next.title=រក​ពាក្យ ឬ​ឃ្លា​ដែល​បាន​ជួប​បន្ទាប់
+find_next_label=បន្ទាប់
+find_highlight=បន្លិច​ទាំងអស់
+find_match_case_label=ករណី​ដំណូច
+find_reached_top=បាន​បន្ážâ€‹áž–ី​ážáž¶áž„​ក្រោម ទៅ​ដល់​ážáž¶áž„​​លើ​នៃ​ឯកសារ
+find_reached_bottom=បាន​បន្ážâ€‹áž–ី​ážáž¶áž„លើ ទៅដល់​ចុង​​នៃ​ឯកសារ
+find_not_found=រក​មិន​ឃើញ​ពាក្យ ឬ​ឃ្លា
+
+# Error panel labels
+error_more_info=áž–áŸážáŸŒáž˜áž¶áž“​បន្ážáŸ‚ម
+error_less_info=áž–áŸážáŸŒáž˜áž¶áž“​ážáž·áž…ážáž½áž…
+error_close=បិទ
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=សារ ៖ {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ជង់ ៖ {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ឯកសារ ៖ {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=ជួរ ៖ {{line}}
+rendering_error=មាន​កំហុស​បាន​កើážáž¡áž¾áž„​ពáŸáž›â€‹áž”ង្ហាញ​ទំពáŸážšÂ ។
+
+# Predefined zoom values
+page_scale_width=ទទឹង​ទំពáŸážš
+page_scale_fit=សម​ទំពáŸážš
+page_scale_auto=ពង្រីក​ស្វáŸáž™áž”្រវážáŸ’ážáž·
+page_scale_actual=ទំហំ​ជាក់ស្ដែង
+
+# Loading indicator messages
+loading_error_indicator=កំហុស
+loading_error=មាន​កំហុស​បាន​កើážáž¡áž¾áž„​ពáŸáž›â€‹áž€áŸ†áž–ុង​ផ្ទុក PDF ។
+invalid_file_error=ឯកសារ PDF ážáž¼áž… ឬ​មិន​ážáŸ’រឹមážáŸ’រូវ ។
+missing_file_error=បាážáŸ‹â€‹áž¯áž€ážŸáž¶ážš PDF
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} ចំណារ​ពន្យល់]
+password_label=បញ្ចូល​ពាក្យសម្ងាážáŸ‹â€‹ážŠáž¾áž˜áŸ’បី​បើក​ឯកសារ PDF áž“áŸáŸ‡áŸ”
+password_invalid=ពាក្យសម្ងាážáŸ‹â€‹áž˜áž·áž“​ážáŸ’រឹមážáŸ’រូវ។ សូម​ព្យាយាម​ម្ដងទៀážáŸ”
+password_ok=យល់​ព្រម
+password_cancel=បោះបង់
+
+printing_not_supported=ការ​ព្រមាន ៖ កា​រ​បោះពុម្ព​មិន​ážáŸ’រូវ​បាន​គាំទ្រ​ពáŸáž‰áž›áŸáž‰â€‹ážŠáŸ„យ​កម្មវិធី​រុករក​នáŸáŸ‡â€‹áž‘áŸÂ ។
+printing_not_ready=ព្រមាន៖ PDF មិន​ážáŸ’រូវ​បាន​ផ្ទុក​ទាំងស្រុង​ដើម្បី​បោះពុម្ព​ទáŸáŸ”
+web_fonts_disabled=បាន​បិទ​ពុម្ពអក្សរ​បណ្ដាញ ៖ មិន​អាច​ប្រើ​ពុម្ពអក្សរ PDF ដែល​បាន​បង្កប់​បាន​ទáŸÂ ។
+document_colors_disabled=ឯកសារ PDF មិន​ážáŸ’រូវ​បាន​អនុញ្ញាážâ€‹áž²áŸ’យ​ប្រើ​ពណ៌​ផ្ទាល់​របស់​វា​ទáŸáŸ– 'អនុញ្ញាážâ€‹â€‹áž²áŸ’យ​ទំពáŸážšâ€‹áž‡áŸ’រើស​ពណ៌​ផ្ទាល់​ážáŸ’លួន' ážáŸ’រូវ​បាន​ធ្វើ​ឲ្យ​អសកម្ម​ក្នុង​​កម្មវិធី​រុករក។
diff --git a/static/pdf.js/locale/kn/viewer.properties b/static/pdf.js/locale/kn/viewer.properties
new file mode 100644
index 000000000..695803735
--- /dev/null
+++ b/static/pdf.js/locale/kn/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=ಹಿಂದಿನ ಪà³à²Ÿ
+previous_label=ಹಿಂದಿನ
+next.title=ಮà³à²‚ದಿನ ಪà³à²Ÿ
+next_label=ಮà³à²‚ದಿನ
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=ಪà³à²Ÿ:
+page_of={{pageCount}} ರಲà³à²²à²¿
+
+zoom_out.title=ಕಿರಿದಾಗಿಸà³
+zoom_out_label=ಕಿರಿದಾಗಿಸಿ
+zoom_in.title=ಹಿರಿದಾಗಿಸà³
+zoom_in_label=ಹಿರಿದಾಗಿಸಿ
+zoom.title=ಗಾತà³à²°à²¬à²¦à²²à²¿à²¸à³
+presentation_mode.title=ಪà³à²°à²¸à³à²¤à³à²¤à²¿ (ಪà³à²°à²¸à³†à²‚ಟೇಶನà³) ಕà³à²°à²®à²•à³à²•à³† ಬದಲಾಯಿಸà³
+presentation_mode_label=ಪà³à²°à²¸à³à²¤à³à²¤à²¿ (ಪà³à²°à²¸à³†à²‚ಟೇಶನà³) ಕà³à²°à²®
+open_file.title=ಕಡತವನà³à²¨à³ ತೆರೆ
+open_file_label=ತೆರೆಯಿರಿ
+print.title=ಮà³à²¦à³à²°à²¿à²¸à³
+print_label=ಮà³à²¦à³à²°à²¿à²¸à²¿
+download.title=ಇಳಿಸà³
+download_label=ಇಳಿಸಿಕೊಳà³à²³à²¿
+bookmark.title=ಪà³à²°à²¸à²•à³à²¤ ನೋಟ (ಪà³à²°à²¤à²¿ ಮಾಡೠಅಥವ ಹೊಸ ಕಿಟಕಿಯಲà³à²²à²¿ ತೆರೆ)
+bookmark_label=ಪà³à²°à²¸à²•à³à²¤ ನೋಟ
+
+# Secondary toolbar and context menu
+tools.title=ಉಪಕರಣಗಳà³
+tools_label=ಉಪಕರಣಗಳà³
+first_page.title=ಮೊದಲ ಪà³à²Ÿà²•à³à²•à³† ತೆರಳà³
+first_page.label=ಮೊದಲ ಪà³à²Ÿà²•à³à²•à³† ತೆರಳà³
+first_page_label=ಮೊದಲ ಪà³à²Ÿà²•à³à²•à³† ತೆರಳà³
+last_page.title=ಕೊನೆಯ ಪà³à²Ÿà²•à³à²•à³† ತೆರಳà³
+last_page.label=ಕೊನೆಯ ಪà³à²Ÿà²•à³à²•à³† ತೆರಳà³
+last_page_label=ಕೊನೆಯ ಪà³à²Ÿà²•à³à²•à³† ತೆರಳà³
+page_rotate_cw.title=ಪà³à²°à²¦à²•à³à²·à²¿à²£à³†à²¯à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³
+page_rotate_cw.label=ಪà³à²°à²¦à²•à³à²·à²¿à²£à³†à²¯à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³
+page_rotate_cw_label=ಪà³à²°à²¦à²•à³à²·à²¿à²£à³†à²¯à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³
+page_rotate_ccw.title=ಅಪà³à²°à²¦à²•à³à²·à²¿à²£à³†à²¯à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³
+page_rotate_ccw.label=ಅಪà³à²°à²¦à²•à³à²·à²¿à²£à³†à²¯à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³
+page_rotate_ccw_label=ಅಪà³à²°à²¦à²•à³à²·à²¿à²£à³†à²¯à²²à³à²²à²¿ ತಿರà³à²—ಿಸà³
+
+hand_tool_enable.title=ಕೈ ಉಪಕರಣವನà³à²¨à³ ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸà³
+hand_tool_enable_label=ಕೈ ಉಪಕರಣವನà³à²¨à³ ಸಕà³à²°à²¿à²¯à²—ೊಳಿಸà³
+hand_tool_disable.title=ಕೈ ಉಪಕರಣವನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸà³
+hand_tool_disable_label=ಕೈ ಉಪಕರಣವನà³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸà³
+
+# Document properties dialog box
+document_properties.title=ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಗà³à²£à²—ಳà³...
+document_properties_label=ಡಾಕà³à²¯à³à²®à³†à²‚ಟà³â€Œ ಗà³à²£à²—ಳà³...
+document_properties_file_name=ಕಡತದ ಹೆಸರà³:
+document_properties_file_size=ಕಡತದ ಗಾತà³à²°:
+document_properties_kb={{size_kb}} KB ({{size_b}} ಬೈಟà³â€à²—ಳà³)
+document_properties_mb={{size_mb}} MB ({{size_b}} ಬೈಟà³â€à²—ಳà³)
+document_properties_title=ಶೀರà³à²·à²¿à²•à³†:
+document_properties_author=ಕರà³à²¤à³ƒ:
+document_properties_subject=ವಿಷಯ:
+document_properties_keywords=ಮà³à²–à³à²¯à²ªà²¦à²—ಳà³:
+document_properties_creation_date=ರಚಿಸಿದ ದಿನಾಂಕ:
+document_properties_modification_date=ಮಾರà³à²ªà²¡à²¿à²¸à²²à²¾à²¦ ದಿನಾಂಕ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ರಚಿಸಿದವರà³:
+document_properties_producer=PDF ಉತà³à²ªà²¾à²¦à²•:
+document_properties_version=PDF ಆವೃತà³à²¤à²¿:
+document_properties_page_count=ಪà³à²Ÿà²¦ ಎಣಿಕೆ:
+document_properties_close=ಮà³à²šà³à²šà³
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=ಬದಿಪಟà³à²Ÿà²¿à²¯à²¨à³à²¨à³ ಹೊರಳಿಸà³
+toggle_sidebar_label=ಬದಿಪಟà³à²Ÿà²¿à²¯à²¨à³à²¨à³ ಹೊರಳಿಸà³
+outline.title=ದಸà³à²¤à²¾à²µà³‡à²œà²¿à²¨ ಹೊರರೇಖೆಯನà³à²¨à³ ತೋರಿಸà³
+outline_label=ದಸà³à²¤à²¾à²µà³‡à²œà²¿à²¨ ಹೊರರೇಖೆ
+attachments.title=ಲಗತà³à²¤à³à²—ಳನà³à²¨à³ ತೋರಿಸà³
+attachments_label=ಲಗತà³à²¤à³à²—ಳà³
+thumbs.title=ಚಿಕà³à²•à²šà²¿à²¤à³à²°à²¦à²‚ತೆ ತೋರಿಸà³
+thumbs_label=ಚಿಕà³à²•à²šà²¿à²¤à³à²°à²—ಳà³
+findbar.title=ದಸà³à²¤à²¾à²µà³‡à²œà²¿à²¨à²²à³à²²à²¿ ಹà³à²¡à³à²•à³
+findbar_label=ಹà³à²¡à³à²•à³
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=ಪà³à²Ÿ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=ಪà³à²Ÿà²µà²¨à³à²¨à³ ಚಿಕà³à²•à²šà²¿à²¤à³à²°à²¦à²‚ತೆ ತೋರಿಸೠ{{page}}
+
+# Find panel button title and messages
+find_label=ಹà³à²¡à³à²•à³:
+find_previous.title=ವಾಕà³à²¯à²¦ ಹಿಂದಿನ ಇರà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಹà³à²¡à³à²•à³
+find_previous_label=ಹಿಂದಿನ
+find_next.title=ವಾಕà³à²¯à²¦ ಮà³à²‚ದಿನ ಇರà³à²µà²¿à²•à³†à²¯à²¨à³à²¨à³ ಹà³à²¡à³à²•à³
+find_next_label=ಮà³à²‚ದಿನ
+find_highlight=ಎಲà³à²²à²µà²¨à³à²¨à³ ಹೈಲೈಟೠಮಾಡà³
+find_match_case_label=ಕೇಸನà³à²¨à³ ಹೊಂದಿಸà³
+find_reached_top=ದಸà³à²¤à²¾à²µà³‡à²œà²¿à²¨ ಮೇಲà³à²à²¾à²—ವನà³à²¨à³ ತಲà³à²ªà²¿à²¦à³†, ಕೆಳಗಿನಿಂದ ಆರಂà²à²¿à²¸à³
+find_reached_bottom=ದಸà³à²¤à²¾à²µà³‡à²œà²¿à²¨ ಕೊನೆಯನà³à²¨à³ ತಲà³à²ªà²¿à²¦à³†, ಮೇಲಿನಿಂದ ಆರಂà²à²¿à²¸à³
+find_not_found=ವಾಕà³à²¯à²µà³ ಕಂಡೠಬಂದಿಲà³à²²
+
+# Error panel labels
+error_more_info=ಹೆಚà³à²šà²¿à²¨ ಮಾಹಿತಿ
+error_less_info=ಕಡಿಮೆ ಮಾಹಿತಿ
+error_close=ಮà³à²šà³à²šà³
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=ಸಂದೇಶ: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ರಾಶಿ: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ಕಡತ: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=ಸಾಲà³: {{line}}
+rendering_error=ಪà³à²Ÿà²µà²¨à³à²¨à³ ನಿರೂಪಿಸà³à²µà²¾à²— ಒಂದೠದೋಷ ಎದà³à²°à²¾à²—ಿದೆ.
+
+# Predefined zoom values
+page_scale_width=ಪà³à²Ÿà²¦ ಅಗಲ
+page_scale_fit=ಪà³à²Ÿà²¦ ಸರಿಹೊಂದಿಕೆ
+page_scale_auto=ಸà³à²µà²¯à²‚ಚಾಲಿತ ಗಾತà³à²°à²¬à²¦à²²à²¾à²µà²£à³†
+page_scale_actual=ನಿಜವಾದ ಗಾತà³à²°
+
+# Loading indicator messages
+loading_error_indicator=ದೋಷ
+loading_error=PDF ಅನà³à²¨à³ ಲೋಡೠಮಾಡà³à²µà²¾à²— ಒಂದೠದೋಷ ಎದà³à²°à²¾à²—ಿದೆ.
+invalid_file_error=ಅಮಾನà³à²¯à²µà²¾à²¦ ಅಥವ ಹಾಳಾದ PDF ಕಡತ.
+missing_file_error=PDF ಕಡತ ಇಲà³à²².
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} ಟಿಪà³à²ªà²£à²¿]
+password_label=PDF ಅನà³à²¨à³ ತೆರೆಯಲೠಗà³à²ªà³à²¤à²ªà²¦à²µà²¨à³à²¨à³ ನಮೂದಿಸಿ.
+password_invalid=ಅಮಾನà³à²¯à²µà²¾à²¦ ಗà³à²ªà³à²¤à²ªà²¦, ದಯವಿಟà³à²Ÿà³ ಇನà³à²¨à³Šà²®à³à²®à³† ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿.
+password_ok=OK
+password_cancel=ರದà³à²¦à³ ಮಾಡà³
+
+printing_not_supported=ಎಚà³à²šà²°à²¿à²•à³†: ಈ ಜಾಲವೀಕà³à²·à²•à²¦à²²à³à²²à²¿ ಮà³à²¦à³à²°à²£à²•à³à²•à³† ಸಂಪೂರà³à²£ ಬೆಂಬಲವಿಲà³à²².
+printing_not_ready=ಎಚà³à²šà²°à²¿à²•à³†: PDF ಕಡತವೠಮà³à²¦à³à²°à²¿à²¸à²²à³ ಸಂಪೂರà³à²£à²µà²¾à²—ಿ ಲೋಡೠಆಗಿಲà³à²².
+web_fonts_disabled=ಜಾಲ ಅಕà³à²·à²°à²¶à³ˆà²²à²¿à²¯à²¨à³à²¨à³ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿದೆ: ಅಡಕಗೊಳಿಸಿದ PDF ಅಕà³à²·à²°à²¶à³ˆà²²à²¿à²—ಳನà³à²¨à³ ಬಳಸಲೠಸಾಧà³à²¯à²µà²¾à²—ಿಲà³à²².
+document_colors_disabled=PDF ದಸà³à²¤à²¾à²µà³‡à²œà³à²—ಳೠತಮà³à²®à²¦à³† ಆದ ಬಣà³à²£à²—ಳನà³à²¨à³ ಬಳಸಲೠಅನà³à²®à²¤à²¿ ಇರà³à²µà³à²¦à²¿à²²à³à²²: 'ಪà³à²Ÿà²—ಳೠತಮà³à²®à²¦à³† ಆದ ಬಣà³à²£à²µà²¨à³à²¨à³ ಆಯà³à²•à³† ಮಾಡಲೠಅನà³à²®à²¤à²¿à²¸à³' ಅನà³à²¨à³ ಜಾಲವೀಕà³à²·à²•à²¦à²²à³à²²à²¿ ನಿಷà³à²•à³à²°à²¿à²¯à²—ೊಳಿಸಲಾಗಿರà³à²¤à³à²¤à²¦à³†.
diff --git a/static/pdf.js/locale/ko/viewer.properties b/static/pdf.js/locale/ko/viewer.properties
index 4454f822d..282be99d2 100644
--- a/static/pdf.js/locale/ko/viewer.properties
+++ b/static/pdf.js/locale/ko/viewer.properties
@@ -13,87 +13,116 @@
# limitations under the License.
# Main toolbar buttons (tooltips and alt text for images)
-previous.title=ì´ì „ 쪽
+previous.title=ì´ì „ 페ì´ì§€
previous_label=ì´ì „
-next.title=ë‹¤ìŒ ìª½
+next.title=ë‹¤ìŒ íŽ˜ì´ì§€
next_label=다ìŒ
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
-page_label=쪽:
-page_of=/ {{pageCount}}
+page_label=페ì´ì§€:
+page_of=/{{pageCount}}
zoom_out.title=축소
zoom_out_label=축소
zoom_in.title=확대
zoom_in_label=확대
-zoom.title=확대 비율
-presentation_mode.title=í”„ë ˆì í…Œì´ì…˜ 모드로 ì „í™˜
-presentation_mode_label=í”„ë ˆì í…Œì´ì…˜ 모드
+zoom.title=í¬ê¸°
+print.title=ì¸ì‡„
+print_label=ì¸ì‡„
+presentation_mode.title=발표 모드로 ì „í™˜
+presentation_mode_label=발표 모드
open_file.title=íŒŒì¼ ì—´ê¸°
open_file_label=열기
-print.title=ì¶œë ¥
-print_label=ì¶œë ¥
-download.title=ë‚´ë ¤ë°›ê¸°
-download_label=ë‚´ë ¤ë°›ê¸°
-bookmark.title=현 화면 (복사하거나 새 ì°½ì—ì„œ 열기)
-bookmark_label=현 화면
+download.title=다운로드
+download_label=다운로드
+bookmark.title=지금 ë³´ì´ëŠ” 그대로 (복사하거나 새 ì°½ì— ì—´ê¸°)
+bookmark_label=지금 ë³´ì´ëŠ” 그대로
# Secondary toolbar and context menu
-first_page.title=첫 쪽으로
-first_page.label=첫 쪽으로
-first_page_label=첫 쪽으로
-last_page.title=ë 쪽으로
-last_page.label=ë 쪽으로
-last_page_label=ë 쪽으로
-page_rotate_cw.title=시계방향 íšŒì „
-page_rotate_cw.label=시계방향 íšŒì „
-page_rotate_cw_label=시계방향 íšŒì „
-page_rotate_ccw.title=반시계방향 íšŒì „
-page_rotate_ccw.label=반시계방향 íšŒì „
-page_rotate_ccw_label=반시계방향 íšŒì „
+tools.title=ë„구
+tools_label=ë„구
+first_page.title=첫 페ì´ì§€ë¡œ ì´ë™
+first_page.label=첫 페ì´ì§€ë¡œ ì´ë™
+first_page_label=첫 페ì´ì§€ë¡œ ì´ë™
+last_page.title=마지막 페ì´ì§€ë¡œ ì´ë™
+last_page.label=마지막 페ì´ì§€ë¡œ ì´ë™
+last_page_label=마지막 페ì´ì§€ë¡œ ì´ë™
+page_rotate_cw.title=시계방향으로 íšŒì „
+page_rotate_cw.label=시계방향으로 íšŒì „
+page_rotate_cw_label=시계방향으로 íšŒì „
+page_rotate_ccw.title=시계 반대방향으로 íšŒì „
+page_rotate_ccw.label=시계 반대방향으로 íšŒì „
+page_rotate_ccw_label=시계 반대방향으로 íšŒì „
+
+hand_tool_enable.title=ì† ë„구 켜기
+hand_tool_enable_label=ì† ë„구 켜기
+hand_tool_disable.title=ì† ë„구 ë„기
+hand_tool_disable_label=ì† ë„구 ë„기
+
+# Document properties dialog box
+document_properties.title=문서 ì†ì„±â€¦
+document_properties_label=문서 ì†ì„±â€¦
+document_properties_file_name=íŒŒì¼ ì´ë¦„:
+document_properties_file_size=íŒŒì¼ ì‚¬ì´ì¦ˆ:
+document_properties_kb={{size_kb}} KB ({{size_b}}ë°”ì´íŠ¸)
+document_properties_mb={{size_mb}} MB ({{size_b}}ë°”ì´íŠ¸)
+document_properties_title=ì œëª©:
+document_properties_author=ì €ìž:
+document_properties_subject=ì£¼ì œ:
+document_properties_keywords=키워드:
+document_properties_creation_date=ìƒì„±ì¼:
+document_properties_modification_date=ìˆ˜ì •ì¼:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ìƒì„±ìž:
+document_properties_producer=PDF ìƒì„±ê¸°:
+document_properties_version=PDF ë²„ì „:
+document_properties_page_count=ì´ íŽ˜ì´ì§€:
+document_properties_close=닫기
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=사ì´ë“œë°” ë³´ì´ê¸°/숨기기
-toggle_sidebar_label=사ì´ë“œë°” ë³´ì´ê¸°/숨기기
-outline.title=문서 개요 ë³´ì´ê¸°
+toggle_sidebar.title=íƒìƒ‰ì°½ ì—´ê³ ë‹«ê¸°
+toggle_sidebar_label=íƒìƒ‰ì°½ ì—´ê³ ë‹«ê¸°
+outline.title=문서 개요 보기
outline_label=문서 개요
-thumbs.title=쪽 작게 보기
-thumbs_label=쪽 작게 보기
-findbar.title=문서 ë‚´ì—ì„œ 찾기
-findbar_label=찾기
+attachments.title=ì²¨ë¶€íŒŒì¼ ë³´ê¸°
+attachments_label=첨부파ì¼
+thumbs.title=미리보기
+thumbs_label=미리보기
+findbar.title=검색
+findbar_label=검색
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
# number.
-thumb_page_title={{page}} 쪽
+thumb_page_title={{page}}쪽
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas={{page}}ìª½ì˜ ì¸ë„¤ì¼
+thumb_page_canvas={{page}}쪽 미리보기
# Find panel button title and messages
-find_label=찾기:
-find_previous.title=ì´ì „ êµ¬ì ˆ 찾기
+find_label=검색:
+find_previous.title=ì§€ì • 문ìžì—´ì— ì¼ì¹˜í•˜ëŠ” 1ê°œ ë¶€ë¶„ì„ ê²€ìƒ‰
find_previous_label=ì´ì „
-find_next.title=ë‹¤ìŒ êµ¬ì ˆ 찾기
+find_next.title=ì§€ì • 문ìžì—´ì— ì¼ì¹˜í•˜ëŠ” ë‹¤ìŒ ë¶€ë¶„ì„ ê²€ìƒ‰
find_next_label=다ìŒ
-find_highlight=ëª¨ë‘ ê°•ì¡°
-find_match_case_label=대/소문ìžê¹Œì§€ ì •í™•ížˆ
-find_reached_top=ë¬¸ì„œì˜ ì²˜ìŒ, ëì—서부터 계ì†
-find_reached_bottom=ë¬¸ì„œì˜ ë, 처ìŒì—서부터 계ì†
-find_not_found=êµ¬ì ˆì„ ì°¾ì„ ìˆ˜ 없습니다
+find_highlight=ëª¨ë‘ ê°•ì¡° 표시
+find_match_case_label=대문ìž/ì†Œë¬¸ìž êµ¬ë³„
+find_reached_top=문서 처ìŒê¹Œì§€ ê²€ìƒ‰í•˜ê³ ë으로 ëŒì•„와 검색했습니다.
+find_reached_bottom=문서 ë까지 ê²€ìƒ‰í•˜ê³ ì•žìœ¼ë¡œ ëŒì•„와 검색했습니다.
+find_not_found=검색 ê²°ê³¼ ì—†ìŒ
# Error panel labels
-error_more_info=ë” ë³´ê¸°
-error_less_info=간략히
+error_more_info=ì •ë³´ ë” ë³´ê¸°
+error_less_info=ì •ë³´ 간단히 보기
error_close=닫기
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (build: {{build}})
+error_version_info=PDF.js v{{version}} (빌드: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
error_message=메시지: {{message}}
@@ -103,29 +132,32 @@ error_stack=스íƒ: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=파ì¼: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=í–‰: {{line}}
-rendering_error=쪽 ë Œë”ë§ ì¤‘ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.
+error_line=줄 번호: {{line}}
+rendering_error=페ì´ì§€ë¥¼ ë Œë”ë§í•˜ë‹¤ 오류가 났습니다.
# Predefined zoom values
-page_scale_width=너비 맞춤
-page_scale_fit=쪽 맞춤
-page_scale_auto=ìžë™ 맞춤
-page_scale_actual=ì‹¤ì œ í¬ê¸°
+page_scale_width=페ì´ì§€ ë„ˆë¹„ì— ë§žì¶¤
+page_scale_fit=페ì´ì§€ì— 맞춤
+page_scale_auto=알아서 맞춤
+page_scale_actual=ì‹¤ì œ í¬ê¸°ì— 맞춤
# Loading indicator messages
loading_error_indicator=오류
-loading_error=PDF를 ë¶ˆëŸ¬ì˜¤ë˜ ì¤‘ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.
-invalid_file_error=PDF 파ì¼ì´ 아니거나 깨진 파ì¼ìž…니다.
+loading_error=PDF를 ì½ëŠ” 중 오류가 ìƒê²¼ìŠµë‹ˆë‹¤.
+invalid_file_error=ìœ íš¨í•˜ì§€ 않거나 파ì†ëœ PDF 파ì¼
missing_file_error=PDF 파ì¼ì´ 없습니다.
# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
-# "{{type}}" will be replaced with an annotation type from a list defined in
+# "{{[type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Annotation]
-request_password=암호로 보호ë˜ëŠ” PDF파ì¼ìž…니다:
+text_annotation_type.alt=[{{type}} 주ì„]
+password_label=ì´ PDF 파ì¼ì„ ì—´ 수 있는 암호를 ìž…ë ¥í•˜ì‹ì‹œì˜¤.
+password_invalid=ìž˜ëª»ëœ ì•”í˜¸ìž…ë‹ˆë‹¤. 다시 ì‹œë„í•´ 주ì‹ì‹œì˜¤.
+password_ok=확ì¸
+password_cancel=취소
-printing_not_supported=ê²½ê³ : ì´ ë¸Œë¼ìš°ì ¸ëŠ” ì¶œë ¥ì„ ì™„ì „ížˆëŠ” 지ì›í•˜ì§€ 않습니다.
-printing_not_ready=ê²½ê³ : ì´ PDF 파ì¼ì€ ì™„ì „ížˆ ì 재ë˜ì§€ 않았습니다.
-web_fonts_disabled=웹 í°íŠ¸ ì‚¬ìš©ì´ ë¹„í™œì„±ë˜ì—ˆìŠµë‹ˆë‹¤: 내장 PDF í°íŠ¸ë¥¼ ì‚¬ìš©í• ìˆ˜ 없습니다.
-web_colors_disabled=웹 컬러가 비활성ë˜ì—ˆìŠµë‹ˆë‹¤.
+printing_not_supported=ê²½ê³ : ì´ ë¸Œë¼ìš°ì €ëŠ” ì¸ì‡„를 ì™„ì „ížˆ 지ì›í•˜ì§€ 않습니다.
+printing_not_ready=ê²½ê³ : ì´ PDF를 ì¸ì‡„를 í• ìˆ˜ ìžˆì„ ì •ë„ë¡œ ì½ì–´ë“¤ì´ì§€ 못했습니다.
+web_fonts_disabled=웹 í°íŠ¸ê°€ êº¼ì ¸ìžˆìŒ: ë‚´ìž¥ëœ PDF ê¸€ê¼´ì„ ì“¸ 수 없습니다.
+document_colors_disabled=PDF ë¬¸ì„œì˜ ìƒ‰ìƒì„ 쓰지 못하게 ë˜ì–´ 있ìŒ: \'웹 페ì´ì§€ ìžì²´ ìƒ‰ìƒ ì‚¬ìš© 허용\'ì´ ë¸Œë¼ìš°ì €ì—ì„œ êº¼ì ¸ 있습니다.
diff --git a/static/pdf.js/locale/ku/viewer.properties b/static/pdf.js/locale/ku/viewer.properties
new file mode 100644
index 000000000..c614fa153
--- /dev/null
+++ b/static/pdf.js/locale/ku/viewer.properties
@@ -0,0 +1,139 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Rûpela berê
+previous_label=PaÅŸve
+next.title=Rûpela pêş
+next_label=Pêş
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Rûpel:
+page_of=/ {{pageCount}}
+
+zoom_out.title=Dûr bike
+zoom_out_label=Dûr bike
+zoom_in.title=Nêzîk bike
+zoom_in_label=Nêzîk bike
+zoom.title=Nêzîk Bike
+presentation_mode.title=Derbasî mûda pêşkêşkariyê bibe
+presentation_mode_label=Moda Pêşkêşkariyê
+open_file.title=Pelî veke
+open_file_label=Veke
+print.title=Çap bike
+print_label=Çap bike
+download.title=Jêbar bike
+download_label=Jêbar bike
+bookmark.title=Xuyakirina niha (kopî yan jî di pencereyeke nû de veke)
+bookmark_label=Xuyakirina niha
+
+# Secondary toolbar and context menu
+tools.title=Amûr
+tools_label=Amûr
+first_page.title=Here rûpela yekemîn
+first_page.label=Here rûpela yekemîn
+first_page_label=Here rûpela yekemîn
+last_page.title=Here rûpela dawîn
+last_page.label=Here rûpela dawîn
+last_page_label=Here rûpela dawîn
+page_rotate_cw.title=Bi aliyê saetê ve bizivirîne
+page_rotate_cw.label=Bi aliyê saetê ve bizivirîne
+page_rotate_cw_label=Bi aliyê saetê ve bizivirîne
+page_rotate_ccw.title=Berevajî aliyê saetê ve bizivirîne
+page_rotate_ccw.label=Berevajî aliyê saetê ve bizivirîne
+page_rotate_ccw_label=Berevajî aliyê saetê ve bizivirîne
+
+
+# Document properties dialog box
+document_properties_title=Sernav:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Darikê kêlekê veke/bigire
+toggle_sidebar_label=Darikê kêlekê veke/bigire
+outline.title=Şemaya belgeyê nîşan bide
+outline_label=Şemaya belgeyê
+thumbs.title=Wênekokan nîşan bide
+thumbs_label=Wênekok
+findbar.title=Di belgeyê de bibîne
+findbar_label=Bibîne
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Rûpel {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Wênekoka rûpelê {{page}}
+
+# Find panel button title and messages
+find_label=Bibîne:
+find_previous.title=Peyva berê bibîne
+find_previous_label=PaÅŸve
+find_next.title=Peyya pêş bibîne
+find_next_label=Pêşve
+find_highlight=Tevî beloq bike
+find_match_case_label=Ji bo tîpên hûrdek-girdek bihîstyar
+find_reached_top=Gihîşt serê rûpelê, ji dawiya rûpelê bidomîne
+find_reached_bottom=Gihîşt dawiya rûpelê, ji serê rûpelê bidomîne
+find_not_found=Peyv nehat dîtin
+
+# Error panel labels
+error_more_info=Zêdetir agahî
+error_less_info=Zêdetir agahî
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js versiyon {{version}} (avanî: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Peyam: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Komik: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Pel: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rêzik: {{line}}
+rendering_error=Di vehûrandina rûpelê de çewtî çêbû.
+
+# Predefined zoom values
+page_scale_width=Firehiya rûpelê
+page_scale_fit=Di rûpelê de bicî bike
+page_scale_auto=Xweber nêzîk bike
+page_scale_actual=Mezinahiya rastîn
+
+# Loading indicator messages
+loading_error_indicator=Xeletî
+loading_error=Dema ku PDF dihat barkirin çewtiyek çêbû.
+invalid_file_error=Pelê PDFê nederbasdar yan jî xirabe ye.
+missing_file_error=Pelê PDFê kêm e.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Nîşaneya {{type}}ê]
+password_label=Ji bo PDFê vekî şîfreyê binivîse.
+password_invalid=Şîfre çewt e. Tika ye dîsa biceribîne.
+password_ok=Temam
+password_cancel=Betal
+
+printing_not_supported=Hişyarî: Çapkirin ji hêla vê gerokê ve bi temamî nayê destekirin.
+printing_not_ready=Hişyarî: PDF bi temamî nehat barkirin û ji bo çapê ne amade ye.
+web_fonts_disabled=Fontên Webê neçalak in: Fontên PDFê yên veşartî nayên bikaranîn.
+document_colors_disabled=Destûr tune ye ku belgeyên PDFê rengên xwe bi kar bînin: Di gerokê de 'destûrê bide rûpelan ku rengên xwe bi kar bînin' nehatiye çalakirin.
diff --git a/static/pdf.js/locale/lg/viewer.properties b/static/pdf.js/locale/lg/viewer.properties
new file mode 100644
index 000000000..5c88487a9
--- /dev/null
+++ b/static/pdf.js/locale/lg/viewer.properties
@@ -0,0 +1,103 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Omuko Ogubadewo
+next.title=Omuko Oguddako
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Omuko:
+page_of=ku {{pageCount}}
+
+zoom_out.title=Zimbulukusa
+zoom_out_label=Zimbulukusa
+zoom_in.title=Funza Munda
+zoom_in_label=Funza Munda
+zoom.title=Gezzamu
+open_file.title=Bikula Fayiro
+open_file_label=Ggulawo
+print.title=Fulumya
+print_label=Fulumya
+download.title=Tikula
+download_label=Tikula
+bookmark.title=Endabika eriwo (koppa oba gulawo mu diriisa epya)
+bookmark_label=Endabika Eriwo
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+outline.title=Laga Ensalo ze Kiwandiko
+outline_label=Ensalo ze Ekiwandiko
+thumbs.title=Laga Ekifanyi Mubufunze
+thumbs_label=Ekifanyi Mubufunze
+findbar_label=Zuula
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Omuko {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Ekifananyi kyo Omuko Mubufunze {{page}}
+
+# Find panel button title and messages
+find_previous.title=Zuula awayise mukweddamu mumiteddera
+find_next.title=Zuula ekidako mukweddamu mumiteddera
+find_highlight=Londa byonna
+find_not_found=Emiteddera tezuuliddwa
+
+# Error panel labels
+error_more_info=Ebisingawo
+error_less_info=Mubumpimpi
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Obubaaka: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Ebipangiddwa: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fayiro {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Layini: {{line}}
+rendering_error=Wabadewo ensobi muku tekawo omuko.
+
+# Predefined zoom values
+page_scale_width=Obugazi bwo Omuko
+page_scale_fit=Okutuka kwo Omuko
+page_scale_auto=Okwefunza no Kwegeza
+page_scale_actual=Obunene Obutufu
+
+# Loading indicator messages
+loading_error_indicator=Ensobi
+loading_error=Wabadewo ensobi mukutika PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Enyonyola]
+password_ok=OK
+password_cancel=Sazaamu
+
+printing_not_supported=Okulaabula: Okulumya empapula tekuwagirwa enonyeso enno.
diff --git a/static/pdf.js/locale/lij/viewer.properties b/static/pdf.js/locale/lij/viewer.properties
new file mode 100644
index 000000000..dbab0a7ba
--- /dev/null
+++ b/static/pdf.js/locale/lij/viewer.properties
@@ -0,0 +1,116 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+previous.title = Pà gina precedénte
+previous_label = Precedénte
+next.title = Pà gina dòppo
+next_label = Pròscima
+page_label = PÃ gina:
+page_of = de {{pageCount}}
+zoom_out.title = Diminoìsci zoom
+zoom_out_label = Diminoìsci zoom
+zoom_in.title = Aoménta zoom
+zoom_in_label = Aoménta zoom
+zoom.title = Zoom
+print.title = Stà npa
+print_label = Stà npa
+open_file.title = Àrvi file
+open_file_label = Àrvi
+download.title = Descaregaménto
+download_label = Descaregaménto
+bookmark.title = Vixón corénte (còpia ò à rvi inte 'n nêuvo barcón)
+bookmark_label = Vixón corénte
+outline.title = Véddi strutûa documénto
+outline_label = Strutûa documénto
+thumbs.title = Móstra miniatûe
+thumbs_label = Miniatûe
+thumb_page_title = PÃ gina {{page}}
+thumb_page_canvas = Miniatûa da pà gina {{page}}
+error_more_info = Ciù informaçioìn
+error_less_info = Mêno informaçioìn
+error_version_info = PDF.js v{{version}} (build: {{build}})
+error_close = Særa
+missing_file_error = O file PDF o no gh'é.
+toggle_sidebar.title = Atîva/dizatîva bâra de scià nco
+toggle_sidebar_label = Atîva/dizatîva bâra de scià nco
+error_message = Mesà ggio: {{message}}
+error_stack = Stack: {{stack}}
+error_file = File: {{file}}
+error_line = Lìnia: {{line}}
+rendering_error = Gh'é stæto 'n'erô itno rendering da pà gina.
+page_scale_width = Larghéssa pà gina
+page_scale_fit = Adà tta a una pà gina
+page_scale_auto = Zoom aotomà tico
+page_scale_actual = Dimenscioìn efetîve
+loading_error_indicator = Erô
+loading_error = S'é verificòu 'n'erô itno caregaménto do PDF.
+printing_not_supported = Atençión: a stà npa a no l'é conpletaménte soportâ da sto navegatô.
+
+# Context menu
+page_rotate_cw.label=Gîa in sénso do reléuio
+page_rotate_ccw.label=Gîa in sénso do reléuio a-a revèrsa
+
+presentation_mode.title=Và nni into mòddo de prezentaçión
+presentation_mode_label=Mòddo de prezentaçión
+
+find_label = Trêuva:
+find_previous.title = Trêuva a ripetiçión precedénte do tèsto da çercâ
+find_previous_label = Precedénte
+find_next.title = Trêuva a ripetiçión dòppo do tèsto da çercâ
+find_next_label = Segoénte
+find_highlight = Evidénçia
+find_match_case_label = Maióscole/minóscole
+find_reached_bottom = Razónto l'inìçio da pà gina, contìnoa da-a fìn
+find_reached_top = Razónto a fìn da pà gina, contìnoa da l'inìçio
+find_not_found = Tèsto no trovòu
+findbar.title = Trêuva into documénto
+findbar_label = Trêuva
+first_page.label = Và nni a-a prìmma pà gina
+last_page.label = Và nni a l'ùrtima pà gina
+invalid_file_error = O file PDF o l'é no và lido ò aroinòu.
+
+web_fonts_disabled = I font do web én dizativæ: inposcìbile adêuviâ i carà teri do PDF.
+printing_not_ready = Atençión: o PDF o no l'é ancón caregòu conpletaménte pe-a stà npa.
+
+document_colors_disabled = No l'é poscìbile adêuviâ i pròpi coî pe-i documénti PDF: l'opçión do navegatô 'Permètti a-e pà gine de çèrne i pròpi coî in cà ngio de quélli inpostæ' a l'é dizativâ.
+text_annotation_type.alt = [Anotaçión: {{type}}]
+
+first_page.title = Và nni a-a prìmma pà gina
+first_page_label = Và nni a-a prìmma pà gina
+last_page.title = Và nni a l'ùrtima pà gina
+last_page_label = Và nni a l'ùrtima pà gina
+page_rotate_ccw.title = Gîa into vèrso antiorâio
+page_rotate_ccw_label = Gîa into vèrso antiorâio
+page_rotate_cw.title = Gîa into vèrso orâio
+page_rotate_cw_label = Gîa into vèrso orâio
+tools.title = Struménti
+tools_label = Struménti
+password_label = Dìmme a paròlla segrêta pe arvî sto file PDF.
+password_invalid = Paròlla segrêta sbaliâ. Prêuva tórna.
+password_ok = Va bén
+password_cancel = Anùlla
+
+document_properties.title = Propietæ do documénto…
+document_properties_label = Propietæ do documénto…
+document_properties_file_name = Nómme file:
+document_properties_file_size = Dimensción file:
+document_properties_kb = {{size_kb}} kB ({{size_b}} byte)
+document_properties_mb = {{size_kb}} MB ({{size_b}} byte)
+document_properties_title = Tìtolo:
+document_properties_author = Aotô:
+document_properties_subject = Ogétto:
+document_properties_keywords = Paròlle ciâve:
+document_properties_creation_date = Dæta creaçión:
+document_properties_modification_date = Dæta cangiaménto:
+document_properties_date_string = {{date}}, {{time}}
+document_properties_creator = Aotô originâle:
+document_properties_producer = Produtô PDF:
+document_properties_version = Versción PDF:
+document_properties_page_count = Contézzo pà gine:
+document_properties_close = Særa
+
+hand_tool_enable.title = Atîva struménto mà n
+hand_tool_enable_label = Atîva struménto mà n
+hand_tool_disable.title = Dizatîva struménto mà n
+hand_tool_disable_label = Dizatîva struménto mà n
diff --git a/static/pdf.js/locale/locale.properties b/static/pdf.js/locale/locale.properties
index d70632808..9aded1b59 100644
--- a/static/pdf.js/locale/locale.properties
+++ b/static/pdf.js/locale/locale.properties
@@ -1,12 +1,54 @@
+[ach]
+@import url(ach/viewer.properties)
+
+[af]
+@import url(af/viewer.properties)
+
+[ak]
+@import url(ak/viewer.properties)
+
+[an]
+@import url(an/viewer.properties)
+
[ar]
@import url(ar/viewer.properties)
+[as]
+@import url(as/viewer.properties)
+
+[ast]
+@import url(ast/viewer.properties)
+
+[az]
+@import url(az/viewer.properties)
+
+[be]
+@import url(be/viewer.properties)
+
+[bg]
+@import url(bg/viewer.properties)
+
+[bn-BD]
+@import url(bn-BD/viewer.properties)
+
+[bn-IN]
+@import url(bn-IN/viewer.properties)
+
+[br]
+@import url(br/viewer.properties)
+
+[bs]
+@import url(bs/viewer.properties)
+
[ca]
@import url(ca/viewer.properties)
[cs]
@import url(cs/viewer.properties)
+[csb]
+@import url(csb/viewer.properties)
+
[cy]
@import url(cy/viewer.properties)
@@ -19,41 +61,161 @@
[el]
@import url(el/viewer.properties)
+[en-GB]
+@import url(en-GB/viewer.properties)
+
[en-US]
@import url(en-US/viewer.properties)
-[es]
-@import url(es/viewer.properties)
+[en-ZA]
+@import url(en-ZA/viewer.properties)
+
+[eo]
+@import url(eo/viewer.properties)
+
+[es-AR]
+@import url(es-AR/viewer.properties)
+
+[es-CL]
+@import url(es-CL/viewer.properties)
+
+[es-ES]
+@import url(es-ES/viewer.properties)
+
+[es-MX]
+@import url(es-MX/viewer.properties)
+
+[et]
+@import url(et/viewer.properties)
+
+[eu]
+@import url(eu/viewer.properties)
[fa]
@import url(fa/viewer.properties)
+[ff]
+@import url(ff/viewer.properties)
+
[fi]
@import url(fi/viewer.properties)
[fr]
@import url(fr/viewer.properties)
+[fy-NL]
+@import url(fy-NL/viewer.properties)
+
+[ga-IE]
+@import url(ga-IE/viewer.properties)
+
+[gd]
+@import url(gd/viewer.properties)
+
+[gl]
+@import url(gl/viewer.properties)
+
+[gu-IN]
+@import url(gu-IN/viewer.properties)
+
[he]
@import url(he/viewer.properties)
+[hi-IN]
+@import url(hi-IN/viewer.properties)
+
+[hr]
+@import url(hr/viewer.properties)
+
+[hu]
+@import url(hu/viewer.properties)
+
+[hy-AM]
+@import url(hy-AM/viewer.properties)
+
+[id]
+@import url(id/viewer.properties)
+
+[is]
+@import url(is/viewer.properties)
+
[it]
@import url(it/viewer.properties)
[ja]
@import url(ja/viewer.properties)
+[ka]
+@import url(ka/viewer.properties)
+
+[kk]
+@import url(kk/viewer.properties)
+
+[km]
+@import url(km/viewer.properties)
+
+[kn]
+@import url(kn/viewer.properties)
+
[ko]
@import url(ko/viewer.properties)
+[ku]
+@import url(ku/viewer.properties)
+
+[lg]
+@import url(lg/viewer.properties)
+
+[lij]
+@import url(lij/viewer.properties)
+
[lt]
@import url(lt/viewer.properties)
+[lv]
+@import url(lv/viewer.properties)
+
+[mai]
+@import url(mai/viewer.properties)
+
+[mk]
+@import url(mk/viewer.properties)
+
+[ml]
+@import url(ml/viewer.properties)
+
+[mn]
+@import url(mn/viewer.properties)
+
+[mr]
+@import url(mr/viewer.properties)
+
+[ms]
+@import url(ms/viewer.properties)
+
+[my]
+@import url(my/viewer.properties)
+
+[nb-NO]
+@import url(nb-NO/viewer.properties)
+
[nl]
@import url(nl/viewer.properties)
-[no]
-@import url(no/viewer.properties)
+[nn-NO]
+@import url(nn-NO/viewer.properties)
+
+[nso]
+@import url(nso/viewer.properties)
+
+[oc]
+@import url(oc/viewer.properties)
+
+[or]
+@import url(or/viewer.properties)
+
+[pa-IN]
+@import url(pa-IN/viewer.properties)
[pl]
@import url(pl/viewer.properties)
@@ -61,27 +223,90 @@
[pt-BR]
@import url(pt-BR/viewer.properties)
+[pt-PT]
+@import url(pt-PT/viewer.properties)
+
+[rm]
+@import url(rm/viewer.properties)
+
[ro]
@import url(ro/viewer.properties)
[ru]
@import url(ru/viewer.properties)
+[rw]
+@import url(rw/viewer.properties)
+
+[sah]
+@import url(sah/viewer.properties)
+
+[si]
+@import url(si/viewer.properties)
+
+[sk]
+@import url(sk/viewer.properties)
+
+[sl]
+@import url(sl/viewer.properties)
+
+[son]
+@import url(son/viewer.properties)
+
+[sq]
+@import url(sq/viewer.properties)
+
[sr]
@import url(sr/viewer.properties)
-[sv]
-@import url(sv/viewer.properties)
+[sv-SE]
+@import url(sv-SE/viewer.properties)
+
+[sw]
+@import url(sw/viewer.properties)
+
+[ta]
+@import url(ta/viewer.properties)
+
+[ta-LK]
+@import url(ta-LK/viewer.properties)
+
+[te]
+@import url(te/viewer.properties)
+
+[th]
+@import url(th/viewer.properties)
+
+[tl]
+@import url(tl/viewer.properties)
+
+[tn]
+@import url(tn/viewer.properties)
[tr]
@import url(tr/viewer.properties)
+[uk]
+@import url(uk/viewer.properties)
+
+[ur]
+@import url(ur/viewer.properties)
+
[vi]
@import url(vi/viewer.properties)
+[wo]
+@import url(wo/viewer.properties)
+
+[xh]
+@import url(xh/viewer.properties)
+
[zh-CN]
@import url(zh-CN/viewer.properties)
[zh-TW]
@import url(zh-TW/viewer.properties)
+[zu]
+@import url(zu/viewer.properties)
+
diff --git a/static/pdf.js/locale/lt/viewer.properties b/static/pdf.js/locale/lt/viewer.properties
index a1c35d7b2..e97f0b563 100644
--- a/static/pdf.js/locale/lt/viewer.properties
+++ b/static/pdf.js/locale/lt/viewer.properties
@@ -15,8 +15,8 @@
# Main toolbar buttons (tooltips and alt text for images)
previous.title=Ankstesnis puslapis
previous_label=Ankstesnis
-next.title=Sekantis puslapis
-next_label=Sekantis
+next.title=Kitas puslapis
+next_label=Kitas
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
@@ -25,105 +25,139 @@ next_label=Sekantis
page_label=Puslapis:
page_of=iš {{pageCount}}
-zoom_out.title=Mažinti
-zoom_out_label=Mažinti
-zoom_in.title=Didinti
-zoom_in_label=Didinti
+zoom_out.title=Sumažinti
+zoom_out_label=Sumažinti
+zoom_in.title=Padidinti
+zoom_in_label=Padidinti
zoom.title=Mastelis
-presentation_mode.title=Įjungti pateikimo būseną
-presentation_mode_label=Pateikimo būsena
-open_file.title=Atverti bylÄ…
+presentation_mode.title=Pereiti į pateikties veikseną
+presentation_mode_label=Pateikties veiksena
+open_file.title=Atverti failÄ…
open_file_label=Atverti
print.title=Spausdinti
print_label=Spausdinti
-download.title=Atsiųsti
-download_label=Atsiųsti
-bookmark.title=Dabartinis rodymas (kopijuoti arba atidaryti naudojame lange)
-bookmark_label=Dabartinis rodymas
+download.title=Parsiųsti
+download_label=Parsiųsti
+bookmark.title=Esamojo rodinio saitas (kopijavimui ar atvÄ—rimui kitame lange)
+bookmark_label=Esamasis rodinys
# Secondary toolbar and context menu
-first_page.title=Nukreipimas į pirmą puslapį
-first_page.label=Nukreipimas į pirmą puslapį
-first_page_label=Nukreipimas į pirmą puslapį
-last_page.title=Nukreipimas į paskutinį puslapį
-last_page.label=Nukreipimas į paskutinį puslapį
-last_page_label=Nukreipimas į paskutinį puslapį
-page_rotate_cw.title=Sukimas pagal laikrodžio rodyklę
-page_rotate_cw.label=Sukimas pagal laikrodžio rodyklę
-page_rotate_cw_label=Sukimas pagal laikrodžio rodyklę
-page_rotate_ccw.title=Sukimas prieš laikrodžio rodyklę
-page_rotate_ccw.label=Sukimas prieš laikrodžio rodyklę
-page_rotate_ccw_label=Sukimas prieš laikrodžio rodyklę
+tools.title=PriemonÄ—s
+tools_label=PriemonÄ—s
+first_page.title=Eiti į pirmą puslapį
+first_page.label=Eiti į pirmą puslapį
+first_page_label=Eiti į pirmą puslapį
+last_page.title=Eiti į paskutinį puslapį
+last_page.label=Eiti į paskutinį puslapį
+last_page_label=Eiti į paskutinį puslapį
+page_rotate_cw.title=Pasukti pagal laikrodžio rodyklę
+page_rotate_cw.label=Pasukti pagal laikrodžio rodyklę
+page_rotate_cw_label=Pasukti pagal laikrodžio rodyklę
+page_rotate_ccw.title=Pasukti prieš laikrodžio rodyklę
+page_rotate_ccw.label=Pasukti prieš laikrodžio rodyklę
+page_rotate_ccw_label=Pasukti prieš laikrodžio rodyklę
+
+hand_tool_enable.title=Įgalinti vilkimo veikseną
+hand_tool_enable_label=Įgalinti vilkimo veikseną
+hand_tool_disable.title=IÅ¡jungti vilkimo veiksenÄ…
+hand_tool_disable_label=IÅ¡jungti vilkimo veiksenÄ…
+
+# Document properties dialog box
+document_properties.title=Dokumento savybės…
+document_properties_label=Dokumento savybės…
+document_properties_file_name=Failo vardas:
+document_properties_file_size=Failo dydis:
+document_properties_kb={{size_kb}} KB ({{size_b}} B)
+document_properties_mb={{size_mb}} MB ({{size_b}} B)
+document_properties_title=Antraštė:
+document_properties_author=Autorius:
+document_properties_subject=Tema:
+document_properties_keywords=Reikšminiai žodžiai:
+document_properties_creation_date=Sukūrimo data:
+document_properties_modification_date=Modifikavimo data:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=KÅ«rÄ—jas:
+document_properties_producer=PDF generatorius:
+document_properties_version=PDF versija:
+document_properties_page_count=Puslapių skaiÄius:
+document_properties_close=Užverti
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Perjungti Å¡oninÄ™ juostÄ…
-toggle_sidebar_label=Perjungti Å¡oninÄ™ juostÄ…
-outline.title=Rodyti dokumento turinį
-outline_label=Dokumento turinys
-thumbs.title=Rodyti miniatiūras
+toggle_sidebar.title=Rodyti / slėpti šoninį polangį
+toggle_sidebar_label=Å oninis polangis
+outline.title=Rodyti dokumento metmenis
+outline_label=Dokumento metmenys
+attachments.title=Rodyti priedus
+attachments_label=Priedai
+thumbs.title=Rodyti puslapių miniatiūras
thumbs_label=Miniatiūros
-findbar.title=Paieška dokumente
-findbar_label=Paieška
+findbar.title=Ieškoti dokumente
+findbar_label=Ieškoti
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
# number.
-thumb_page_title=Puslapis {{page}}
+thumb_page_title={{page}} puslapis
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=Miniatūra iš {{page}} puslapio
+thumb_page_canvas={{page}} puslapio miniatiūra
# Find panel button title and messages
-find_label=Paieška:
-find_previous.title=Ankstesnis paieškos atitikmuo
+find_label=Ieškoti:
+find_previous.title=Ieškoti ankstesnio frazės egzemplioriaus
find_previous_label=Ankstesnis
-find_next.title=Sekantis paieškos atitikmuo
-find_next_label=Sekantis
-find_highlight=Pažymėti visus
+find_next.title=Ieškoti tolesnio frazės egzemplioriaus
+find_next_label=Tolesnis
+find_highlight=Viską paryškinti
find_match_case_label=Skirti didžiąsias ir mažąsias raides
-find_reached_top=Pasiektas dokumento virÅ¡us, pradÄ—ti nuo apaÄios
-find_reached_bottom=Pasiekta dokumento apaÄia, pradÄ—ti nuo virÅ¡aus
-find_not_found=Paieškos rezultatų nėra
+find_reached_top=Pasiekus dokumento pradžią, paieška pratęsta nuo pabaigos
+find_reached_bottom=Pasiekus dokumento pabaigą, paieška pratęsta nuo pradžios
+find_not_found=Ieškoma frazė nerasta
# Error panel labels
-error_more_info=Daugiau informacijos
-error_less_info=Mažiau informacijos
-error_close=Uždaryti
+error_more_info=IÅ¡samiau
+error_less_info=GlausÄiau
+error_close=Užverti
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (build: {{build}})
+error_version_info=PDF.js v. {{version}} (darinys: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=Žinutė: {{message}}
+error_message=Pranešimas: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
error_stack=DÄ—klas: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
-error_file=Byla: {{file}}
+error_file=Failas: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=EilutÄ—: {{line}}
-rendering_error=Įvyko klaida atvaizduojant puslapį.
+rendering_error=Atvaizduojant puslapį, įvyko klaida.
# Predefined zoom values
-page_scale_width=Puslapio plotis
-page_scale_fit=Puslapio priderinimas
+page_scale_width=Priderinti prie lapo ploÄio
+page_scale_fit=Pritaikyti prie lapo dydžio
page_scale_auto=Automatinis mastelis
-page_scale_actual=Numatytas dydis
+page_scale_actual=Tikras dydis
# Loading indicator messages
loading_error_indicator=Klaida
-loading_error=PDF bylos įkelimo metu įvyko klaida.
-invalid_file_error=Neteisinga arba pažeista PDF byla.
-missing_file_error=Trūksta PDF bylos.
+loading_error=Įkeliant PDF failą, įvyko klaida.
+invalid_file_error=Tai nÄ—ra PDF failas arba jis yra sugadintas.
+missing_file_error=PDF failas nerastas.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[{{type}} Pastaba]
-request_password=PDF byla yra apsaugota slaptažodžiu:
+text_annotation_type.alt=[„{{type}}“ tipo anotacija]
+password_label=Įveskite slaptažodį šiam PDF failui atverti.
+password_invalid=Slaptažodis neteisingas. Bandykite dar kartą.
+password_ok=Gerai
+password_cancel=Atsisakyti
-printing_not_supported=Dėmesio: Naršyklė pilnai nepalaiko spausdinimo.
-web_fonts_disabled=Yra išjungti žiniatinklio šriftai: naudoti įterpus PDF šriftus nėra galima.
+printing_not_supported=Dėmesio! Spausdinimas šioje naršyklėje nėra pilnai realizuotas.
+printing_not_ready=Dėmesio! PDF failas dar nėra pilnai įkeltas spausdinimui.
+web_fonts_disabled=Neįgalinti saityno Å¡riftai – Å¡iame PDF faile esanÄių Å¡riftų naudoti negalima.
+document_colors_disabled=PDF dokumentams neleidžiama nurodyti savo spalvų, nes išjungta naršyklės nuostata „Leisti tinklalapiams nurodyti spalvas“.
diff --git a/static/pdf.js/locale/lv/viewer.properties b/static/pdf.js/locale/lv/viewer.properties
new file mode 100644
index 000000000..f46f13665
--- /dev/null
+++ b/static/pdf.js/locale/lv/viewer.properties
@@ -0,0 +1,160 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=IepriekÅ¡Ä“jÄ lapa
+previous_label=IepriekÅ¡Ä“jÄ
+next.title=NÄkamÄ lapa
+next_label=NÄkamÄ
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Lapa:
+page_of=no {{pageCount}}
+
+zoom_out.title=AttÄlinÄt
+zoom_out_label=AttÄlinÄt
+zoom_in.title=PietuvinÄt
+zoom_in_label=PietuvinÄt
+zoom.title=PalielinÄjums
+print.title=DrukÄÅ¡ana
+print_label=DrukÄt
+presentation_mode.title=PÄrslÄ“gties uz PrezentÄcijas režīmu
+presentation_mode_label=PrezentÄcijas režīms
+open_file.title=Atvērt failu
+open_file_label=Atvērt
+download.title=LejupielÄde
+download_label=LejupielÄdÄ“t
+bookmark.title=PaÅ¡reizÄ“jais skats (kopÄ“t vai atvÄ“rt jaunÄ logÄ)
+bookmark_label=Pašreizējais skats
+findbar.title=MeklÄ“t dokumentÄ
+findbar_label=Meklēt
+attachments.title=RÄdÄ«t pielikumus
+attachments_label=Pielikumi
+
+
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=PÄrslÄ“gt sÄnu joslu
+toggle_sidebar_label=PÄrslÄ“gt sÄnu joslu
+outline.title=ParÄdÄ«t dokumenta saturu
+outline_label=Dokumenta saturs
+thumbs.title=ParÄdÄ«t sÄ«ktÄ“lus
+thumbs_label=Sīktēli
+
+# Find panel button title and messages
+find_label=Meklēt:
+find_previous.title=Atrast iepriekšējo
+find_previous_label=IepriekÅ¡Ä“jÄ
+find_next.title=Atrast nÄkamo
+find_next_label=NÄkamÄ
+find_highlight=IekrÄsot visas
+find_match_case_label=Lielo, mazo burtu jutīgs
+find_reached_top=Sasniegts dokumenta sÄkums, turpinÄm no beigÄm
+find_reached_bottom=Sasniegtas dokumenta beigas, turpinÄm no sÄkuma
+find_not_found=FrÄze nav atrasta
+first_page.title=Iet uz pirmo lapu
+first_page.label=Iet uz pirmo lapu
+first_page_label=Iet uz pirmo lapu
+last_page.title=Iet uz pēdējo lapu
+last_page.label=Iet uz pēdējo lapu
+last_page_label=Iet uz pēdējo lapu
+tools.title=RÄ«ki
+tools_label=RÄ«ki
+page_rotate_cw.title=Pagriezt pa pulksteni
+page_rotate_cw.label=Pagriezt pa pulksteni
+page_rotate_cw_label=Pagriezt pa pulksteni
+page_rotate_ccw.title=Pagriezt pret pulksteni
+page_rotate_ccw.label=Pagriezt pret pulksteni
+page_rotate_ccw_label=Pagriezt pret pulksteni
+
+# Document properties dialog box
+document_properties.title=Dokumenta iestatījumi…
+document_properties_label=Dokumenta iestatījumi…
+document_properties_file_name=Faila nosaukums:
+document_properties_file_size=Faila izmērs:
+document_properties_kb={{size_kb}} KB ({{size_b}} biti)
+document_properties_mb={{size_mb}} MB ({{size_b}} biti)
+document_properties_title=Nosaukums:
+document_properties_author=Autors:
+document_properties_subject=TÄ“ma:
+document_properties_keywords=AtslÄ“gas vÄrdi:
+document_properties_creation_date=Izveides datums:
+document_properties_modification_date=LAbošanas datums:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=RadÄ«tÄjs:
+document_properties_producer=PDF producents:
+document_properties_version=PDF versija:
+document_properties_page_count=Lapu skaits:
+document_properties_close=Aizvērt
+
+hand_tool_enable.title=Aktivēt rokas rīku
+hand_tool_enable_label=Aktivēt rokas rīku
+hand_tool_disable.title=Deaktivēt rokas rīku
+hand_tool_disable_label=Deaktivēt rokas rīku
+
+invalid_file_error=NederÄ«gs vai bojÄts PDF fails.
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Lapa {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Lapas {{page}} sīktēls
+
+# Error panel labels
+error_more_info=VairÄk informÄcijas
+error_less_info=MAzÄk informÄcijas
+error_close=Close
+
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Ziņojums: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Steks: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=File: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rindiņa: {{line}}
+rendering_error=AttÄ“lojot lapu radÄs kļūda
+missing_file_error=PDF fails nav atrasts.
+
+# Predefined zoom values
+page_scale_width=Lapas platumÄ
+page_scale_fit=Ietilpinot lapu
+page_scale_auto=AutomÄtiskais izmÄ“rs
+page_scale_actual=Patiesais izmērs
+
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+loading_error_indicator=Kļūda
+loading_error=IelÄdÄ“jot PDF notika kļūda.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{[type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} anotÄcija]
+
+text_annotation_type.alt=[{{type}} AnotÄcija]
+password_label=Ievadiet paroli, lai atvērtu PDF failu.
+password_invalid=Nepareiza parole, mēģiniet vēlreiz.
+password_ok=Labi
+password_cancel=Atcelt
+
+
+printing_not_supported=UzmanÄ«bu: DrukÄÅ¡ana no Å¡Ä« pÄrlÅ«ka darbojas tikai daļēji.
+web_fonts_disabled=Tīmekļa fonti nav aktivizēti: Nevar iegult PDF fontus.
+printing_not_ready=UzmanÄ«bu: PDF nav pilnÄ«bÄ ielÄdÄ“ts drukÄÅ¡anai.
+document_colors_disabled=PDF dokumentiem nav atļauts izmantot paÅ¡iem savas krÄsas: \'Atļaut lapÄm izvÄ“lÄ“ties paÅ¡Äm savas krÄsas\' ir deaktivÄ“ts pÄrlÅ«kÄ.
+
diff --git a/static/pdf.js/locale/mai/viewer.properties b/static/pdf.js/locale/mai/viewer.properties
new file mode 100644
index 000000000..1775dbfd1
--- /dev/null
+++ b/static/pdf.js/locale/mai/viewer.properties
@@ -0,0 +1,121 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=पछिला पृषà¥à¤
+previous_label=पछिला
+next.title=अगिला पृषà¥à¤
+next_label=आगाà¤
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=पृषà¥à¤ :
+page_of={{pageCount}} क
+
+zoom_out.title=छोट करू
+zoom_out_label=छोट करू
+zoom_in.title=पैघ करू
+zoom_in_label=जूम इन
+zoom.title=छोट-पैघ करू\u0020
+presentation_mode.title=पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¤¿ अवसà¥à¤¥à¤¾à¤®à¥‡ जाउ
+presentation_mode_label=पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¤¿ अवसà¥à¤¥à¤¾
+open_file.title=फाइल खोलू
+open_file_label=खोलू
+print.title=छापू
+print_label=छापू
+download.title=डाउनलोड
+download_label=डाउनलोड
+bookmark.title=मोजà¥à¤¦à¤¾ दृशà¥à¤¯ (नव विंडोमे नकल लिअ अथवा खोलू)
+bookmark_label=वरà¥à¤¤à¤®à¤¾à¤¨ दृशà¥à¤¯
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_title=शीरà¥à¤·à¤•:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=सà¥à¤²à¤¾à¤‡à¤¡à¤° टागल
+toggle_sidebar_label=सà¥à¤²à¤¾à¤‡à¤¡à¤° टागल
+outline.title=दसà¥à¤¤à¤¾à¤µà¥‡à¤œ आउटलाइन देखाउ
+outline_label=दसà¥à¤¤à¤¾à¤µà¥‡à¤œ खाका
+thumbs.title=लघà¥-छवि देखाउ
+thumbs_label=लघॠछवि
+findbar.title=दसà¥à¤¤à¤¾à¤µà¥‡à¤œà¤®à¥‡ ढूà¤à¤¢à¥‚
+findbar_label=ताकू
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=पृषà¥à¤ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=पृषà¥à¤ {{page}} का लघà¥-चितà¥à¤°
+
+# Find panel button title and messages
+find_label=ताकू:
+find_previous.title=खोजक पछिला उपसà¥à¤¥à¤¿à¤¤à¤¿ ताकू
+find_previous_label=पछिला
+find_next.title=खोजक अगिला उपसà¥à¤¥à¤¿à¤¤à¤¿ ताकू
+find_next_label=आगाà¤
+find_highlight=सà¤à¤Ÿà¤¾ आलोकित करू
+find_match_case_label=मिलान सà¥à¤¥à¤¿à¤¤à¤¿
+find_reached_top=पृषà¥à¤ क शीरà¥à¤· जाठपहà¥à¤à¤šà¤², तल सठजारी
+find_reached_bottom=पृषà¥à¤ क तल मे जाठपहà¥à¤à¤šà¤², शीरà¥à¤· सठजारी
+find_not_found=वाकींश नहि à¤à¥‡à¤Ÿà¤²
+
+# Error panel labels
+error_more_info=बेसी सूचना
+error_less_info=कम सूचना
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=संदेश: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=सà¥à¤Ÿà¥ˆà¤•: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=फ़ाइल: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=पंकà¥à¤¤à¤¿: {{line}}
+rendering_error=पृषà¥à¤ रेंडरिंगक समय तà¥à¤°à¥à¤Ÿà¤¿ आà¤à¤².
+
+# Predefined zoom values
+page_scale_width=पृषà¥à¤ चओड़ाइ
+page_scale_fit=पृषà¥à¤ फिट
+page_scale_auto=सà¥à¤µà¤šà¤¾à¤²à¤¿à¤¤ जूम
+page_scale_actual=सही आकार
+
+# Loading indicator messages
+loading_error_indicator=तà¥à¤°à¥à¤Ÿà¤¿
+loading_error=पीडीà¤à¤« लोड करैत समय à¤à¤•à¤Ÿà¤¾ तà¥à¤°à¥à¤Ÿà¤¿ à¤à¥‡à¤².
+invalid_file_error=अमानà¥à¤¯ अथवा à¤à¥à¤°à¤·à¥à¤Ÿ PDF फाइल.
+missing_file_error=अनà¥à¤ªà¤¸à¥à¤¥à¤¿à¤¤ PDF फाइल.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_cancel=रदà¥à¤¦ करू\u0020
+
+printing_not_supported=चेतावनी: ई बà¥à¤°à¤¾à¤‰à¤œà¤° पर छपाइ पूरà¥à¤£ तरह सठसमरà¥à¤¥à¤¿à¤¤ नहि अछि.
+printing_not_ready=चेतावनी: पीडीà¤à¤« छपाइक लेल पूरà¥à¤£ तरह सठलोड नहि अछि.
+web_fonts_disabled=वेब फॉनà¥à¤Ÿà¥à¤¸ निषà¥à¤•à¥à¤°à¤¿à¤¯ अछि: अंतःसà¥à¤¥à¤¾à¤ªà¤¿à¤¤ PDF फानà¥à¤Ÿà¤¸à¤• उपयोगमे असमरà¥à¤¥.
diff --git a/static/pdf.js/locale/mk/viewer.properties b/static/pdf.js/locale/mk/viewer.properties
new file mode 100644
index 000000000..18ded8914
--- /dev/null
+++ b/static/pdf.js/locale/mk/viewer.properties
@@ -0,0 +1,126 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Претходна Ñтраница
+previous_label=Претходна
+next.title=Следна Ñтраница
+next_label=Следна
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Страница:
+page_of=од {{pageCount}}
+
+zoom_out.title=Ðамалување
+zoom_out_label=Ðамали
+zoom_in.title=Зголемување
+zoom_in_label=Зголеми
+zoom.title=Променување на големина
+print.title=Печатење
+print_label=Печати
+open_file.title=Отварање датотека
+open_file_label=Отвори
+download.title=Преземање
+download_label=Преземи
+bookmark.title=Овој преглед (копирај или отвори во нов прозорец)
+bookmark_label=Овој преглед
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_slider.title=Вклучување на лизгач
+toggle_slider_label=Вклучи лизгач
+outline.title=Прикажување на Ñодржина на документот
+outline_label=Содржина на документот
+thumbs.title=Прикажување на икони
+thumbs_label=Икони
+
+# Document outline messages
+no_outline=Ðема Ñодржина
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Страница {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Икона од Ñтраница {{page}}
+
+# Error panel labels
+error_more_info=Повеќе информации
+error_less_info=Помалку информации
+error_close=Затвори
+# LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
+# build ID.
+error_build=PDF.JS Build: {{build}}
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Порака: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Датотека: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Линија: {{line}}
+rendering_error=ÐаÑтана грешка при прикажувањето на Ñтраницата.
+
+# Predefined zoom values
+page_scale_width=Ширина на Ñтраница
+page_scale_fit=Цела Ñтраница
+page_scale_auto=ÐвтоматÑка големина
+page_scale_actual=ВиÑтинÑка големина
+
+loading_error_indicator=Грешка
+loading_error=ÐаÑтана грешка при вчитувањето на PDF-от.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{[type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type=[{{type}} Забелешка]
+request_password=PDF-от е заштитен Ñо лозинка:
+
+
+printing_not_supported=Предупредување: Печатењето не е целоÑно поддржано во овој прелиÑтувач.
+
+find_highlight=Означи ÑÑ
+
+# Find panel button title and messages
+find_label=Ðајди:
+find_match_case_label=Токму така
+find_next.title=Ðајди ја Ñледната појава на фразата
+find_next_label=Следно
+find_not_found=Фразата не е пронајдена
+find_previous.title=Ðајди ја предходната појава на фразата
+find_previous_label=Претходно
+find_reached_bottom=Барањето Ñтигна до крајот на документот и почнува од почеток
+find_reached_top=Барањето Ñтигна до почетокот на документот и почнува од крајот
+findbar.title=Ðајди во документот
+findbar_label=Ðајди
+
+# Context menu
+first_page.label=Оди до првата Ñтраница
+invalid_file_error=Ðевалидна или корумпирана PDF датотека.
+last_page.label=Оди до поÑледната Ñтраница
+page_rotate_ccw.label=Ротирај Ñпротивно од Ñтрелките на чаÑовникот
+page_rotate_cw.label=Ротирај по Ñтрелките на чаÑовникот
+presentation_mode.title=Премини во презентациÑки режим
+presentation_mode_label=ПрезентациÑки режим
+
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+missing_file_error=ÐедоÑтаÑува PDF документ.
+printing_not_ready=Предупредување: PDF документот не е целоÑно вчитан за печатење.
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Вклучи Ñтранична лента
+toggle_sidebar_label=Вклучи Ñтранична лента
+web_fonts_disabled=Интернет фонтовите Ñе оневозможени: не може да Ñе кориÑтат вградените PDF фонтови.
diff --git a/static/pdf.js/locale/ml/viewer.properties b/static/pdf.js/locale/ml/viewer.properties
new file mode 100644
index 000000000..ecacc7c68
--- /dev/null
+++ b/static/pdf.js/locale/ml/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=à´®àµà´®àµà´ªàµà´³àµà´³ താളàµâ€
+previous_label=à´®àµà´®àµà´ªàµàµ
+next.title=à´…à´Ÿàµà´¤àµà´¤ താളàµâ€
+next_label=à´…à´Ÿàµà´¤àµà´¤à´¤àµàµ
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=താളàµâ€:
+page_of={{pageCount}}
+
+zoom_out.title=ചെറàµà´¤à´¾à´•àµà´•àµà´•
+zoom_out_label=ചെറàµà´¤à´¾à´•àµà´•àµà´•
+zoom_in.title=വലàµà´¤à´¾à´•àµà´•àµà´•
+zoom_in_label=വലàµà´¤à´¾à´•àµà´•àµà´•
+zoom.title=à´µàµà´¯à´¾à´ªàµà´¤à´¿ മാറàµà´±àµà´•
+presentation_mode.title=à´ªàµà´°à´¸à´¨àµà´±àµ‡à´·à´¨àµâ€ രീതിയിലേകàµà´•àµàµ മാറàµà´±àµà´•
+presentation_mode_label=à´ªàµà´°à´¸à´¨àµà´±àµ‡à´·à´¨àµâ€ രീതി
+open_file.title=ഫയലàµâ€ à´¤àµà´±à´•àµà´•àµà´•
+open_file_label=à´¤àµà´±à´•àµà´•àµà´•
+print.title=à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´•
+print_label=à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´•
+download.title=ഡൌണàµâ€à´²àµ‡à´¾à´¡àµ ചെയàµà´¯àµà´•
+download_label=ഡൌണàµâ€à´²àµ‡à´¾à´¡àµ ചെയàµà´¯àµà´•
+bookmark.title=നിലവിലàµà´³àµà´³ കാഴàµà´š (à´ªàµà´¤à´¿à´¯ ജാലകതàµà´¤à´¿à´²àµâ€ പകരàµâ€à´¤àµà´¤àµà´• à´…à´²àµà´²àµ†à´™àµà´•à´¿à´²àµâ€ à´¤àµà´±à´•àµà´•àµà´•)
+bookmark_label=നിലവിലàµà´³àµà´³ കാഴàµà´š
+
+# Secondary toolbar and context menu
+tools.title=ഉപകരണങàµà´™à´³àµâ€
+tools_label=ഉപകരണങàµà´™à´³àµâ€
+first_page.title=ആദàµà´¯à´¤àµà´¤àµ† താളിലേയàµà´•àµà´•àµàµ പോകàµà´•
+first_page.label=ആദàµà´¯à´¤àµà´¤àµ† താളിലേയàµà´•àµà´•àµàµ പോകàµà´•
+first_page_label=ആദàµà´¯à´¤àµà´¤àµ† താളിലേയàµà´•àµà´•àµàµ പോകàµà´•
+last_page.title=അവസാന താളിലേയàµà´•àµà´•àµàµ പോകàµà´•
+last_page.label=അവസാന താളിലേയàµà´•àµà´•àµàµ പോകàµà´•
+last_page_label=അവസാന താളിലേയàµà´•àµà´•àµàµ പോകàµà´•
+page_rotate_cw.title=ഘടികാരദിശയിലàµâ€ കറകàµà´•àµà´•
+page_rotate_cw.label=ഘടികാരദിശയിലàµâ€ കറകàµà´•àµà´•
+page_rotate_cw_label=ഘടികാരദിശയിലàµâ€ കറകàµà´•àµà´•
+page_rotate_ccw.title=ഘടികാര ദിശയàµà´•àµà´•àµàµ വിപരീതമായി കറകàµà´•àµà´•
+page_rotate_ccw.label=ഘടികാര ദിശയàµà´•àµà´•àµàµ വിപരീതമായി കറകàµà´•àµà´•
+page_rotate_ccw_label=ഘടികാര ദിശയàµà´•àµà´•àµàµ വിപരീതമായി കറകàµà´•àµà´•
+
+hand_tool_enable.title=ഹാനàµâ€à´¡àµ ടൂളàµâ€ à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨ സജàµà´œà´®à´¾à´•àµà´•àµà´•
+hand_tool_enable_label=ഹാനàµâ€à´¡àµ ടൂളàµâ€ à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨ സജàµà´œà´®à´¾à´•àµà´•àµà´•
+hand_tool_disable.title=ഹാനàµâ€à´¡àµ ടൂളàµâ€ à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨ രഹിതമാകàµà´•àµà´•
+hand_tool_disable_label=ഹാനàµâ€à´¡àµ ടൂളàµâ€ à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨ രഹിതമാകàµà´•àµà´•
+
+# Document properties dialog box
+document_properties.title=രേഖയàµà´Ÿàµ† വിശേഷതകളàµâ€...
+document_properties_label=രേഖയàµà´Ÿàµ† വിശേഷതകളàµâ€...
+document_properties_file_name=ഫയലിനàµà´±àµ† പേരàµâ€Œ:
+document_properties_file_size=ഫയലിനàµà´±àµ† വലിപàµà´ªà´‚:‌‌
+document_properties_kb={{size_kb}} കെബി ({{size_b}} ബൈറàµà´±àµà´•à´³àµâ€)
+document_properties_mb={{size_mb}} എംബി ({{size_b}} ബൈറàµà´±àµà´•à´³àµâ€)
+document_properties_title=തലകàµà´•àµ†à´Ÿàµà´Ÿàµâ€Œ\u0020
+document_properties_author=രചയിതാവàµ:
+document_properties_subject=വിഷയം:
+document_properties_keywords=കീവേരàµâ€à´¡àµà´•à´³àµâ€:
+document_properties_creation_date=പൂരàµâ€à´¤àµà´¤à´¿à´¯à´¾à´•àµà´¨àµà´¨ തീയതി:
+document_properties_modification_date=മാറàµà´±à´‚ വരàµà´¤àµà´¤à´¿à´¯ തീയതി:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=സൃഷàµà´Ÿà´¿à´•à´°àµâ€à´¤àµà´¤à´¾à´µàµ:
+document_properties_producer=പിഡിഎഫൠപàµà´°àµŠà´¡àµà´¯àµ‚സരàµâ€:
+document_properties_version=പിഡിഎഫൠപതിപàµà´ªàµ:
+document_properties_page_count=താളിനàµà´±àµ† à´Žà´£àµà´£à´‚:
+document_properties_close=à´…à´Ÿà´¯àµà´•àµà´•àµà´•
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=സൈഡൠബാറിലേകàµà´•àµàµ മാറàµà´±àµà´•
+toggle_sidebar_label=സൈഡൠബാറിലേകàµà´•àµàµ മാറàµà´±àµà´•
+outline.title=രേഖയàµà´Ÿàµ† ഔടàµà´Ÿàµà´²àµˆà´¨àµâ€ കാണിയàµà´•àµà´•àµà´•
+outline_label=രേഖയàµà´Ÿàµ† ഔടàµà´Ÿàµà´²àµˆà´¨àµâ€
+attachments.title=à´…à´±àµà´±à´¾à´šàµà´®àµ†à´¨àµà´±àµà´•à´³àµâ€ കാണിയàµà´•àµà´•àµà´•
+attachments_label=à´…à´±àµà´±à´¾à´šàµà´®àµ†à´¨àµà´±àµà´•à´³àµâ€
+thumbs.title=തംബàµà´¨àµ†à´¯à´¿à´²àµà´•à´³àµâ€ കാണിയàµà´•àµà´•àµà´•
+thumbs_label=തംബàµà´¨àµ†à´¯à´¿à´²àµà´•à´³àµâ€
+findbar.title=രേഖയിലàµâ€ à´•à´£àµà´Ÿàµà´ªà´¿à´Ÿà´¿à´¯àµà´•àµà´•àµà´•
+findbar_label=à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´•\u0020
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=താളàµâ€ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}} താളിനàµà´³àµà´³ തംബàµà´¨àµ†à´¯à´¿à´²àµâ€
+
+# Find panel button title and messages
+find_label=à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´•
+find_previous.title=വാചകം ഇതിനൠമàµà´¨àµâ€à´ªàµâ€Œ ആവരàµâ€à´¤àµà´¤à´¿à´šàµà´šà´¤àµâ€Œ à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´•\u0020
+find_previous_label=à´®àµà´®àµà´ªàµàµ
+find_next.title=വാചകം വീണàµà´Ÿàµà´‚ ആവരàµâ€à´¤àµà´¤à´¿à´•àµà´•àµà´¨àµà´¨à´¤àµâ€Œ à´•à´£àµà´Ÿàµ†à´¤àµà´¤àµà´•\u0020
+find_next_label=à´…à´Ÿàµà´¤àµà´¤à´¤àµàµ
+find_highlight=à´Žà´²àµà´²à´¾à´‚ à´Žà´Ÿàµà´¤àµà´¤àµà´•à´¾à´£à´¿à´¯àµà´•àµà´•àµà´•
+find_match_case_label=à´…à´•àµà´·à´°à´™àµà´™à´³àµâ€ à´’à´¤àµà´¤àµà´¨àµ‹à´•àµà´•àµà´•
+find_reached_top=രേഖയàµà´Ÿàµ† à´®àµà´•à´³à´¿à´²àµâ€ à´Žà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, താഴെ നിനàµà´¨àµà´‚ à´¤àµà´Ÿà´°àµà´¨àµà´¨àµ
+find_reached_bottom=രേഖയàµà´Ÿàµ† അവസാനം വരെ à´Žà´¤àµà´¤à´¿à´¯à´¿à´°à´¿à´•àµà´•àµà´¨àµà´¨àµ, à´®àµà´•à´³à´¿à´²àµâ€ നിനàµà´¨àµà´‚ à´¤àµà´Ÿà´°àµà´¨àµà´¨àµ\u0020
+find_not_found=വാചകം à´•à´£àµà´Ÿàµ†à´¤àµà´¤à´¾à´¨à´¾à´¯à´¿à´²àµà´²\u0020
+
+# Error panel labels
+error_more_info=കൂടàµà´¤à´²àµâ€ വിവരം
+error_less_info=à´•àµà´±à´šàµà´šàµ വിവരം
+error_close=à´…à´Ÿà´¯àµà´•àµà´•àµà´•
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=സനàµà´¦àµ‡à´¶à´‚: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=à´¸àµà´±àµà´±à´¾à´•àµà´•àµ: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ഫയലàµâ€: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=വരി: {{line}}
+rendering_error=താളàµâ€ റെണàµà´Ÿà´°àµâ€ ചെയàµà´¯àµà´®àµà´ªàµ‹à´³àµâ€â€Œ പിശകàµà´£àµà´Ÿà´¾à´¯à´¿à´°à´¿à´¯àµà´•àµà´•àµà´¨àµà´¨àµ.
+
+# Predefined zoom values
+page_scale_width=താളിനàµà´±àµ† വീതി
+page_scale_fit=താളàµâ€ പാകതàµà´¤à´¿à´¨à´¾à´•àµà´•àµà´•
+page_scale_auto=à´¸àµà´µà´¯à´®à´¾à´¯à´¿ വലàµà´¤à´¾à´•àµà´•àµà´•
+page_scale_actual=യഥാരàµâ€à´¤àµà´¥ à´µàµà´¯à´¾à´ªàµà´¤à´¿
+
+# Loading indicator messages
+loading_error_indicator=പിശകàµ
+loading_error=പിഡിഎഫൠലà´àµà´¯à´®à´¾à´•àµà´•àµà´®àµà´ªàµ‹à´³àµâ€ പിശകൠഉണàµà´Ÿà´¾à´¯à´¿à´°à´¿à´¯àµà´•àµà´•àµà´¨àµà´¨àµ.
+invalid_file_error=തെറàµà´±à´¾à´¯ à´…à´²àµà´²àµ†à´™àµà´•à´¿à´²àµâ€ തകരാറàµà´³àµà´³ പിഡിഎഫൠഫയലàµâ€.
+missing_file_error=പിഡിഎഫൠഫയലàµâ€ à´²à´àµà´¯à´®à´²àµà´².
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=à´ˆ പിഡിഎഫൠഫയലàµâ€ à´¤àµà´±à´•àµà´•àµà´¨àµà´¨à´¤à´¿à´¨àµàµ രഹസàµà´¯à´µà´¾à´•àµà´•àµ നലàµâ€à´•àµà´•.
+password_invalid=തെറàµà´±à´¾à´¯ രഹസàµà´¯à´µà´¾à´•àµà´•àµ, ദയവായി വീണàµà´Ÿàµà´‚ à´¶àµà´°à´®à´¿à´¯àµà´•àµà´•àµà´•.
+password_ok=ശരി
+password_cancel=റദàµà´¦à´¾à´•àµà´•àµà´•
+
+printing_not_supported=à´®àµà´¨àµà´¨à´±à´¿à´¯à´¿à´ªàµà´ªàµàµ: à´ˆ à´¬àµà´°àµŒà´¸à´°àµâ€ പൂരàµâ€à´£àµà´£à´®à´¾à´¯à´¿ à´ªàµà´°à´¿à´¨àµà´±à´¿à´™àµ പിനàµà´¤àµà´£à´¯àµà´•àµà´•àµà´¨àµà´¨à´¿à´²àµà´².
+printing_not_ready=à´®àµà´¨àµà´¨à´±à´¿à´¯à´¿à´ªàµà´ªàµàµ: à´ªàµà´°à´¿à´¨àµà´±àµ ചെയàµà´¯àµà´¨àµà´¨à´¤à´¿à´¨àµàµ പിഡിഎഫൠപൂരàµâ€à´£àµà´£à´®à´¾à´¯à´¿ à´²à´àµà´¯à´®à´²àµà´².
+web_fonts_disabled=വെബിനàµà´³àµà´³ à´…à´•àµà´·à´°à´¸à´žàµà´šà´¯à´™àµà´™à´³àµâ€ à´ªàµà´°à´µà´°àµâ€à´¤àµà´¤à´¨ രഹിതം: എംബഡàµà´¡àµ ചെയàµà´¤ പിഡിഎഫൠഅകàµà´·à´°à´¸à´žàµà´šà´¯à´™àµà´™à´³àµâ€ ഉപയോഗിയàµà´•àµà´•àµà´µà´¾à´¨àµâ€ സാധàµà´¯à´®à´²àµà´².
+document_colors_disabled=à´¸àµà´µà´¨àµà´¤à´‚ നിറങàµà´™à´³àµâ€ ഉപയോഗിയàµà´•àµà´•àµà´µà´¾à´¨àµâ€ പിഡിഎഫൠരേഖകളàµâ€à´•àµà´•àµàµ à´…à´¨àµà´µà´¾à´¦à´®à´¿à´²àµà´²: 'à´¸àµà´µà´¨àµà´¤à´‚ നിറങàµà´™à´³àµâ€ ഉപയോഗിയàµà´•àµà´•àµà´µà´¾à´¨àµâ€ താളàµà´•à´³àµ† à´…à´¨àµà´µà´¦à´¿à´¯àµà´•àµà´•àµà´•' à´Žà´¨àµà´¨à´¤àµàµ à´¬àµà´°àµŒà´¸à´±à´¿à´²àµâ€ നിരàµâ€à´œàµ€à´µà´®à´¾à´£àµàµ.
diff --git a/static/pdf.js/locale/mn/viewer.properties b/static/pdf.js/locale/mn/viewer.properties
new file mode 100644
index 000000000..f0366444a
--- /dev/null
+++ b/static/pdf.js/locale/mn/viewer.properties
@@ -0,0 +1,65 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+
+zoom.title=ТÑлÑлт
+open_file.title=Файл нÑÑ
+open_file_label=ÐÑÑ
+
+# Secondary toolbar and context menu
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+findbar_label=Ол
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+
+# Find panel button title and messages
+find_previous.title=Хайлтын өмнөх олдцыг харуулна
+find_next.title=Хайлтын дараагийн олдцыг харуулна
+find_not_found=ОлдÑонгүй
+
+# Error panel labels
+error_more_info=ÐÑмÑлт мÑдÑÑлÑл
+error_close=Хаа
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+
+# Predefined zoom values
+
+# Loading indicator messages
+loading_error_indicator=Ðлдаа
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+
diff --git a/static/pdf.js/locale/mr/viewer.properties b/static/pdf.js/locale/mr/viewer.properties
new file mode 100644
index 000000000..fafcf754b
--- /dev/null
+++ b/static/pdf.js/locale/mr/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=मागील पृषà¥à¤
+previous_label=मागील
+next.title=पà¥à¤¢à¥€à¤² पृषà¥à¤
+next_label=पà¥à¤¢à¥€à¤²
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=पृषà¥à¤ :
+page_of=पैकी {{pageCount}}
+
+zoom_out.title=छोटे करा
+zoom_out_label=छोटे करा
+zoom_in.title=मोठे करा
+zoom_in_label=मोठे करा
+zoom.title=लहान किंवा मोठे करा
+presentation_mode.title=पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¤¿à¤•à¤°à¤£ मोडचा वापर करा
+presentation_mode_label=पà¥à¤°à¤¸à¥à¤¤à¥à¤¤à¤¿à¤•à¤°à¤£ मोड
+open_file.title=फाइल उघडा
+open_file_label=उघडा
+print.title=छपाई करा
+print_label=छपाई करा
+download.title=डाउनलोड करा
+download_label=डाउनलोड करा
+bookmark.title=सधà¥à¤¯à¤¾à¤šà¥‡ अवलोकन (नविन पटलात पà¥à¤°à¤¤ बनवा किंवा उघडा)
+bookmark_label=सधà¥à¤¯à¤¾à¤šà¥‡ अवलोकन
+
+# Secondary toolbar and context menu
+tools.title=साधने
+tools_label=साधने
+first_page.title=पहिलà¥à¤¯à¤¾ पानावर जा
+first_page.label=पहिलà¥à¤¯à¤¾ पानावर जा
+first_page_label=पहिलà¥à¤¯à¤¾ पानावर जा
+last_page.title=शेवटचà¥à¤¯à¤¾ पानावर जा
+last_page.label=शेवटचà¥à¤¯à¤¾ पानावर जा
+last_page_label=शेवटचà¥à¤¯à¤¾ पानावर जा
+page_rotate_cw.title=घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ काटà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ दिशेने फिरवा
+page_rotate_cw.label=घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ काटà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ दिशेने फिरवा
+page_rotate_cw_label=घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ काटà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ दिशेने फिरवा
+page_rotate_ccw.title=घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ काटà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ उलट दिशेने फिरवा
+page_rotate_ccw.label=घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ काटà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ उलट दिशेने फिरवा
+page_rotate_ccw_label=घडà¥à¤¯à¤¾à¤³à¤¾à¤šà¥à¤¯à¤¾ काटà¥à¤¯à¤¾à¤šà¥à¤¯à¤¾ उलट दिशेने फिरवा
+
+hand_tool_enable.title=हात साधन सà¥à¤°à¥‚ करा
+hand_tool_enable_label=हात साधन सà¥à¤°à¥‚ करा
+hand_tool_disable.title=हात साधन बंद करा
+hand_tool_disable_label=हात साधन बंद करा
+
+# Document properties dialog box
+document_properties.title=दसà¥à¤¤à¤à¤µà¤œ गà¥à¤£à¤§à¤°à¥à¤®â€¦
+document_properties_label=दसà¥à¤¤à¤à¤µà¤œ गà¥à¤£à¤§à¤°à¥à¤®â€¦
+document_properties_file_name=फाइलचे नाव:
+document_properties_file_size=फाइल आकार:
+document_properties_kb={{size_kb}} KB ({{size_b}} बाइटà¥à¤¸)
+document_properties_mb={{size_mb}} MB ({{size_b}} बाइटà¥à¤¸)
+document_properties_title=शिरà¥à¤·à¤•:
+document_properties_author=लेखक:
+document_properties_subject=विषय:
+document_properties_keywords=मà¥à¤–à¥à¤¯à¤¶à¤¬à¥à¤¦:
+document_properties_creation_date=निरà¥à¤®à¤¾à¤£ दिनांक:
+document_properties_modification_date=दà¥à¤°à¥‚सà¥à¤¤à¥€ दिनांक:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=निरà¥à¤®à¤¾à¤¤à¤¾:
+document_properties_producer=PDF निरà¥à¤®à¤¾à¤¤à¤¾:
+document_properties_version=PDF आवृतà¥à¤¤à¥€:
+document_properties_page_count=पृषà¥à¤ संखà¥à¤¯à¤¾:
+document_properties_close=बंद करा
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=बाजूचीपटà¥à¤Ÿà¥€ टॉगल करा
+toggle_sidebar_label=बाजूचीपटà¥à¤Ÿà¥€ टॉगल करा
+outline.title=दसà¥à¤¤à¤à¤µà¤œ रूपरेषा दाखवा
+outline_label=दसà¥à¤¤à¤à¤µà¤œ रूपरेषा
+attachments.title=जोडपतà¥à¤° दाखवा
+attachments_label=जोडपतà¥à¤°
+thumbs.title=थंबनेलà¥à¤¸à¥ दाखवा
+thumbs_label=थंबनेलà¥à¤¸à¥
+findbar.title=दसà¥à¤¤à¤à¤µà¤œà¤¾à¤¤ शोधा
+findbar_label=शोधा
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=पृषà¥à¤ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=पृषà¥à¤ ाचे थंबनेल {{page}}
+
+# Find panel button title and messages
+find_label=शोधा:
+find_previous.title=वाकपà¥à¤°à¤¯à¥‹à¤—ची मागील घटना शोधा
+find_previous_label=मागील
+find_next.title=वाकपà¥à¤°à¤¯à¥‹à¤—ची पà¥à¤¢à¥€à¤² घटना शोधा
+find_next_label=पà¥à¤¢à¥€à¤²
+find_highlight=सरà¥à¤µ ठळक करा
+find_match_case_label=आकार जà¥à¤³à¤µà¤¾
+find_reached_top=दसà¥à¤¤à¤à¤µà¤œà¤¾à¤šà¥à¤¯à¤¾ शीरà¥à¤·à¤•à¤¾à¤¸ पोहचले, तळपासून पà¥à¤¢à¥‡
+find_reached_bottom=दसà¥à¤¤à¤à¤µà¤œà¤¾à¤šà¥à¤¯à¤¾ तळाला पोहचले, शीरà¥à¤·à¤•à¤¾à¤ªà¤¾à¤¸à¥‚न पà¥à¤¢à¥‡
+find_not_found=वाकपà¥à¤°à¤¯à¥‹à¤— आढळले नाही
+
+# Error panel labels
+error_more_info=आणखी माहिती
+error_less_info=कमी माहिती
+error_close=बंद करा
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=संदेश: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=सà¥à¤Ÿà¥…क: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=फाइल: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=रेष: {{line}}
+rendering_error=पृषà¥à¤ दाखवतेवेळी तà¥à¤°à¥à¤Ÿà¥€ आढळली.
+
+# Predefined zoom values
+page_scale_width=पृषà¥à¤ ाची रूंदी
+page_scale_fit=पृषà¥à¤ बसवा
+page_scale_auto=सà¥à¤µà¤¯à¤‚ लाहन किंवा मोठे करणे
+page_scale_actual=पà¥à¤°à¤¤à¥à¤¯à¤•à¥à¤· आकार
+
+# Loading indicator messages
+loading_error_indicator=तà¥à¤°à¥à¤Ÿà¥€
+loading_error=PDF लोड करतेवेळी तà¥à¤°à¥à¤Ÿà¥€ आढळली.
+invalid_file_error=अवैध किंवा दोषीत PDF फाइल.
+missing_file_error=न आढळणारी PDF फाइल.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} टिपणà¥à¤£à¥€]
+password_label=ही PDF फाइल उघडणà¥à¤¯à¤¾à¤•à¤°à¤¿à¤¤à¤¾ पासवरà¥à¤¡ दà¥à¤¯à¤¾.
+password_invalid=अवैध पासवरà¥à¤¡. कृपया पà¥à¤¨à¥à¤¹à¤¾ पà¥à¤°à¤¯à¤¤à¥à¤¨ करा.
+password_ok=ठीक आहे
+password_cancel=रदà¥à¤¦ करा
+
+printing_not_supported=सावधानता: या बà¥à¤°à¤¾à¤‰à¤œà¤°à¤¤à¤°à¥à¤«à¥‡ छपाइ पूरà¥à¤£à¤ªà¤£à¥‡ समरà¥à¤¥à¥€à¤¤ नाही.
+printing_not_ready=सावधानता: छपाईकरिता PDF पूरà¥à¤£à¤¤à¤¯à¤¾ लोड à¤à¤¾à¤²à¥‡ नाही.
+web_fonts_disabled=वेब फाà¤à¤Ÿà¥à¤¸ असमरà¥à¤¥à¥€à¤¤ आहेत: à¤à¤®à¥à¤¬à¥‡à¤¡à¥‡à¤¡ PDF फाà¤à¤Ÿà¥à¤¸à¥à¤šà¤¾ वापर अशकà¥à¤¯.
+document_colors_disabled=PDF दसà¥à¤¤à¤¾à¤à¤µà¤œà¤¾à¤‚ना तà¥à¤¯à¤¾à¤‚चे रंग वापरणà¥à¤¯à¤¾à¤¸ अनà¥à¤®à¤¤à¥€ नाही: बà¥à¤°à¤¾à¤‰à¤œà¤°à¤®à¤§à¥à¤¯à¥‡ ' पानांना तà¥à¤¯à¤¾à¤‚चे रंग निवडणà¥à¤¯à¤¾à¤¸ अनà¥à¤®à¤¤à¥€ दà¥à¤¯à¤¾' बंद केले आहे.
diff --git a/static/pdf.js/locale/ms/viewer.properties b/static/pdf.js/locale/ms/viewer.properties
new file mode 100644
index 000000000..b43b4ad34
--- /dev/null
+++ b/static/pdf.js/locale/ms/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Laman Sebelumnya
+previous_label=Terdahulu
+next.title=Laman seterusnya
+next_label=Berikut
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Laman:
+page_of=daripada {{pageCount}}
+
+zoom_out.title=Zum Keluar
+zoom_out_label=Zum Keluar
+zoom_in.title=Zum Masuk
+zoom_in_label=Zum Masuk
+zoom.title=Zum
+presentation_mode.title=Bertukar ke Mod Persembahan
+presentation_mode_label=Mod Persembahan
+open_file.title=Buka Fail
+open_file_label=Buka
+print.title=Cetak
+print_label=Cetak
+download.title=Muat turun
+download_label=Muat turun
+bookmark.title=Pandangan semasa (salinan atau dibuka dalam tetingkap baru)
+bookmark_label=Lihat semasa
+
+# Secondary toolbar and context menu
+tools.title=Alatan
+tools_label=Alatan
+first_page.title=Pergi ke Halaman Pertama
+first_page.label=Pergi ke Halaman Pertama
+first_page_label=Pergi ke Halaman Pertama
+last_page.title=Pergi ke Halaman Terakhir
+last_page.label=Pergi ke Halaman Terakhir
+last_page_label=Pergi ke Halaman Terakhir
+page_rotate_cw.title=Berputar ikut arah Jam
+page_rotate_cw.label=Berputar ikut arah Jam
+page_rotate_cw_label=Berputar ikut arah Jam
+page_rotate_ccw.title=Pusing berlawan arah jam
+page_rotate_ccw.label=Pusing berlawan arah jam
+page_rotate_ccw_label=Pusing berlawan arah jam
+
+hand_tool_enable.title=Bolehkan alatan tangan
+hand_tool_enable_label=Bolehkan alatan tangan
+hand_tool_disable.title=Lumpuhkan alatan tangan
+hand_tool_disable_label=Lumpuhkan alatan tangan
+
+# Document properties dialog box
+document_properties.title=Ciri Dokumen…
+document_properties_label=Ciri Dokumen…
+document_properties_file_name=Nama fail:
+document_properties_file_size=Saiz fail:
+document_properties_kb={{size_kb}} KB ({{size_b}} bait)
+document_properties_mb={{size_mb}} MB ({{size_b}} bait)
+document_properties_title=Tajuk:
+document_properties_author=Pengarang:
+document_properties_subject=Subjek:
+document_properties_keywords=Kata kunci:
+document_properties_creation_date=Masa Dicipta:
+document_properties_modification_date=Tarikh Ubahsuai:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Pencipta:
+document_properties_producer=Pengeluar PDF:
+document_properties_version=Versi PDF:
+document_properties_page_count=Kiraan Laman:
+document_properties_close=Tutup
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Togol Bar Sisi
+toggle_sidebar_label=Togol Bar Sisi
+outline.title=Tunjuk Rangka Dokumen
+outline_label=Rangka Dokument
+attachments.title=Tunjuk Lampiran
+attachments_label=Lampiran
+thumbs.title=Tunjuk Imej kecil
+thumbs_label=Imej kecil
+findbar.title=Cari didalam Dokumen
+findbar_label=Cari
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Halaman {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Halaman Imej kecil {{page}}
+
+# Find panel button title and messages
+find_label=Cari:
+find_previous.title=Cari teks frasa berkenaan yang terdahulu
+find_previous_label=Sebelumnya
+find_next.title=Cari teks frasa berkenaan yang berikut
+find_next_label=Berikut
+find_highlight=Serlahkan semua
+find_match_case_label=Kes Sepadan
+find_reached_top=Mencapai teratas daripada dokumen, sambungan daripada bawah
+find_reached_bottom=Mencapai terakhir daripada dokumen, sambungan daripada atas
+find_not_found=Frasa tidak ditemui
+
+# Error panel labels
+error_more_info=Maklumat lanjut
+error_less_info=Kurang Informasi
+error_close=Tutup
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mesej: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Timbun: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fail: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Garis: {{line}}
+rendering_error=Ralat berlaku ketika memberikan halaman.
+
+# Predefined zoom values
+page_scale_width=Lebar Halaman
+page_scale_fit=Muat Halaman
+page_scale_auto=Zoom Automatik
+page_scale_actual=Saiz Sebenar
+
+# Loading indicator messages
+loading_error_indicator=Ralat
+loading_error=Masalah berlaku semasa menuatkan sebuah PDF.
+invalid_file_error=Tidak sah atau fail PDF rosak.
+missing_file_error=Fail PDF Hilang.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Anotasi]
+password_label=Masukan kata kunci untuk membuka fail PDF ini.
+password_invalid=Kata laluan salah. Cuba lagi.
+password_ok=OK
+password_cancel=Batal
+
+printing_not_supported=Amaran: Cetakan ini tidak sepenuhnya disokong oleh pelayar ini.
+printing_not_ready=Amaran: PDF tidak sepenuhnya dimuatkan untuk dicetak.
+web_fonts_disabled=Fon web dilumpuhkan: tidak dapat fon PDF terbenam.
+document_colors_disabled=Dokumen PDF tidak dibenarkan untuk menggunakan warna sendiri: 'Benarkan muka surat untuk memilih warna sendiri' telah dinyahaktif dalam pelayar.
diff --git a/static/pdf.js/locale/my/viewer.properties b/static/pdf.js/locale/my/viewer.properties
new file mode 100644
index 000000000..721e0d019
--- /dev/null
+++ b/static/pdf.js/locale/my/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=အရင် စာမျက်နှာ
+previous_label=အရင်နေရာ
+next.title=ရှေ့ စာမျက်နှာ
+next_label=နောက်á€á€á€¯
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=စာမျက်နှာ -
+page_of=á {{pageCount}}
+
+zoom_out.title=á€á€»á€¯á€¶á€·á€•á€«
+zoom_out_label=á€á€»á€¯á€¶á€·á€•á€«
+zoom_in.title=á€á€»á€²á€·á€•á€«
+zoom_in_label=á€á€»á€²á€·á€•á€«
+zoom.title=á€á€»á€¯á€¶á€·/á€á€»á€²á€·á€•á€«
+presentation_mode.title=Switch to Presentation Mode
+presentation_mode_label=Presentation Mode
+open_file.title=ဖá€á€¯á€„်အားဖွင့်ပါá‹
+open_file_label=ဖွင့်ပါ
+print.title=ပုံနှá€á€¯á€•á€ºá€•á€«
+print_label=ပုံနှá€á€¯á€•á€ºá€•á€«
+download.title=ကူးဆွဲ
+download_label=ကူးဆွဲ
+bookmark.title=လက်ရှဠမြင်ကွင်း (á€á€„်းဒá€á€¯á€¸á€¡á€žá€…်မှာ ကူးပါ သá€á€¯á€·á€™á€Ÿá€¯á€á€º ဖွင့်ပါ)
+bookmark_label=လက်ရှဠမြင်ကွင်း
+
+# Secondary toolbar and context menu
+tools.title=ကá€á€›á€á€šá€¬á€™á€»á€¬á€¸
+tools_label=ကá€á€›á€á€šá€¬á€™á€»á€¬á€¸
+first_page.title=ပထမ စာမျက်နှာသá€á€¯á€·
+first_page.label=ပထမ စာမျက်နှာသá€á€¯á€·
+first_page_label=ပထမ စာမျက်နှာသá€á€¯á€·
+last_page.title=နောက်ဆုံး စာမျက်နှာသá€á€¯á€·
+last_page.label=နောက်ဆုံး စာမျက်နှာသá€á€¯á€·
+last_page_label=နောက်ဆုံး စာမျက်နှာသá€á€¯á€·
+page_rotate_cw.title=နာရီလက်á€á€¶ အá€á€á€¯á€„်း
+page_rotate_cw.label=နာရီလက်á€á€¶ အá€á€á€¯á€„်း
+page_rotate_cw_label=နာရီလက်á€á€¶ အá€á€á€¯á€„်း
+page_rotate_ccw.title=နာရီလက်á€á€¶ ပြောင်းပြန်
+page_rotate_ccw.label=နာရီလက်á€á€¶ ပြောင်းပြန်
+page_rotate_ccw_label=နာရီလက်á€á€¶ ပြောင်းပြန်
+
+hand_tool_enable.title=လက်ကá€á€¯á€„် ကá€á€›á€á€šá€¬á€¡á€¬á€¸á€žá€¯á€¶á€¸
+hand_tool_enable_label=လက်ကá€á€¯á€„် ကá€á€›á€á€šá€¬á€–ွင့်
+hand_tool_disable.title=လက်ကá€á€¯á€„် ကá€á€›á€á€šá€¬á€¡á€¬á€¸á€•á€á€á€º
+hand_tool_disable_label=လက်ကá€á€¯á€„်ကá€á€›á€á€šá€¬ အားပá€á€á€º
+
+# Document properties dialog box
+document_properties.title=မှá€á€ºá€á€™á€ºá€¸á€™á€¾á€á€ºá€›á€¬ ဂုá€á€ºá€žá€á€¹á€á€á€™á€»á€¬á€¸
+document_properties_label=မှá€á€ºá€á€™á€ºá€¸á€™á€¾á€á€ºá€›á€¬ ဂုá€á€ºá€žá€á€¹á€á€á€™á€»á€¬á€¸
+document_properties_file_name=ဖá€á€¯á€„် :
+document_properties_file_size=ဖá€á€¯á€„်ဆá€á€¯á€’် :
+document_properties_kb={{size_kb}} ကီလá€á€¯á€˜á€á€¯á€á€º ({size_kb}}ဘá€á€¯á€á€º)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=á€á€±á€«á€„်းစဉ်‌ -
+document_properties_author=ရေးသားသူ:
+document_properties_subject=အကြောင်းအရာ:\u0020
+document_properties_keywords=သော့á€á€»á€€á€º စာလုံး:
+document_properties_creation_date=ထုá€á€ºá€œá€¯á€•á€ºá€›á€€á€ºá€…ွဲ:
+document_properties_modification_date=ပြင်ဆင်ရက်စွဲ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ဖန်á€á€®á€¸á€žá€°:
+document_properties_producer=PDF ထုá€á€ºá€œá€¯á€•á€ºá€žá€°:
+document_properties_version=PDF ဗားရှင်း:
+document_properties_page_count=စာမျက်နှာအရေအá€á€½á€€á€º:
+document_properties_close=ပá€á€á€º
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=ဘေးá€á€”်းဖွင့်ပá€á€á€º
+toggle_sidebar_label=ဖွင့်ပá€á€á€º ဆလá€á€¯á€€á€ºá€’ါ
+outline.title=စာá€á€™á€ºá€¸ မူကြမ်း ကá€á€¯á€•á€¼á€•á€«
+outline_label=စာá€á€™á€ºá€¸ မူကြမ်း
+attachments.title=á€á€½á€²á€á€»á€€á€ºá€™á€»á€¬á€¸ ပြပါ
+attachments_label=á€á€½á€²á€‘ားá€á€»á€€á€ºá€™á€»á€¬á€¸
+thumbs.title=ပုံရá€á€•á€ºá€„ယ်များကá€á€¯ ပြပါ
+thumbs_label=ပုံရá€á€•á€ºá€„ယ်များ
+findbar.title=Find in Document
+findbar_label=ရှာဖွေပါ
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=စာမျက်နှာ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=စာမျက်နှာရဲ့ ပုံရá€á€•á€ºá€„ယ် {{page}}
+
+# Find panel button title and messages
+find_label=ရှာဖွေပါ -
+find_previous.title=စကားစုရဲ့ အရင် ​ဖြစ်ပွားမှုကá€á€¯ ရှာဖွေပါ
+find_previous_label=နောက်သá€á€¯á€·
+find_next.title=စကားစုရဲ့ နောက်ထပ် ​ဖြစ်ပွားမှုကá€á€¯ ရှာဖွေပါ
+find_next_label=ရှေ့သá€á€¯á€·
+find_highlight=အားလုံးကá€á€¯ မျဉ်းသားပါ
+find_match_case_label=စာလုံး á€á€á€¯á€€á€ºá€†á€á€¯á€„်ပါ
+find_reached_top=စာမျက်နှာထá€á€•á€º ရောက်နေပြီአအဆုံးကနေ ပြန်စပါ
+find_reached_bottom=စာမျက်နှာအဆုံး ရောက်နေပြီአထá€á€•á€ºá€€á€”ေ ပြန်စပါ
+find_not_found=စကားစု မá€á€½á€±á€·á€›á€˜á€°á€¸
+
+# Error panel labels
+error_more_info=နောက်ထပ်အá€á€»á€€á€ºá€¡á€œá€€á€ºá€™á€»á€¬á€¸
+error_less_info=အနည်းငယ်မျှသော သá€á€„်းအá€á€»á€€á€ºá€¡á€œá€€á€º
+error_close=ပá€á€á€º
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=မက်ဆေ့ - {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=အထပ် - {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ဖá€á€¯á€„် {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=လá€á€¯á€„်း - {{line}}
+rendering_error=စာမျက်နှာကá€á€¯ ပုံဖော်နေá€á€»á€á€”်မှာ အမှားá€á€…်á€á€¯á€á€½á€±á€·á€›á€•á€«á€á€šá€ºá‹
+
+# Predefined zoom values
+page_scale_width=စာမျက်နှာ အကျယ်
+page_scale_fit=စာမျက်နှာ ကွက်á€á€
+page_scale_auto=အလá€á€¯á€¡á€œá€»á€±á€¬á€€á€º á€á€»á€¯á€¶á€·á€á€»á€²á€·
+page_scale_actual=အမှန်á€á€€á€šá€ºá€›á€¾á€á€á€²á€· အရွယ်
+
+# Loading indicator messages
+loading_error_indicator=အမှား
+loading_error=PDF ဖá€á€¯á€„် ကá€á€¯á€†á€½á€²á€á€„်နေá€á€»á€á€”်မှာ အမှားá€á€…်á€á€¯á€á€½á€±á€·á€›á€•á€«á€á€šá€ºá‹
+invalid_file_error=မရသော သá€á€¯á€· ပျက်နေသော PDF ဖá€á€¯á€„်
+missing_file_error=PDF ပျောက်ဆုံး
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} အဓá€á€•á€¹á€•á€¬á€šá€ºá€–ွင့်ဆá€á€¯á€á€»á€€á€º]
+password_label=PDF အားဖွင့်ရန် ပá€á€ºá€…်á€á€á€ºá€¡á€¬á€¸á€‘ည့်ပါ
+password_invalid=စာá€á€¾á€€á€º မှားသည်ዠထပ်ကြá€á€¯á€¸á€…ားကြည့်ပါá‹
+password_ok=OK
+password_cancel=ပယ်​ဖျက်ပါ
+
+printing_not_supported=သá€á€á€•á€±á€¸á€á€»á€€á€ºáŠá€•á€›á€„့်ထုá€á€ºá€á€¼á€„်းကá€á€¯á€¤á€˜á€šá€±á€¬á€€á€ºá€†á€¬á€žá€Šá€º ပြည့်á€á€…ွာထောက်ပံ့မထားပါ á‹
+printing_not_ready=သá€á€á€•á€±á€¸á€á€»á€€á€º: ယá€á€¯ PDF ဖá€á€¯á€„်သည် ပုံနှá€á€•á€ºá€›á€”် မပြည့်စုံပါ
+web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts.
+document_colors_disabled=PDF ဖá€á€¯á€„်အား áŽá€„်းဤ ကá€á€¯á€šá€ºá€•á€á€¯á€„်အရောင်များကá€á€¯ အသုံးပြုá€á€½á€„့်မပေးထားပါ á‹ 'စာမျက်နှာအားလုံးအားအရောင်ရွေးá€á€»á€šá€ºá€á€½á€„့်' အား ယá€á€¯ ဘယောက်ဆာá€á€½á€„် ပá€á€á€ºá€‘ားá€á€¼á€„်းကြောင့်ဖြစ် သှ်
diff --git a/static/pdf.js/locale/nb-NO/viewer.properties b/static/pdf.js/locale/nb-NO/viewer.properties
new file mode 100644
index 000000000..cce8cbf96
--- /dev/null
+++ b/static/pdf.js/locale/nb-NO/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Forrige side
+previous_label=Forrige
+next.title=Neste side
+next_label=Neste
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Side:
+page_of=av {{pageCount}}
+
+zoom_out.title=Zoom ut
+zoom_out_label=Zoom ut
+zoom_in.title=Zoom inn
+zoom_in_label=Zoom inn
+zoom.title=Zoom
+presentation_mode.title=Bytt til presentasjonsmodus
+presentation_mode_label=Presentasjonsmodus
+open_file.title=Ã…pne fil
+open_file_label=Ã…pne
+print.title=Skriv ut
+print_label=Skriv ut
+download.title=Last ned
+download_label=Last ned
+bookmark.title=Nåværende visning (kopier eller åpne i et nytt vindu)
+bookmark_label=Nåværende visning
+
+# Secondary toolbar and context menu
+tools.title=Verktøy
+tools_label=Verktøy
+first_page.title=Gå til første side
+first_page.label=Gå til første side
+first_page_label=Gå til første side
+last_page.title=GÃ¥ til siste side
+last_page.label=GÃ¥ til siste side
+last_page_label=GÃ¥ til siste side
+page_rotate_cw.title=Roter med klokken
+page_rotate_cw.label=Roter med klokken
+page_rotate_cw_label=Roter med klokken
+page_rotate_ccw.title=Roter mot klokken
+page_rotate_ccw.label=Roter mot klokken
+page_rotate_ccw_label=Roter mot klokken
+
+hand_tool_enable.title=Slå på hånd-verktøy
+hand_tool_enable_label=Slå på hånd-verktøy
+hand_tool_disable.title=Slå av hånd-verktøy
+hand_tool_disable_label=Slå av hånd-verktøy
+
+# Document properties dialog box
+document_properties.title=Dokumentegenskaper …
+document_properties_label=Dokumentegenskaper …
+document_properties_file_name=Filnavn:
+document_properties_file_size=Filstørrelse:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Tittel:
+document_properties_author=Forfatter:
+document_properties_subject=Emne:
+document_properties_keywords=Nøkkelord:
+document_properties_creation_date=Opprettet dato:
+document_properties_modification_date=Endret dato:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Opprettet av:
+document_properties_producer=PDF-verktøy:
+document_properties_version=PDF-versjon:
+document_properties_page_count=Sideantall:
+document_properties_close=Lukk
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Slå av/på sidestolpe
+toggle_sidebar_label=Slå av/på sidestolpe
+outline.title=Vis dokumentdisposisjon
+outline_label=Dokumentdisposisjon
+attachments.title=Vis vedlegg
+attachments_label=Vedlegg
+thumbs.title=Vis miniatyrbilde
+thumbs_label=Miniatyrbilde
+findbar.title=Finn i dokumentet
+findbar_label=Finn
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Side {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatyrbilde av side {{page}}
+
+# Find panel button title and messages
+find_label=Finn:
+find_previous.title=Finn forrige forekomst av frasen
+find_previous_label=Forrige
+find_next.title=Finn neste forekomst av frasen
+find_next_label=Neste
+find_highlight=Uthev alle
+find_match_case_label=Skill store/små bokstaver
+find_reached_top=NÃ¥dde toppen av dokumentet, fortsetter fra bunnen
+find_reached_bottom=NÃ¥dde bunnen av dokumentet, fortsetter fra toppen
+find_not_found=Fant ikke teksten
+
+# Error panel labels
+error_more_info=Mer info
+error_less_info=Mindre info
+error_close=Lukk
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (bygg: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Melding: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stakk: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fil: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linje: {{line}}
+rendering_error=En feil oppstod ved opptegning av siden.
+
+# Predefined zoom values
+page_scale_width=Sidebredde
+page_scale_fit=Tilpass til siden
+page_scale_auto=Automatisk zoom
+page_scale_actual=Virkelig størrelse
+
+# Loading indicator messages
+loading_error_indicator=Feil
+loading_error=En feil oppstod ved lasting av PDF.
+invalid_file_error=Ugyldig eller skadet PDF-fil.
+missing_file_error=Manglende PDF-fil.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} annotasjon]
+password_label=Skriv inn passordet for å åpne denne PDF-filen.
+password_invalid=Ugyldig passord. Prøv igjen.
+password_ok=OK
+password_cancel=Avbryt
+
+printing_not_supported=Advarsel: Utskrift er ikke fullstendig støttet av denne nettleseren.
+printing_not_ready=Advarsel: PDF er ikke fullstendig innlastet for utskrift.
+web_fonts_disabled=Web-fonter er avslått: Kan ikke bruke innbundne PDF-fonter.
+document_colors_disabled=PDF-dokumenter tillates ikke å bruke deres egne farger: 'Tillat sider å velge egne farger' er deaktivert i nettleseren.
diff --git a/static/pdf.js/locale/nl/viewer.properties b/static/pdf.js/locale/nl/viewer.properties
index 38f266d5f..d5ed70aeb 100644
--- a/static/pdf.js/locale/nl/viewer.properties
+++ b/static/pdf.js/locale/nl/viewer.properties
@@ -30,7 +30,7 @@ zoom_out_label=Uitzoomen
zoom_in.title=Inzoomen
zoom_in_label=Inzoomen
zoom.title=Zoomen
-presentation_mode.title=Omschakelen naar presentatiemodus
+presentation_mode.title=Wisselen naar presentatiemodus
presentation_mode_label=Presentatiemodus
open_file.title=Bestand openen
open_file_label=Openen
@@ -44,31 +44,53 @@ bookmark_label=Huidige weergave
# Secondary toolbar and context menu
tools.title=Hulpmiddelen
tools_label=Hulpmiddelen
-first_page.title=Naar de eerste pagina gaan
-first_page.label=Naar de eerste pagina gaan
-first_page_label=Naar de eerste pagina gaan
-last_page.title=Naar de laatste pagina gaan
-last_page.label=Naar de laatste pagina gaan
-last_page_label=Naar de laatste pagina gaan
-page_rotate_cw.title=Met de klok mee roteren
-page_rotate_cw.label=Met de klok mee roteren
-page_rotate_cw_label=Met de klok mee roteren
-page_rotate_ccw.title=Tegen de klok in roteren
-page_rotate_ccw.label=Tegen de klok in roteren
-page_rotate_ccw_label=Tegen de klok in roteren
+first_page.title=Naar eerste pagina gaan
+first_page.label=Naar eerste pagina gaan
+first_page_label=Naar eerste pagina gaan
+last_page.title=Naar laatste pagina gaan
+last_page.label=Naar laatste pagina gaan
+last_page_label=Naar laatste pagina gaan
+page_rotate_cw.title=Rechtsom draaien
+page_rotate_cw.label=Rechtsom draaien
+page_rotate_cw_label=Rechtsom draaien
+page_rotate_ccw.title=Linksom draaien
+page_rotate_ccw.label=Linksom draaien
+page_rotate_ccw_label=Linksom draaien
-hand_tool_enable.title=Handcursor inschakelen
-hand_tool_enable_label=Handcursor inschakelen
-hand_tool_disable.title=Handcursor uitschakelen
-hand_tool_disable_label=Handcursor uitschakelen
+hand_tool_enable.title=Handhulpmiddel inschakelen
+hand_tool_enable_label=Handhulpmiddel inschakelen
+hand_tool_disable.title=Handhulpmiddel uitschakelen
+hand_tool_disable_label=Handhulpmiddel uitschakelen
+
+# Document properties dialog box
+document_properties.title=Documenteigenschappen…
+document_properties_label=Documenteigenschappen…
+document_properties_file_name=Bestandsnaam:
+document_properties_file_size=Bestandsgrootte:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Titel:
+document_properties_author=Auteur:
+document_properties_subject=Onderwerp:
+document_properties_keywords=Trefwoorden:
+document_properties_creation_date=Aanmaakdatum:
+document_properties_modification_date=Wijzigingsdatum:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Auteur:
+document_properties_producer=PDF-producent:
+document_properties_version=PDF-versie:
+document_properties_page_count=Aantal pagina’s:
+document_properties_close=Sluiten
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Zijbalk tonen/verbergen
-toggle_sidebar_label=Zijbalk tonen/verbergen
-outline.title=Documentstructuur tonen
-outline_label=Documentstructuur
+toggle_sidebar.title=Zijbalk in-/uitschakelen
+toggle_sidebar_label=Zijbalk in-/uitschakelen
+outline.title=Documentoverzicht tonen
+outline_label=Documentoverzicht
+attachments.title=Bijlagen tonen
+attachments_label=Bijlagen
thumbs.title=Miniaturen tonen
thumbs_label=Miniaturen
findbar.title=Zoeken in document
@@ -90,8 +112,8 @@ find_next.title=Het volgende voorkomen van de tekst zoeken
find_next_label=Volgende
find_highlight=Alles markeren
find_match_case_label=Hoofdlettergevoelig
-find_reached_top=Bovenkant van de pagina bereikt, doorgegaan vanaf de onderkant
-find_reached_bottom=Onderkant van de pagina bereikt, doorgegaan vanaf de bovenkant
+find_reached_top=Bovenkant van het document bereikt, doorgegaan vanaf de onderkant
+find_reached_bottom=Onderkant van het document bereikt, doorgegaan vanaf de bovenkant
find_not_found=Tekst niet gevonden
# Error panel labels
@@ -100,7 +122,7 @@ error_less_info=Minder informatie
error_close=Sluiten
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js versie {{version}} (build {{build}})
+error_version_info=PDF.js v{{version}} (build: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
error_message=Bericht: {{message}}
@@ -111,19 +133,19 @@ error_stack=Stack: {{stack}}
error_file=Bestand: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Regel: {{line}}
-rendering_error=Er is een probleem opgetreden bij het renderen van de pagina.
+rendering_error=Er is een fout opgetreden bij het weergeven van de pagina.
# Predefined zoom values
-page_scale_width=Paginabreed maken
-page_scale_fit=Passend maken
+page_scale_width=Paginabreedte
+page_scale_fit=Hele pagina
page_scale_auto=Automatisch zoomen
page_scale_actual=Werkelijke grootte
# Loading indicator messages
loading_error_indicator=Fout
-loading_error=Er is een fout opgetreden bij het laden van het PDF-bestand.
-invalid_file_error=Ongeldig of corrupt PDF-bestand.
-missing_file_error=Ontbrekend PDF-bestand.
+loading_error=Er is een fout opgetreden bij het laden van de PDF.
+invalid_file_error=Ongeldig of beschadigd PDF-bestand.
+missing_file_error=PDF-bestand ontbreekt.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
@@ -131,11 +153,11 @@ missing_file_error=Ontbrekend PDF-bestand.
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
text_annotation_type.alt=[{{type}}-aantekening]
password_label=Voer het wachtwoord in om dit PDF-bestand te openen.
-password_invalid=Onjuist wachtwoord. Probeer het opnieuw.
+password_invalid=Ongeldig wachtwoord. Probeer het opnieuw.
password_ok=OK
password_cancel=Annuleren
printing_not_supported=Waarschuwing: afdrukken wordt niet volledig ondersteund door deze browser.
-printing_not_ready=Waarschuwing: het PDF-bestand is niet volledig geladen en kan daarom nog niet afgedrukt worden.
-web_fonts_disabled=Weblettertypen zijn uitgeschakeld: kan geen ingebakken PDF-lettertypen gebruiken.
-document_colors_disabled=PDF-documenten mogen hun eigen kleuren niet gebruiken. \"Pagina\'s toestaan om hun eigen kleuren te kiezen\" is uitgeschakeld in de browser.
+printing_not_ready=Warning: PDF is niet volledig geladen om af te drukken.
+web_fonts_disabled=Weblettertypen zijn uitgeschakeld: gebruik van ingebedde PDF-lettertypen is niet mogelijk.
+document_colors_disabled=PDF-documenten mogen hun eigen kleuren niet gebruiken: ‘Pagina’s toestaan om hun eigen kleuren te kiezen’ is uitgeschakeld in de browser.
diff --git a/static/pdf.js/locale/nn-NO/viewer.properties b/static/pdf.js/locale/nn-NO/viewer.properties
new file mode 100644
index 000000000..7b016f326
--- /dev/null
+++ b/static/pdf.js/locale/nn-NO/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Førre side
+previous_label=Førre
+next.title=Neste side
+next_label=Neste
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Side:
+page_of=av {{pageCount}}
+
+zoom_out.title=Mindre
+zoom_out_label=Mindre
+zoom_in.title=Større
+zoom_in_label=Større
+zoom.title=Skalering
+presentation_mode.title=Byt til presentasjonsmodus
+presentation_mode_label=Presentasjonsmodus
+open_file.title=Opna fil
+open_file_label=Opna
+print.title=Skriv ut
+print_label=Skriv ut
+download.title=Last ned
+download_label=Last ned
+bookmark.title=Gjeldande vising (kopier eller opna i nytt vindauge)
+bookmark_label=Gjeldande vising
+
+# Secondary toolbar and context menu
+tools.title=Verktøy
+tools_label=Verktøy
+first_page.title=Gå til første side
+first_page.label=Gå til første side
+first_page_label=Gå til første side
+last_page.title=GÃ¥ til siste side
+last_page.label=GÃ¥ til siste side
+last_page_label=GÃ¥ til siste side
+page_rotate_cw.title=Roter med klokka
+page_rotate_cw.label=Roter med klokka
+page_rotate_cw_label=Roter med klokka
+page_rotate_ccw.title=Roter mot klokka
+page_rotate_ccw.label=Roter mot klokka
+page_rotate_ccw_label=Roter mot klokka
+
+hand_tool_enable.title=Slå på handverktøy
+hand_tool_enable_label=Slå på handverktøy
+hand_tool_disable.title=Så av handverktøy
+hand_tool_disable_label=Slå av handverktøy
+
+# Document properties dialog box
+document_properties.title=Dokumenteigenskapar …
+document_properties_label=Dokumenteigenskapar …
+document_properties_file_name=Filnamn:
+document_properties_file_size=Filstorleik:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Dokumenteigenskapar …
+document_properties_author=Forfattar:
+document_properties_subject=Emne:
+document_properties_keywords=Nykelord:
+document_properties_creation_date=Dato oppretta:
+document_properties_modification_date=Dato endra:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Oppretta av:
+document_properties_producer=PDF-verktøy:
+document_properties_version=PDF-versjon:
+document_properties_page_count=Sidetal:
+document_properties_close=Lukk
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Slå av/på sidestolpe
+toggle_sidebar_label=Slå av/på sidestolpe
+outline.title=Vis dokumentdisposisjon
+outline_label=Dokumentdisposisjon
+attachments.title=Vis vedlegg
+attachments_label=Vedlegg
+thumbs.title=Vis miniatyrbilde
+thumbs_label=Miniatyrbilde
+findbar.title=Finn i dokumentet
+findbar_label=Finn
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Side {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatyrbilde av side {{page}}
+
+# Find panel button title and messages
+find_label=Finn:
+find_previous.title=Finn tidlegare førekomst av frasen
+find_previous_label=Førre
+find_next.title=Finn neste førekomst av frasen
+find_next_label=Neste
+find_highlight=Uthev alle
+find_match_case_label=Skil store/små bokstavar
+find_reached_top=Nådde toppen av dokumentet, held fram frå botnen
+find_reached_bottom=Nådde botnen av dokumentet, held fram frå toppen
+find_not_found=Fann ikkje teksten
+
+# Error panel labels
+error_more_info=Meir info
+error_less_info=Mindre info
+error_close=Lukk
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (bygg: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Melding: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stakk: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fil: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linje: {{line}}
+rendering_error=Ein feil oppstod ved oppteikning av sida.
+
+# Predefined zoom values
+page_scale_width=Sidebreidde
+page_scale_fit=Tilpass til sida
+page_scale_auto=Automatisk skalering
+page_scale_actual=Verkeleg storleik
+
+# Loading indicator messages
+loading_error_indicator=Feil
+loading_error=Ein feil oppstod ved lasting av PDF.
+invalid_file_error=Ugyldig eller korrupt PDF fil.
+missing_file_error=Manglande PDF-fil.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} annotasjon]
+password_label=Skriv inn passordet for å opna denne PDF-fila.
+password_invalid=Ugyldig passord. Prøv igjen.
+password_ok=OK
+password_cancel=Avbryt
+
+printing_not_supported=Åtvaring: Utskrift er ikkje fullstendig støtta av denne nettlesaren.
+printing_not_ready=Ã…tvaring: PDF ikkje fullstendig innlasta for utskrift.
+web_fonts_disabled=Vev-fontar er slått av: Kan ikkje bruka innbundne PDF-fontar.
+document_colors_disabled=PDF-dokument har ikkje løyve til å bruka eigne fargar: \'Tillat sider å velja eigne fargar\' er slått av i nettlesaren.
diff --git a/static/pdf.js/locale/nso/viewer.properties b/static/pdf.js/locale/nso/viewer.properties
new file mode 100644
index 000000000..09923f593
--- /dev/null
+++ b/static/pdf.js/locale/nso/viewer.properties
@@ -0,0 +1,123 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Letlakala le fetilego
+previous_label=Fetilego
+next.title=Letlakala le latelago
+next_label=Latelago
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Letlakala:
+page_of=la {{pageCount}}
+
+zoom_out.title=Bušetša ka gare
+zoom_out_label=Bušetša ka gare
+zoom_in.title=Godišetša ka ntle
+zoom_in_label=Godišetša ka ntle
+zoom.title=Godiša
+print.title=Gatiša
+print_label=Gatiša
+presentation_mode.title=Fetogela go mokgwa wa tlhagišo
+presentation_mode_label=Mokgwa wa tlhagišo
+open_file.title=Bula faele
+open_file_label=Bula
+download.title=Laolla
+download_label=Laolla
+bookmark.title=Pono ya bjale (kopiša le go bula lefasetereng le leswa)
+bookmark_label=Tebelelo ya gona bjale
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Å ielanya para ya ka thoko
+toggle_sidebar_label=Å ielanya para ya ka thoko
+outline.title=Laetša kakaretšo ya tokumente
+outline_label=Kakaretšo ya tokumente
+thumbs.title=Laetša dikhutšofatšo
+thumbs_label=Dikhutšofatšo
+findbar.title=Hwetša go tokumente
+findbar_label=Hwetša
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Letlakala {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Khutšofatšo ya letlakala {{page}}
+
+# Context menu
+first_page.label=Eya letlakaleng la mathomo
+last_page.label=Eya letlakaleng la mafelelo
+page_rotate_cw.label=Dikološa go ya ka go la go ja
+page_rotate_ccw.label=Dikološa go ya go la ntsogošo
+
+# Find panel button title and messages
+find_label=Hwetša:
+find_previous.title=Hwetša tiragalo e fetilego ya sekafoko
+find_previous_label=Fetilego
+find_next.title=Hwetša tiragalo e latelago ya sekafoko
+find_next_label=Latelago
+find_highlight=Bonagatša tšohle
+find_match_case_label=Swantšha kheisi
+find_reached_top=Fihlile godimo ga tokumente, go tšwetšwe pele go tloga tlase
+find_reached_bottom=Fihlile mafelelong a tokumente, go tšwetšwe pele go tloga godimo
+find_not_found=Sekafoko ga sa hwetšwa
+
+# Error panel labels
+error_more_info=Tshedimošo e oketšegilego
+error_less_info=Tshedimošo ya tlasana
+error_close=Tswalela
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Molaetša: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Mokgobo: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Faele: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Mothaladi: {{line}}
+rendering_error=Go diregile phošo ge go be go gafelwa letlakala.
+
+# Predefined zoom values
+page_scale_width=Bophara bja letlakala
+page_scale_fit=Go lekana ga letlakala
+page_scale_auto=Kgodišo ya maitirišo
+page_scale_actual=Bogolo bja kgonthe
+
+# Loading indicator messages
+loading_error_indicator=Phošo
+loading_error=Go diregile phošo ge go hlahlelwa PDF.
+invalid_file_error=Faele ye e sa Å¡omego goba e senyegilego ya PDF.
+missing_file_error=Faele yeo e sego gona ya PDF.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type=[{{type}} Tlhaloso]
+request_password=PDF e šireleditšwe ka lentšuphetišo:
+
+printing_not_supported=Temošo: Go gatiša ga go thekgwe ke praosara ye ka botlalo.
+printing_not_ready=Temošo: PDF ga ya hlahlelwa ka botlalo bakeng sa go gatišwa.
+web_fonts_disabled=Difonte tša wepe di šitišitšwe: ga e kgone go diriša difonte tša PDF tše khutišitšwego.
+web_colors_disabled=Mebala ya wepe e šitišitšwe.
diff --git a/static/pdf.js/locale/oc/viewer.properties b/static/pdf.js/locale/oc/viewer.properties
new file mode 100644
index 000000000..f80fcef9e
--- /dev/null
+++ b/static/pdf.js/locale/oc/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Pagina precedenta
+previous_label=Precedent
+next.title=Pagina seguenta
+next_label=Seguent
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pagina :
+page_of=sus {{pageCount}}
+
+zoom_out.title=Zoom arrièr
+zoom_out_label=Zoom arrièr
+zoom_in.title=Zoom avant
+zoom_in_label=Zoom avant
+zoom.title=Zoom
+presentation_mode.title=Bascuolar en mòde presentacion
+presentation_mode_label=Mòde Presentacion
+open_file.title=Dobrir lo fichièr
+open_file_label=Dobrir
+print.title=Imprimir
+print_label=Imprimir
+download.title=Telecargar
+download_label=Telecargar
+bookmark.title=Afichatge corrent (copiar o dobrir dins una fenèstra novèla)
+bookmark_label=Afichatge actual
+
+# Secondary toolbar and context menu
+tools.title=Aisinas
+tools_label=Aisinas
+first_page.title=Anar a la primièra pagina
+first_page.label=Anar a la primièra pagina
+first_page_label=Anar a la primièra pagina
+last_page.title=Anar a la darrièra pagina
+last_page.label=Anar a la darrièra pagina
+last_page_label=Anar a la darrièra pagina
+page_rotate_cw.title=Rotacion orà ria
+page_rotate_cw.label=Rotacion orà ria
+page_rotate_cw_label=Rotacion orà ria
+page_rotate_ccw.title=Rotacion antiorà ria
+page_rotate_ccw.label=Rotacion antiorà ria
+page_rotate_ccw_label=Rotacion antiorà ria
+
+hand_tool_enable.title=Activar l'aisina man
+hand_tool_enable_label=Activar l'aisina man
+hand_tool_disable.title=Desactivar l'aisina man
+hand_tool_disable_label=Desactivar l'aisina man
+
+# Document properties dialog box
+document_properties.title=Proprietats del document...
+document_properties_label=Proprietats del document...
+document_properties_file_name=Nom del fichièr :
+document_properties_file_size=Talha del fichièr :
+document_properties_kb={{size_kb}} Ko ({{size_b}} octets)
+document_properties_mb={{size_mb}} Mo ({{size_b}} octets)
+document_properties_title=TÃtol :
+document_properties_author=Autor :
+document_properties_subject=Subjècte :
+document_properties_keywords=Mots claus :
+document_properties_creation_date=Data de creacion :
+document_properties_modification_date=Data de modificacion :
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Creator :
+document_properties_producer=Aisina de conversion PDF :
+document_properties_version=Version PDF :
+document_properties_page_count=Nombre de paginas :
+document_properties_close=Tampar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Afichar/amagar lo panèl lateral
+toggle_sidebar_label=Afichar/amagar lo panèl lateral
+outline.title=Afichar los marcapaginas
+outline_label=Marcapaginas del document
+attachments.title=Visualizar las pèças juntas
+attachments_label=Pèças juntas
+thumbs.title=Afichar las vinhetas
+thumbs_label=Vinhetas
+findbar.title=Trobar dins lo document
+findbar_label=Recercar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pagina {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Vinheta de la pagina {{page}}
+
+# Find panel button title and messages
+find_label=Recercar
+find_previous.title=Tròba l'ocurréncia precedenta de la frasa
+find_previous_label=Precedent
+find_next.title=Tròba l'ocurréncia venenta de la frasa
+find_next_label=Seguent
+find_highlight=Suslinhar tot
+find_match_case_label=Respectar la cassa
+find_reached_top=Naut de la pagina atench, perseguida dempuèi lo bas
+find_reached_bottom=Bas de la pagina atench, perseguida al començament
+find_not_found=Frasa pas trobada
+
+# Error panel labels
+error_more_info=Mai de detalhs
+error_less_info=Mens d'informacions
+error_close=Tampar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (identificant de compilacion : {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Messatge : {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pila : {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fichièr : {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linha : {{line}}
+rendering_error=Una error s'es producha pendent l'afichatge de la pagina.
+
+# Predefined zoom values
+page_scale_width=Largor plena
+page_scale_fit=Pagina entièra
+page_scale_auto=Zoom automatic
+page_scale_actual=Talha vertadièra
+
+# Loading indicator messages
+loading_error_indicator=Error
+loading_error=Una error s'es producha pendent lo cargament del fichièr PDF.
+invalid_file_error=Fichièr PDF invalid o corromput.
+missing_file_error=Fichièr PDF mancant.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotacion {{type}}]
+password_label=Picatz lo senhal per dobrir aqueste fichièr PDF.
+password_invalid=Senhal incorrècte. Tornatz ensajar.
+password_ok=D'acòrdi
+password_cancel=Anullar
+
+printing_not_supported=Atencion : l'estampatge es pas completament gerit per aqueste navigador.
+printing_not_ready=Atencion : lo PDF es pas entièrament cargat per lo poder imprimir.
+web_fonts_disabled=Las poliças web son desactivadas : impossible d'utilizar las poliças integradas al PDF.
+document_colors_disabled=Los documents PDF pòdon pas utilizar lors pròprias colors : « Autorizar las paginas web d'utilizar lors pròprias colors » es desactivat dins lo navigador.
diff --git a/static/pdf.js/locale/or/viewer.properties b/static/pdf.js/locale/or/viewer.properties
new file mode 100644
index 000000000..4706f82e9
--- /dev/null
+++ b/static/pdf.js/locale/or/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=ପà‚ରàବ ପàƒà¬·àଠା
+previous_label=ପà‚ରàବ
+next.title=ପର ପàƒà¬·àଠା
+next_label=ପର
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=ପàƒà¬·àଠା:
+page_of={{pageCount}} ର
+
+zoom_out.title=ଛà‹à¬Ÿ କରନàତà
+zoom_out_label=ଛà‹à¬Ÿ କରନàତà
+zoom_in.title=ବଡ଼ କରନàତà
+zoom_in_label=ବଡ଼ କରନàତà
+zoom.title=ଛà‹à¬Ÿ ବଡ଼ କରନàତà
+presentation_mode.title=ଉପସàଥାପନ ଧାରାକà ବଦଳାନàତà
+presentation_mode_label=ଉପସàଥାପନ ଧାରା
+open_file.title=ଫାଇଲ ଖà‹à¬²à¬¨àତà
+open_file_label=ଖà‹à¬²à¬¨àତà
+print.title=ମàଦàରଣ
+print_label=ମàଦàରଣ
+download.title=ଆହରଣ
+download_label=ଆହରଣ
+bookmark.title=ପàରଚଳିତ ଦàƒà¬¶ààŸ (ନକଲ କରନàତà କିମàବା à¬à¬• ନà‚ତନ à±à¬¿à¬£àଡà‹à¬°à‡ ଖà‹à¬²à¬¨àତà)
+bookmark_label=ପàରଚଳିତ ଦàƒà¬¶ààŸ
+
+# Secondary toolbar and context menu
+tools.title=ସାଧନଗàଡ଼ିକ
+tools_label=ସାଧନଗàଡ଼ିକ
+first_page.title=ପàରଥମ ପàƒà¬·àଠାକà ଯାଆନàତà
+first_page.label=ପàରଥମ ପàƒà¬·àଠାକà ଯାଆନàତà
+first_page_label=ପàରଥମ ପàƒà¬·àଠାକà ଯାଆନàତà
+last_page.title=ଶà‡à¬· ପàƒà¬·àଠାକà ଯାଆନàତà
+last_page.label=ଶà‡à¬· ପàƒà¬·àଠାକà ଯାଆନàତà
+last_page_label=ଶà‡à¬· ପàƒà¬·àଠାକà ଯାଆନàତà
+page_rotate_cw.title=ଦକàଷିଣାବରàତàà¬¤à€ à¬˜àରାନàତà
+page_rotate_cw.label=ଦକàଷିଣାବରàତàà¬¤à€ à¬˜àରାନàତà
+page_rotate_cw_label=ଦକàଷିଣାବରàତàà¬¤à€ à¬˜àରାନàତà
+page_rotate_ccw.title=ବାମାବରàତàà¬¤à€ à¬˜àରାନàତà
+page_rotate_ccw.label=ବାମାବରàତàà¬¤à€ à¬˜àରାନàତà
+page_rotate_ccw_label=ବାମାବରàତàà¬¤à€ à¬˜àରାନàତà
+
+hand_tool_enable.title=ହସàତକàƒà¬¤ ସାଧନକà ସକàà¬°à¬¿àŸ à¬•à¬°à¬¨àତà
+hand_tool_enable_label=ହସàତକàƒà¬¤ ସାଧନକà ସକàà¬°à¬¿àŸ à¬•à¬°à¬¨àତà
+hand_tool_disable.title=ହସàତକàƒà¬¤ ସାଧନକà ନିଷàକàà¬°à¬¿àŸ à¬•à¬°à¬¨àତà
+hand_tool_disable_label=ହସàତକàƒà¬¤ ସାଧନକà ନିଷàକàà¬°à¬¿àŸ à¬•à¬°à¬¨àତà
+
+# Document properties dialog box
+document_properties.title=ଦଲିଲ ଗàଣଧରàମ…
+document_properties_label=ଦଲିଲ ଗàଣଧରàମ…
+document_properties_file_name=ଫାଇଲ ନାମ:
+document_properties_file_size=ଫାଇଲ ଆକାର:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=ଶà€à¬°àଷକ:
+document_properties_author=ଲà‡à¬–କ:
+document_properties_subject=ବିଷàŸ:
+document_properties_keywords=ସà‚ଚକ ଶବàଦ:
+document_properties_creation_date=ନିରàମାଣ ତାରିଖ:
+document_properties_modification_date=ପରିବରàତàତନ ତାରିଖ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ନିରàମାତା:
+document_properties_producer=PDF ପàରଯà‹à¬œà¬•:
+document_properties_version=PDF ସଂସàକରଣ:
+document_properties_page_count=ପàƒà¬·àଠା ଗଣନା:
+document_properties_close=ବନàଦ କରନàତà
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=ପାରàଶàà±à¬ªà¬Ÿà¬¿à¬•à ଆଗପଛ କରନàତà
+toggle_sidebar_label=ପାରàଶàà±à¬ªà¬Ÿà¬¿à¬•à ଆଗପଛ କରନàତà
+outline.title=ଦଲିଲ ସାରାଂଶ ଦରàଶାନàତà
+outline_label=ଦଲିଲ ସାରାଂଶ
+attachments.title=ସଂଲଗàନକଗàଡ଼ିକà ଦରàଶାନàତà
+attachments_label=ସଲଗàନକଗàଡିକ
+thumbs.title=ସଂକàଷିପàତ à¬¬à¬¿à¬¬à¬°à¬£à€ à¬¦à¬°àଶାନàତà
+thumbs_label=ସଂକàଷିପàତ ବିବରଣà€
+findbar.title=à¬¦à¬²à¬¿à¬²à¬°à‡ à¬–à‹à¬œà¬¨àତà
+findbar_label=ଖà‹à¬œà¬¨àତà
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=ପàƒà¬·àଠା {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=ପàƒà¬·àଠାର ସଂକàଷିପàତ à¬¬à¬¿à¬¬à¬°à¬£à€ {{page}}
+
+# Find panel button title and messages
+find_label=ଖà‹à¬œà¬¨àତà:
+find_previous.title=à¬à¬¹à¬¿ ବାକààŸà¬¾à¬‚ଶର ପà‚ରàବ ଉପସàଥିତିକà ଖà‹à¬œà¬¨àତà
+find_previous_label=ପà‚ରàବବରàତàତà€
+find_next.title=à¬à¬¹à¬¿ ବାକààŸà¬¾à¬‚ଶର ପରବରàତàà¬¤à€ à¬‰à¬ªà¬¸àଥିତିକà ଖà‹à¬œà¬¨àତà
+find_next_label=ପରବରàତàତà€\u0020
+find_highlight=ସମସàତଙàକà ଆଲà‹à¬•à¬¿à¬¤ କରନàତà
+find_match_case_label=ଅକàଷର ମà‡à¬³à¬¾à¬¨àତà
+find_reached_top=ତଳà ଉପରକà ଗତି କରି ଦଲିଲର ଉପର à¬à¬¾à¬—à¬°à‡ à¬ªà¬¹à¬žàଚି ଯାଇଛି
+find_reached_bottom=ଉପରà ତଳକà ଗତି କରି ଦଲିଲର ଶà‡à¬· à¬à¬¾à¬—à¬°à‡ à¬ªà¬¹à¬žàଚି ଯାଇଛି
+find_not_found=ବାକààŸà¬¾à¬‚ଶ ମିଳିଲା ନାହିà¬
+
+# Error panel labels
+error_more_info=ଅଧିକ ସà‚ଚନା
+error_less_info=ସàà±à¬³àପ ସà‚ଚନା
+error_close=ବନàଦ କରନàତà
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=ସନàଦà‡à¬¶: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ଷàଟାକ: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ଫାଇଲ: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=ଧାଡ଼ି: {{line}}
+rendering_error=ପàƒà¬·àଠା ଚିତàରଣ କରିବା ସମàŸà¬°à‡ ତàରàଟି ଘଟିଲା।
+
+# Predefined zoom values
+page_scale_width=ପàƒà¬·àଠା ଓସାର
+page_scale_fit=ପàƒà¬·àଠା ମà‡à¬³à¬¨
+page_scale_auto=ସàà±àŸà¬‚ଚାଳିତ à¬à¬¾à¬¬à¬°à‡ ଛà‹à¬Ÿà¬¬à¬¡à¬¼ କରିବା
+page_scale_actual=ପàରକàƒà¬¤ ଆକାର
+
+# Loading indicator messages
+loading_error_indicator=ତàରàଟି
+loading_error=PDF ଧାରଣ କରିବା ସମàŸà¬°à‡ à¬à¬• ତàରàଟି ଘଟିଲା।
+invalid_file_error=ଅବàˆà¬§ କିମàବା ତàରàଟିଯàକàତ PDF ଫାଇଲ।
+missing_file_error=ହଜିଯାଇଥିବା PDF ଫାଇଲ।
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Annotation]
+password_label=à¬à¬¹à¬¿ PDF ଫାଇଲକà ଖà‹à¬²à¬¿à¬¬à¬¾ ପାଇଠପàରବà‡à¬¶ ସଂକà‡à¬¤ à¬à¬°à¬£ କରନàତà।
+password_invalid=à¬àଲ ପàରବà‡à¬¶ ସଂକà‡à¬¤à¥¤ ଦàŸà¬¾à¬•à¬°à¬¿ ପàଣି ଚà‡à¬·àଟା କରନàତà।
+password_ok=ଠିକ ଅଛି
+password_cancel=ବାତିଲ କରନàତà
+
+printing_not_supported=ଚà‡à¬¤à¬¾à¬¬à¬¨à€: à¬à¬¹à¬¿ ବàରାଉଜର ଦàà±à¬¾à¬°à¬¾ ମàଦàରଣ କàରିàŸà¬¾ ସମàପà‚ରàଣàଣ à¬à¬¾à¬¬à¬°à‡ ସହାàŸà¬¤à¬¾ ପàରାପàତ ନàହà¬à¥¤
+printing_not_ready=ଚà‡à¬¤à¬¾à¬¬à¬¨à€: PDF ଟି ମàଦàରଣ ପାଇଠସମàପà‚ରàଣàଣ à¬à¬¾à¬¬à¬°à‡ ଧାରଣ ହà‹à¬‡ ନାହିà¬à¥¤
+web_fonts_disabled=à±à‡à¬¬ ଅକàଷରରà‚ପଗàଡ଼ିକà ନିଷàକàà¬°à¬¿àŸ à¬•à¬°à¬¾à¬¯à¬¾à¬‡à¬›à¬¿: ସନàନିହିତ PDF ଅକàଷରରà‚ପଗàଡ଼ିକà ବààŸà¬¬à¬¹à¬¾à¬° à¬•à¬°à¬¿à¬¬à¬¾à¬°à‡ à¬…à¬¸à¬®à¬°àଥ।
+document_colors_disabled=PDF ଦଲିଲଗàଡ଼ିକ ସà‡à¬®à¬¾à¬¨à¬™àକର ନିଜର ରଙàଗ ବààŸà¬¬à¬¹à¬¾à¬° କରିବା ପାଇଠଅନàମତି ପàରାପàତ ନàହà¬: 'ସà‡à¬®à¬¾à¬¨à¬™àକର ନିଜ ରଙàଗ ବାଛିବା ପାଇଠପàƒà¬·àଠାଗàଡ଼ିକà ଅନàମତି ଦିଅନàତà' କà ବàà¬°à¬¾à¬‰à¬œà¬°à¬°à‡ à¬¨à¬¿à¬·àକàà¬°à¬¿àŸ à¬•à¬°à¬¾à¬¯à¬¾à¬‡à¬›à¬¿à¥¤
diff --git a/static/pdf.js/locale/pa-IN/viewer.properties b/static/pdf.js/locale/pa-IN/viewer.properties
new file mode 100644
index 000000000..1b0fb3483
--- /dev/null
+++ b/static/pdf.js/locale/pa-IN/viewer.properties
@@ -0,0 +1,177 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=ਸਫ਼ਾ ਪਿੱਛੇ
+previous_label=ਪਿੱਛੇ
+next.title=ਸਫ਼ਾ ਅੱਗੇ
+next_label=ਅੱਗੇ
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=ਸਫ਼ਾ:
+page_of={{pageCount}} ਵਿੱਚੋਂ
+
+zoom_out.title=ਜ਼ੂਮ ਆਉਟ
+zoom_out_label=ਜ਼ੂਮ ਆਉਟ
+zoom_in.title=ਜ਼ੂਮ ਇਨ
+zoom_in_label=ਜ਼ੂਮ ਇਨ
+zoom.title=ਜ਼ੂਨ
+print.title=ਪਰਿੰਟ
+print_label=ਪਰਿੰਟ
+presentation_mode.title=ਪਰਿਜੈਂਟੇਸ਼ਨ ਮੋਡ ਵਿੱਚ ਜਾਓ
+presentation_mode_label=ਪਰਿਜੈਂਟੇਸ਼ਨ ਮੋਡ
+
+open_file.title=ਫਾਇਲ ਖੋਲà©à¨¹à©‹
+open_file_label=ਖੋਲà©à¨¹à©‹
+download.title=ਡਾਊਨਲੋਡ
+download_label=ਡਾਊਨਲੋਡ
+bookmark.title=ਮੌਜੂਦਾ à¨à¨²à¨• (ਨਵੀਂ ਵਿੰਡੋ ਵਿੱਚ ਕਾਪੀ ਕਰੋ ਜਾਂ ਖੋਲà©à¨¹à©‹)
+bookmark_label=ਮੌਜੂਦਾ à¨à¨²à¨•
+
+# Secondary toolbar and context menu
+tools.title=ਟੂਲ
+tools_label=ਟੂਲ
+first_page.title=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+first_page.label=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+first_page_label=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+
+last_page.title=ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+last_page_label=ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+page_rotate_cw.title=ਸੱਜੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨“
+page_rotate_cw.label=ਸੱਜੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨“
+page_rotate_cw_label=ਸੱਜੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨“
+page_rotate_ccw.title=ਖੱਬੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨“
+page_rotate_ccw_label=ਖੱਬੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨“
+
+hand_tool_enable.title=ਹੱਥ ਟੂਲ ਚਾਲੂ
+hand_tool_enable_label=ਹੱਥ ਟੂਲ ਚਾਲੂ
+hand_tool_disable.title=ਹੱਥ ਟੂਲ ਬੰਦ
+hand_tool_disable_label=ਹੱਥ ਟੂਲ ਬੰਦ
+
+# Document properties dialog box
+document_properties.title=…ਦਸਤਾਵੇਜ਼ ਵਿਸ਼ੇਸ਼ਤਾ
+document_properties_label=…ਦਸਤਾਵੇਜ਼ ਵਿਸ਼ੇਸ਼ਤਾ
+document_properties_file_name=ਫਾਇਲ ਨਾਂ:
+document_properties_file_size=ਫਾਇਲ ਆਕਾਰ:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=ਟਾਈਟਲ:
+document_properties_author=ਲੇਖਕ:
+document_properties_subject=ਵਿਸ਼ਾ:
+document_properties_keywords=ਸ਼ਬਦ:
+document_properties_creation_date=ਬਣਾਉਣ ਮਿਤੀ:
+document_properties_modification_date=ਸੋਧ ਮਿਤੀ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=ਨਿਰਮਾਤਾ:
+document_properties_producer=PDF ਪà©à¨°à©‹à¨¡à¨¿à¨Šà¨¸à¨°:
+document_properties_version=PDF ਵਰਜਨ:
+document_properties_page_count=ਸਫ਼ਾ ਗਿਣਤੀ:
+document_properties_close=ਬੰਦ ਕਰੋ
+
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=ਬਾਹੀ ਬਦਲੋ
+toggle_sidebar_label=ਬਾਹੀ ਬਦਲੋ
+
+outline.title=ਦਸਤਾਵੇਜ਼ ਆਉਟਲਾਈਨ ਵੇਖਾਓ
+outline_label=ਦਸਤਾਵੇਜ਼ ਆਉਟਲਾਈਨ
+attachments.title=Show Attachments
+attachments_label=Attachments
+thumbs.title=ਥੰਮਨੇਲ ਵੇਖਾਓ
+thumbs_label=ਥੰਮਨੇਲ
+findbar.title=ਦਸਤਾਵੇਜ਼ ਵਿੱਚ ਲੱà¨à©‹
+findbar_label=ਲੱà¨à©‹
+
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=ਸਫ਼ਾ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas={{page}} ਸਫ਼ੇ ਦਾ ਥੰਮਨੇਲ
+
+
+# Context menu
+first_page.label=ਪਹਿਲੇ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+last_page.label=ਆਖਰੀ ਸਫ਼ੇ ਉੱਤੇ ਜਾਓ
+page_rotate_cw.label=ਸੱਜੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨‰
+page_rotate_ccw.label=ਖੱਬੇ ਦਾਅ ਘà©à©°à¨®à¨¾à¨‰
+
+# Find panel button title and messages
+find_label=ਲੱà¨à©‹:
+find_previous.title=ਵਾਕ ਦੀ ਪਿਛਲੀ ਮੌਜੂਦਗੀ ਲੱà¨à©‹
+find_previous_label=ਪਿੱਛੇ
+find_next.title=ਵਾਕ ਦੀ ਅਗਲੀ ਮੌਜੂਦਗੀ ਲੱà¨à©‹
+find_next_label=ਅੱਗੇ
+find_highlight=ਸਠਉà¨à¨¾à¨°à©‹
+find_match_case_label=ਅੱਖਰ ਆਕਾਰ ਮਿਲਾਉ
+find_reached_top=ਦਸਤਾਵੇਜ਼ ਦੇ ਉੱਤੇ ਆ ਗਠਹਾਂ, ਥੱਲੇ ਤੋਂ ਜਾਰੀ ਰੱਖਿਆ ਹੈ
+find_reached_bottom=ਦਸਤਾਵੇਜ਼ ਦੇ ਅੰਤ ਉੱਤੇ ਆ ਗਠਹਾਂ, ਉੱਤੇ ਤੋਂ ਜਾਰੀ ਰੱਖਿਆ ਹੈ
+find_not_found=ਵਾਕ ਨਹੀਂ ਲੱà¨à¨¿à¨†
+
+
+# Error panel labels
+error_more_info=ਹੋਰ ਜਾਣਕਾਰੀ
+error_less_info=ਘੱਟ ਜਾਣਕਾਰੀ
+error_close=ਬੰਦ ਕਰੋ
+
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (ਬਿਲਡ: {{build}}
+
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=ਸà©à¨¨à©‡à¨¹à¨¾: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ਸਟੈਕ: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ਫਾਇਲ: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=ਲਾਈਨ: {{line}}
+rendering_error=ਸਫ਼ਾ ਰੈਡਰ ਕਰਨ ਦੇ ਦੌਰਾਨ ਗਲਤੀ ਆਈ ਹੈ।
+
+# Predefined zoom values
+page_scale_width=ਸਫ਼ਾ ਚੌੜਾਈ
+page_scale_fit=ਸਫ਼ਾ ਫਿੱਟ
+page_scale_auto=ਆਟੋਮੈਟਿਕ ਜ਼ੂਮ
+page_scale_actual=ਆਟੋਮੈਟਿਕ ਆਕਾਰ
+
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+loading_error_indicator=ਗਲਤੀ
+loading_error=PDF ਲੋਡ ਕਰਨ ਦੇ ਦੌਰਾਨ ਗਲਤੀ ਆਈ ਹੈ।
+invalid_file_error=ਗਲਤ ਜਾਂ ਨਿਕਾਰਾ PDF ਫਾਇਲ ਹੈ।
+missing_file_error=ਨਾ-ਮੌਜੂਦ PDF ਫਾਇਲ।
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} ਵਿਆਖਿਆ]
+password_label=ਇਹ PDF ਫਾਇਲ ਖੋਲà©à¨¹à¨£ ਲਈ ਪਾਸਵਰਡ ਦਿਉ।
+password_invalid=ਗਲਤ ਪਾਸਵਰਡ। ਫੇਰ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜੀ।
+password_ok=ਠੀਕ ਹੈ
+password_cancel=ਰੱਦ ਕਰੋ
+
+printing_not_supported=ਸਾਵਧਾਨ: ਇਹ ਬਰਾਊਜ਼ਰ ਪਰਿੰਟ ਕਰਨ ਲਈ ਪੂਰੀ ਤਰà©à¨¹à¨¾à¨‚ ਸਹਾਇਕ ਨਹੀਂ ਹੈ।
+printing_not_ready=ਸਾਵਧਾਨ: ਪੀਡੀà¨à¨«(PDF) ਪਰਿੰਟ ਕਰਨ ਲਈ ਪੂਰੀ ਤਰà©à¨¹à¨¾à¨‚ ਲੋਡ ਨਹੀਂ ਹੈ।
+web_fonts_disabled=ਵੈਬ ਫੋਂਟ ਬੰਦ ਹਨ: ਇੰਬੈਡ ਪੀਡੀà¨à¨« (PDF) ਫੋਂਟ ਵਰਤਨ ਲਈ ਅਸਮਰੱਥ ਹੈ।
+document_colors_disabled=PDF ਡੌਕੂਮੈਂਟ ਨੂੰ ਆਪਣੇ ਰੰਗ ਵਰਤਣ ਦੀ ਇਜ਼ਾਜ਼ਤ ਨਹੀਂ ਹੈ।: ਬਰਾਊਜ਼ਰ ਵਿੱਚ \u0022ਸਫ਼ਿਆਂ ਨੂੰ ਆਪਣੇ ਰੰਗ ਵਰਤਣ ਦਿਉ\u0022 ਨੂੰ ਬੰਦ ਕੀਤਾ ਹੋਇਆ ਹੈ।
\ No newline at end of file
diff --git a/static/pdf.js/locale/pl/viewer.properties b/static/pdf.js/locale/pl/viewer.properties
index 61c384776..d603cfee9 100644
--- a/static/pdf.js/locale/pl/viewer.properties
+++ b/static/pdf.js/locale/pl/viewer.properties
@@ -1,22 +1,12 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Main toolbar buttons (tooltips and alt text for images)
previous.title=Poprzednia strona
-previous_label=Wstecz
+previous_label=Poprzednia
next.title=Następna strona
-next_label=Dalej
+next_label=Następna
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
@@ -25,46 +15,73 @@ next_label=Dalej
page_label=Strona:
page_of=z {{pageCount}}
-zoom_out.title=Pomniejsz
+zoom_out.title=Pomniejszenie
zoom_out_label=Pomniejsz
-zoom_in.title=Powiększ
+zoom_in.title=Powiększenie
zoom_in_label=Powiększ
-zoom.title=Powiększenie
-presentation_mode.title=Przełącz do trybu prezentacji
+zoom.title=Skala
+presentation_mode.title=Przełącz na tryb prezentacji
presentation_mode_label=Tryb prezentacji
-open_file.title=Otwórz plik
+open_file.title=Otwieranie pliku
open_file_label=Otwórz
-print.title=Drukuj
+print.title=Drukowanie
print_label=Drukuj
-download.title=Pobierz
+download.title=Pobieranie
download_label=Pobierz
-bookmark.title=Aktualny widok (kopiuj lub otwórz w nowym oknie)
-bookmark_label=Aktualny widok
+bookmark.title=Bieżąca pozycja (skopiuj lub otwórz jako odnośnik w nowym oknie)
+bookmark_label=Bieżąca pozycja
-# Secondary toolbar and context menu
-first_page.title=Idź do pierwszej strony
-first_page.label=Idź do pierwszej strony
-first_page_label=Idź do pierwszej strony
-last_page.title=Idź do ostatniej strony
-last_page.label=Idź do ostatniej strony
-last_page_label=Idź do ostatniej strony
-page_rotate_cw.title=Obróć w prawo
-page_rotate_cw.label=Obróć w prawo
-page_rotate_cw_label=Obróć w prawo
-page_rotate_ccw.title=Obróć w lewo
-page_rotate_ccw.label=Obróć w lewo
-page_rotate_ccw_label=Obróć w lewo
+tools.title=Tools
+tools_label=Tools
+first_page.title=Przechodzenie do pierwszej strony
+first_page.label=Przejdź do pierwszej strony
+first_page_label=Przejdź do pierwszej strony
+last_page.title=Przechodzenie do ostatniej strony
+last_page.label=Przejdź do ostatniej strony
+last_page_label=Przejdź do ostatniej strony
+page_rotate_cw.title=Obracanie zgodnie z ruchem wskazówek zegara
+page_rotate_cw.label=Obróć zgodnie z ruchem wskazówek zegara
+page_rotate_cw_label=Obróć zgodnie z ruchem wskazówek zegara
+page_rotate_ccw.title=Obracanie przeciwnie do ruchu wskazówek zegara
+page_rotate_ccw.label=Obróć przeciwnie do ruchu wskazówek zegara
+page_rotate_ccw_label=Obróć przeciwnie do ruchu wskazówek zegara
+
+hand_tool_enable.title=Włączanie narzędzia rączka
+hand_tool_enable_label=Włącz narzędzie rączka
+hand_tool_disable.title=Wyłączanie narzędzia rączka
+hand_tool_disable_label=Wyłącz narzędzie rączka
+
+document_properties.title=Właściwości dokumentu…
+document_properties_label=Właściwości dokumentu…
+document_properties_file_name=Nazwa pliku:
+document_properties_file_size=Rozmiar pliku:
+document_properties_kb={{size_kb}} KB ({{size_b}} b)
+document_properties_mb={{size_mb}} MB ({{size_b}} b)
+document_properties_title=Tytuł:
+document_properties_author=Autor:
+document_properties_subject=Temat:
+document_properties_keywords=SÅ‚owa kluczowe:
+document_properties_creation_date=Data utworzenia:
+document_properties_modification_date=Data modyfikacji:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Utworzony przez:
+document_properties_producer=PDF wyprodukowany przez:
+document_properties_version=Wersja PDF:
+document_properties_page_count=Liczba stron:
+document_properties_close=Zamknij
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Pokaż/Ukryj panel boczny
-toggle_sidebar_label=Pokaż/Ukryj panel
-outline.title=Wyświetl konspekt dokumentu
-outline_label=Konspekt dokumentu
-thumbs.title=Wyświetl miniatury
-thumbs_label=Miniatury
-findbar.title=Szukaj w tekście
+toggle_sidebar.title=Przełączanie panelu bocznego
+toggle_sidebar_label=Przełącz panel boczny
+outline.title=Wyświetlanie zarysu dokumentu
+outline_label=Zarys dokumentu
+attachments.title=Wyświetlanie załączników
+attachments_label=Załączniki
+thumbs.title=Wyświetlanie miniaturek
+thumbs_label=Miniaturki
+findbar.title=Znajdź w dokumencie
findbar_label=Znajdź
# Thumbnails panel item (tooltip and alt text for images)
@@ -73,19 +90,19 @@ findbar_label=Znajdź
thumb_page_title=Strona {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=Miniatura strony {{page}}
+thumb_page_canvas=Miniaturka strony {{page}}
# Find panel button title and messages
find_label=Znajdź:
-find_previous.title=Znajdź poprzednie wystąpienie ostatnio szukanej frazy
+find_previous.title=Znajdź poprzednie wystąpienie tekstu
find_previous_label=Poprzednie
-find_next.title=Znajdź następne wystąpienie ostatnio szukanej frazy
+find_next.title=Znajdź następne wystąpienie tekstu
find_next_label=Następne
-find_highlight=Podświetl
-find_match_case_label=Rozróżniaj wielkość liter
-find_reached_top=Początek strony. Wyszukiwanie od końca.
-find_reached_bottom=Koniec strony. Wyszukiwanie od poczÄ…tku.
-find_not_found=Szukany tekst nie został odnaleziony.
+find_highlight=Podświetl wszystkie
+find_match_case_label=Rozróżniaj wielkość znaków
+find_reached_top=Osiągnięto początek dokumentu, kontynuacja od końca
+find_reached_bottom=Osiągnięto koniec dokumentu, kontynuacja od początku
+find_not_found=Tekst nieznaleziony
# Error panel labels
error_more_info=Więcej informacji
@@ -93,7 +110,7 @@ error_less_info=Mniej informacji
error_close=Zamknij
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=Wersja PDF.js: {{version}} (kompilacja: {{build}})
+error_version_info=PDF.js v{{version}} (kompilacja: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
error_message=Wiadomość: {{message}}
@@ -103,30 +120,32 @@ error_stack=Stos: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Plik: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=Linia: {{line}}
-rendering_error=Wystąpił błąd podczas wyświetlania strony.
+error_line=Wiersz: {{line}}
+rendering_error=Podczas renderowania strony wystąpił błąd.
# Predefined zoom values
page_scale_width=Szerokość strony
-page_scale_fit=Cała strona
-page_scale_auto=Automatyczne dopasowanie
-page_scale_actual=Rzeczywisty rozmiar
+page_scale_fit=Dopasowanie strony
+page_scale_auto=Skala automatyczna
+page_scale_actual=Rozmiar rzeczywisty
# Loading indicator messages
loading_error_indicator=BÅ‚Ä…d
-loading_error=Wystąpił błąd podczas wczytywania pliku PDF.
-invalid_file_error=Błędny lub uszkodzony plik PDF.
-missing_file_error=Nie znaleziono pliku PDF.
+loading_error=Podczas wczytywania dokumentu PDF wystąpił błąd.
+invalid_file_error=Nieprawidłowy lub uszkodzony plik PDF.
+missing_file_error=Brak pliku PDF.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
-# the PDF spec (32000-1:2008 Table 169 - Annotation types).
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[Komentarz {{type}}]
-request_password=Plik PDF jest chroniony przez hasło:
-invalid_password=Nieprawidłowe hasło.
+text_annotation_type.alt=[Adnotacja: {{type}}]
+password_label=Wprowadź hasło, aby otworzyć ten dokument PDF.
+password_invalid=Nieprawidłowe hasło. Proszę spróbować ponownie.
+password_ok=OK
+password_cancel=Anuluj
-printing_not_supported=Ostrzeżenie: Drukowanie nie jest w pełni obsługiwane przez tę przeglądarkę.
-printing_not_ready=Ostrzeżenie: Plik PDF nie jest całkowicie wczytany do drukowania.
-web_fonts_disabled=Web fonty są nieaktywne. Nie można korzystać z osadzonych czcionek w plikach PDF.
-document_colors_disabled=Dokumenty PDF nie mają pozwolenia na korzystanie z ich własnych kolorów: \'Pozwalaj stronom stosować inne kolory niż ustawione tutaj\' nie jest aktywne w przeglądarce.
+printing_not_supported=Ostrzeżenie: Drukowanie nie jest w pełni wspierane przez przeglądarkę.
+printing_not_ready=Ostrzeżenie: Dokument PDF nie jest całkowicie wczytany, więc nie można go wydrukować.
+web_fonts_disabled=Czcionki sieciowe są wyłączone: nie można użyć osadzonych czcionek PDF.
+document_colors_disabled=Dokumenty PDF nie mogą używać własnych kolorów: Opcja „Pozwalaj stronom stosować inne kolory†w przeglądarce jest nieaktywna.
diff --git a/static/pdf.js/locale/pt-BR/viewer.properties b/static/pdf.js/locale/pt-BR/viewer.properties
index edea5f11c..ec40786f2 100644
--- a/static/pdf.js/locale/pt-BR/viewer.properties
+++ b/static/pdf.js/locale/pt-BR/viewer.properties
@@ -12,33 +12,152 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-bookmark.title=Marcar posição atual (bookmark)
+# Main toolbar buttons (tooltips and alt text for images)
previous.title=Página anterior
+previous_label=Anterior
next.title=Próxima página
+next_label=Próxima
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Página:
+page_of=de {{pageCount}}
+
+zoom_out.title=Diminuir zoom
+zoom_out_label=Diminuir zoom
+zoom_in.title=Aumentar zoom
+zoom_in_label=Aumentar zoom
+zoom.title=Zoom
+presentation_mode.title=Alternar para modo de apresentação
+presentation_mode_label=Modo de apresentação
+open_file.title=Abrir arquivo
+open_file_label=Abrir
print.title=Imprimir
-download.title=Baixar arquivo
-zoom_out.title=Diminuir Zoom
-zoom_in.title=Aumentar Zoom
+print_label=Imprimir
+download.title=Download
+download_label=Download
+bookmark.title=Visualização atual (copie ou abra em nova janela)
+bookmark_label=Visualização atual
+
+# Secondary toolbar and context menu
+tools.title=Ferramentas
+tools_label=Ferramentas
+first_page.title=Ir para a primeira página
+first_page.label=Ir para a primeira página
+first_page_label=Ir para a primeira página
+last_page.title=Ir para a última página
+last_page.label=Ir para a última página
+last_page_label=Ir para a última página
+page_rotate_cw.title=Girar no sentido horário
+page_rotate_cw.label=Girar no sentido horário
+page_rotate_cw_label=Girar no sentido horário
+page_rotate_ccw.title=Girar no sentido anti-horário
+page_rotate_ccw.label=Girar no sentido anti-horário
+page_rotate_ccw_label=Girar no sentido anti-horário
+
+hand_tool_enable.title=Ativar ferramenta da mão
+hand_tool_enable_label=Ativar ferramenta da mão
+hand_tool_disable.title=Desativar ferramenta da mão
+hand_tool_disable_label=Desativar ferramenta da mão
+
+# Document properties dialog box
+document_properties.title=Propriedades do documento…
+document_properties_label=Propriedades do documento…
+document_properties_file_name=Nome do arquivo:
+document_properties_file_size=Tamanho do arquivo:
+document_properties_kb={{size_kb}}\u202fKB ({{size_b}} bytes)
+document_properties_mb={{size_mb}}\u202fMB ({{size_b}} bytes)
+document_properties_title=TÃtulo:
+document_properties_author=Autor:
+document_properties_subject=Assunto:
+document_properties_keywords=Palavras-chave:
+document_properties_creation_date=Data da criação:
+document_properties_modification_date=Data da modificação:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Criação:
+document_properties_producer=Criador do PDF:
+document_properties_version=Versão do PDF:
+document_properties_page_count=Contagem de páginas:
+document_properties_close=Fechar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Exibir/ocultar painel
+toggle_sidebar_label=Exibir/ocultar painel
+outline.title=Exibir estrutura de tópicos
+outline_label=Estrutura de tópicos do documento
+attachments.title=Exibir anexos
+attachments_label=Anexos
+thumbs.title=Exibir miniaturas das páginas
+thumbs_label=Miniaturas
+findbar.title=Localizar no documento
+findbar_label=Localizar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Página {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura da página {{page}}
+
+# Find panel button title and messages
+find_label=Localizar:
+find_previous.title=Localizar a ocorrência anterior do texto
+find_previous_label=Anterior
+find_next.title=Localizar a próxima ocorrência do texto
+find_next_label=Próxima
+find_highlight=Realçar tudo
+find_match_case_label=Diferenciar maiúsculas/minúsculas
+find_reached_top=Atingido o inÃcio do documento, continuando do fim
+find_reached_bottom=Atingido o fim do documento, continuando do inÃcio
+find_not_found=Texto não encontrado
+
+# Error panel labels
error_more_info=Mais informações
error_less_info=Menos informações
error_close=Fechar
-error_build=PDF.JS Versão: {{build}}
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
error_message=Mensagem: {{message}}
-error_stack=Pilha: {{stack}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Arquivo: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Linha: {{line}}
+rendering_error=Ocorreu um erro ao renderizar a página.
+
+# Predefined zoom values
page_scale_width=Largura da página
-page_scale_fit=Página inteira
+page_scale_fit=Ajustar à janela
page_scale_auto=Zoom automático
-page_scale_actual=Tamanho original
-toggle_slider.title=Abrir/fechar aba lateral
-thumbs.title=Mostrar miniaturas
-outline.title=Mostrar Ãndice
-loading=Carregando... {{percent}}%
+page_scale_actual=Tamanho real
+
+# Loading indicator messages
loading_error_indicator=Erro
-loading_error=Um erro ocorreu ao carregar o arquivo.
-rendering_error=Um erro ocorreu ao apresentar a página.
-page_label=Página:
-page_of=de {{pageCount}}
-open_file.title=Abrir arquivo
-text_annotation_type.alt=[{{type}} Anotações]
+loading_error=Ocorreu um erro ao carregar o PDF.
+invalid_file_error=Arquivo PDF corrompido ou inválido.
+missing_file_error=Arquivo PDF ausente.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotação {{type}}]
+password_label=Forneça a senha para abrir este arquivo PDF.
+password_invalid=Senha inválida. Por favor, tente de novo.
+password_ok=OK
+password_cancel=Cancelar
+
+printing_not_supported=Alerta: a impressão não é totalmente suportada neste navegador.
+printing_not_ready=Alerta: o PDF não está totalmente carregado para impressão.
+web_fonts_disabled=Fontes da web estão desativadas: não é possÃvel usar fontes incorporadas do PDF.
+document_colors_disabled=Documentos PDF não estão permitidos a usar suas próprias cores: “Páginas podem usar outras cores†está desativado no navegador.
diff --git a/static/pdf.js/locale/pt-PT/viewer.properties b/static/pdf.js/locale/pt-PT/viewer.properties
new file mode 100644
index 000000000..43ec85baa
--- /dev/null
+++ b/static/pdf.js/locale/pt-PT/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Página anterior
+previous_label=Anterior
+next.title=Página seguinte
+next_label=Seguinte
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Página:
+page_of=de {{pageCount}}
+
+zoom_out.title=Reduzir
+zoom_out_label=Reduzir
+zoom_in.title=Ampliar
+zoom_in_label=Ampliar
+zoom.title=Ampliação
+presentation_mode.title=Mudar para modo de apresentação
+presentation_mode_label=Modo de apresentação
+open_file.title=Abrir ficheiro
+open_file_label=Abrir
+print.title=Imprimir
+print_label=Imprimir
+download.title=Transferir
+download_label=Transferir
+bookmark.title=Vista atual (copiar ou abrir em nova janela)
+bookmark_label=Vista atual
+
+# Secondary toolbar and context menu
+tools.title=Ferramentas
+tools_label=Ferramentas
+first_page.title=Ir para a primeira página
+first_page.label=Ir para a primeira página
+first_page_label=Ir para a primeira página
+last_page.title=Ir para a última página
+last_page.label=Ir para a última página
+last_page_label=Ir para a última página
+page_rotate_cw.title=Rodar à direita
+page_rotate_cw.label=Rodar à direita
+page_rotate_cw_label=Rodar à direita
+page_rotate_ccw.title=Rodar à esquerda
+page_rotate_ccw.label=Rodar à esquerda
+page_rotate_ccw_label=Rodar à esquerda
+
+hand_tool_enable.title=Ativar ferramenta de mão
+hand_tool_enable_label=Ativar ferramenta de mão
+hand_tool_disable.title=Desativar ferramenta de mão
+hand_tool_disable_label=Desativar ferramenta de mão
+
+# Document properties dialog box
+document_properties.title=Propriedades do documento...
+document_properties_label=Propriedades do documento...
+document_properties_file_name=Nome do ficheiro:
+document_properties_file_size=Tamanho do ficheiro:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=TÃtulo:
+document_properties_author=Autor:
+document_properties_subject=Assunto:
+document_properties_keywords=Palavras-chave:
+document_properties_creation_date=Data de criação:
+document_properties_modification_date=Data de modificação:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Criador:
+document_properties_producer=Produtor de PDF:
+document_properties_version=versão do PDF:
+document_properties_page_count=N.º de páginas:
+document_properties_close=Fechar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Comutar barra lateral
+toggle_sidebar_label=Comutar barra lateral
+outline.title=Mostrar estrutura do documento
+outline_label=Estrutura do documento
+attachments.title=Mostrar anexos
+attachments_label=Anexos
+thumbs.title=Mostrar miniaturas
+thumbs_label=Miniaturas
+findbar.title=Localizar no documento
+findbar_label=Localizar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Página {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura da página {{page}}
+
+# Find panel button title and messages
+find_label=Localizar:
+find_previous.title=Localizar a ocorrência anterior
+find_previous_label=Anterior
+find_next.title=Localizar a ocorrência seguinte
+find_next_label=Seguinte
+find_highlight=Destacar tudo
+find_match_case_label=Correspondência
+find_reached_top=InÃcio de documento atingido, a continuar do fim
+find_reached_bottom=Fim da página atingido, a continuar do inÃcio
+find_not_found=Frase não encontrada
+
+# Error panel labels
+error_more_info=Mais informação
+error_less_info=Menos informação
+error_close=Fechar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (compilação: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mensagem: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Pilha: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Ficheiro: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linha: {{line}}
+rendering_error=Ocorreu um erro ao processar a página.
+
+# Predefined zoom values
+page_scale_width=Ajustar à largura
+page_scale_fit=Ajustar à página
+page_scale_auto=Tamanho automático
+page_scale_actual=Tamanho real
+
+# Loading indicator messages
+loading_error_indicator=Erro
+loading_error=Ocorreu um erro ao carregar o PDF.
+invalid_file_error=Ficheiro PDF inválido ou danificado.
+missing_file_error=Ficheiro PDF inexistente.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotação {{type}}]
+password_label=Introduza a senha para abrir este PDF.
+password_invalid=Senha inválida. Tente novamente.
+password_ok=OK
+password_cancel=Cancelar
+
+printing_not_supported=Aviso: a impressão não é totalmente suportada por este navegador.
+printing_not_ready=Aviso: o PDF ainda não está totalmente carregado.
+web_fonts_disabled=Os tipos de letra web estão desativados: não é possÃvel utilizar os tipos de letra PDF incorporados.
+document_colors_disabled=Os documentos PDF não permitem a utilização das suas próprias cores: \'Autorizar as páginas a escolher as suas próprias cores\' está desativado no navegador.
diff --git a/static/pdf.js/locale/rm/viewer.properties b/static/pdf.js/locale/rm/viewer.properties
new file mode 100644
index 000000000..924f51e2a
--- /dev/null
+++ b/static/pdf.js/locale/rm/viewer.properties
@@ -0,0 +1,153 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Pagina precedenta
+previous_label=Enavos
+next.title=Proxima pagina
+next_label=Enavant
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pagina:
+page_of=da {{pageCount}}
+
+zoom_out.title=Empitschnir
+zoom_out_label=Empitschnir
+zoom_in.title=Engrondir
+zoom_in_label=Engrondir
+zoom.title=Zoom
+presentation_mode.title=Midar en il modus da preschentaziun
+presentation_mode_label=Modus da preschentaziun
+open_file.title=Avrir datoteca
+open_file_label=Avrir
+print.title=Stampar
+print_label=Stampar
+download.title=Telechargiar
+download_label=Telechargiar
+bookmark.title=Vista actuala (copiar u avrir en ina nova fanestra)
+bookmark_label=Vista actuala
+
+# Secondary toolbar and context menu
+tools.title=Utensils
+tools_label=Utensils
+first_page.title=Siglir a l'emprima pagina
+first_page.label=Siglir a l'emprima pagina
+first_page_label=Siglir a l'emprima pagina
+last_page.title=Siglir a la davosa pagina
+last_page.label=Siglir a la davosa pagina
+last_page_label=Siglir a la davosa pagina
+page_rotate_cw.title=Rotar en direcziun da l'ura
+page_rotate_cw.label=Rotar en direcziun da l'ura
+page_rotate_cw_label=Rotar en direcziun da l'ura
+page_rotate_ccw.title=Rotar en direcziun cuntraria a l'ura
+page_rotate_ccw.label=Rotar en direcziun cuntraria a l'ura
+page_rotate_ccw_label=Rotar en direcziun cuntraria a l'ura
+
+hand_tool_enable.title=Activar l'utensil da maun
+hand_tool_enable_label=Activar l'utensil da maun
+hand_tool_disable.title=Deactivar l'utensil da maun
+hand_tool_disable_label=Deactivar l'utensil da maun
+
+# Document properties dialog box
+document_properties.title=Caracteristicas dal document…
+document_properties_label=Caracteristicas dal document…
+document_properties_file_name=Num da la datoteca:
+document_properties_file_size=Grondezza da la datoteca:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=Titel:
+document_properties_author=Autur:
+document_properties_subject=Tema:
+document_properties_keywords=Chavazzins:
+document_properties_creation_date=Data da creaziun:
+document_properties_modification_date=Data da modificaziun:
+document_properties_date_string={{date}} {{time}}
+document_properties_creator=Creà da:
+document_properties_producer=Creà il PDF cun:
+document_properties_version=Versiun da PDF:
+document_properties_page_count=Dumber da paginas:
+document_properties_close=Serrar
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Activar/deactivar la trav laterala
+toggle_sidebar_label=Activar/deactivar la trav laterala
+outline.title=Mussar la structura da la pagina
+outline_label=Structura da la pagina
+attachments.title=Mussar agiuntas
+attachments_label=Agiuntas
+thumbs.title=Mussar las miniaturas
+thumbs_label=Miniaturas
+findbar.title=Tschertgar en il document
+findbar_label=Tschertgar
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pagina {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura da la pagina {{page}}
+
+# Find panel button title and messages
+find_label=Tschertgar:
+find_previous.title=Tschertgar la posiziun precedenta da l'expressiun
+find_previous_label=Enavos
+find_next.title=Tschertgar la proxima posiziun da l'expressiun
+find_next_label=Enavant
+find_highlight=Relevar tuts
+find_match_case_label=Resguardar maiusclas/minusclas
+find_reached_top=Il cumenzament dal document è cuntanschì, la tschertga cuntinuescha a la fin dal document
+find_reached_bottom=La fin dal document è cuntanschì, la tschertga cuntinuescha al cumenzament dal document
+find_not_found=Impussibel da chattar l'expressiun
+
+# Error panel labels
+error_more_info=Dapli infurmaziuns
+error_less_info=Damain infurmaziuns
+error_close=Serrar
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Messadi: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Datoteca: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Lingia: {{line}}
+rendering_error=Ina errur è cumparida cun visualisar questa pagina.
+
+# Predefined zoom values
+page_scale_width=Ladezza da la pagina
+page_scale_fit=Entira pagina
+page_scale_auto=Zoom automatic
+page_scale_actual=Grondezza actuala
+
+# Loading indicator messages
+loading_error_indicator=Errur
+loading_error=Ina errur è cumparida cun chargiar il PDF.
+invalid_file_error=Datoteca PDF nunvalida u donnegiada.
+missing_file_error=Datoteca PDF manconta.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Annotaziun da {{type}}]
+password_label=Endatescha il pled-clav per avrir questa datoteca da PDF.
+password_invalid=Pled-clav nunvalid. Emprova anc ina giada.
+password_ok=OK
+password_cancel=Interrumper
+
+printing_not_supported=Attenziun: Il stampar na funcziunescha anc betg dal tut en quest navigatur.
+printing_not_ready=Attenziun: Il PDF n'è betg chargià cumplettamain per stampar.
+web_fonts_disabled=Scrittiras dal web èn deactivadas: impussibel dad utilisar las scrittiras integradas en il PDF.
+document_colors_disabled=Documents da PDF na pon betg utilisar lur atgnas colurs: \'Permetter a las paginas d'utilisar lur atgnas colurs empè da las colurs tschernidas survart\' è deactivà en il navigatur.
diff --git a/static/pdf.js/locale/ro/viewer.properties b/static/pdf.js/locale/ro/viewer.properties
index ae37ec72d..20d2d95f7 100644
--- a/static/pdf.js/locale/ro/viewer.properties
+++ b/static/pdf.js/locale/ro/viewer.properties
@@ -12,44 +12,152 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-bookmark.title=Vederea curentă (copiază sau deschide în fereastră nouă)
+# Main toolbar buttons (tooltips and alt text for images)
previous.title=Pagina precedentă
-next.title=Pagina următoare
-print.title=Tipărește
-download.title=Descarcă
-zoom_out.title=Micșorează
-zoom_in.title=Mărește
-error_more_info=Detaliat
-error_less_info=Sumarizat
-error_close=ÃŽnchide
-error_build=PDF.JS Build: {{build}}
-error_message=Message: {{message}}
-error_stack=Stack: {{stack}}
-error_file=File: {{file}}
-error_line=Line: {{line}}
-page_scale_width=După lățime
-page_scale_fit=Toată pagina
-page_scale_auto=Mărime automată
-page_scale_actual=Mărime originală
-toggle_slider.title=Vedere de ansamblu
-thumbs.title=Miniaturi
-outline.title=Cuprins
-loading=Încărcare... {{percent}}%
-loading_error_indicator=Eroare
-loading_error=S-a produs o eroare în timpul încărcării documentului.
-rendering_error=S-a produs o eroare în timpul procesării paginii.
-page_label=Pagina:
-page_of=din {{pageCount}}
-open_file.title=Deschide fișier
-text_annotation_type.alt=[Adnotare {{type}}]
-toggle_slider_label=Vedere de ansamblu
-thumbs_label=Miniaturi
-outline_label=Cuprins
-bookmark_label=Vederea curentă
previous_label=ÃŽnapoi
+next.title=Pagina următoare
next_label=ÃŽnainte
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pagină:
+page_of=din {{pageCount}}
+
+zoom_out.title=Depărtează
+zoom_out_label=Depărtează
+zoom_in.title=Apropie
+zoom_in_label=Apropie
+zoom.title=Panoramează
+presentation_mode.title=Schimbă la modul de prezentare
+presentation_mode_label=Mod de prezentare
+open_file.title=Deschide un fișier
+open_file_label=Deschide
+print.title=Tipărește
print_label=Tipărește
+download.title=Descarcă
download_label=Descarcă
-zoom_out_label=Micșorează
-zoom_in_label=Mărește
-zoom.title=Mărime
+bookmark.title=Vizualizare curentă (copiați sau deschideți într-o fereastră nouă)
+bookmark_label=Vizualizare curentă
+
+# Secondary toolbar and context menu
+tools.title=Unelte
+tools_label=Unelte
+first_page.title=Mergi la prima pagină
+first_page.label=Mergeți la prima pagină
+first_page_label=Mergi la prima pagină
+last_page.title=Mergi la ultima pagină
+last_page.label=Mergi la ultima pagină
+last_page_label=Mergi la ultima pagină
+page_rotate_cw.title=Rotește în sensul acelor de ceasornic
+page_rotate_cw.label=Rotește în sensul acelor de ceasornic
+page_rotate_cw_label=Rotește în sensul acelor de ceasornic
+page_rotate_ccw.title=Rotește în sens invers al acelor de ceasornic
+page_rotate_ccw.label=Rotate Counter-Clockwise
+page_rotate_ccw_label=Rotește în sens invers acelor de ceasornic
+
+hand_tool_enable.title=Activează instrumentul mână
+hand_tool_enable_label=Activează instrumentul mână
+hand_tool_disable.title=Dezactivează instrumentul mână
+hand_tool_disable_label=Dezactivează instrumentul mână
+
+# Document properties dialog box
+document_properties.title=Proprietățile documentului…
+document_properties_label=Proprietățile documentului…
+document_properties_file_name=Nume fișier:
+document_properties_file_size=Dimensiune fișier:
+document_properties_kb={{size_kb}} KB ({{size_b}} biți)
+document_properties_mb={{size_mb}} MB ({{size_b}} biți)
+document_properties_title=Titlu:
+document_properties_author=Autor:
+document_properties_subject=Subiect:
+document_properties_keywords=Cuvinte cheie:
+document_properties_creation_date=Data creării:
+document_properties_modification_date=Data modificării:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Autor:
+document_properties_producer=Producător PDF:
+document_properties_version=Versiune PDF:
+document_properties_page_count=Număr de pagini:
+document_properties_close=ÃŽnchidere
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Comută bara laterală
+toggle_sidebar_label=Comută bara laterală
+outline.title=Arată schița documentului
+outline_label=Schiță document
+attachments.title=Afișează atașamentele
+attachments_label=Atașamente
+thumbs.title=Arată miniaturi
+thumbs_label=Miniaturi
+findbar.title=Caută în document
+findbar_label=Căutați
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pagina {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatura paginii {{page}}
+
+# Find panel button title and messages
+find_label=Caută:
+find_previous.title=Găsește instanța anterioară în frază
+find_previous_label=Anterior
+find_next.title=Găstește următoarea instanță în frază
+find_next_label=Următor
+find_highlight=Evidențiază aparițiile
+find_match_case_label=Potrivire litere
+find_reached_top=Am ajuns la începutul documentului, continuă de la sfârșit
+find_reached_bottom=Am ajuns la sfârșitul documentului, continuă de la început
+find_not_found=Nu s-a găsit textul
+
+# Error panel labels
+error_more_info=Mai multe informații
+error_less_info=Mai puțină informație
+error_close=ÃŽnchide
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (varianta: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mesaj: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stivă: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fișier: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linie: {{line}}
+rendering_error=A intervenit o eroare la afișarea paginii.
+
+# Predefined zoom values
+page_scale_width=Lățime pagină
+page_scale_fit=Potrivire la pagină
+page_scale_auto=Dimensiune automată
+page_scale_actual=Dimensiune reală
+
+# Loading indicator messages
+loading_error_indicator=Eroare
+loading_error=A intervenit o eroare la încărcarea fișierului PDF.
+invalid_file_error=Fișier PDF invalid sau deteriorat.
+missing_file_error=Fișier PDF lipsă.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Adnotare]
+password_label=Introduceți parola pentru a deschide acest fişier PDF.
+password_invalid=Parolă greșită. Vă rugăm încercați din nou.
+password_ok=OK
+password_cancel=Renunță
+
+printing_not_supported=Atenție: Tipărirea nu este suportată în totalitate de acest navigator.
+printing_not_ready=Avertisment: Fișierul PDF nu este încărcat complet pentru tipărire.
+web_fonts_disabled=Fonturile web sunt dezactivate: nu pot utiliza fonturile PDF încorporate.
+document_colors_disabled=Documentele PDF nu sunt autorizate să folosească propriile culori: 'Permite paginilor să aleagă propriile culori' este dezactivată în navigator.
diff --git a/static/pdf.js/locale/ru/viewer.properties b/static/pdf.js/locale/ru/viewer.properties
index f86b601a2..b2de0fe69 100644
--- a/static/pdf.js/locale/ru/viewer.properties
+++ b/static/pdf.js/locale/ru/viewer.properties
@@ -1,62 +1,109 @@
-# Copyright 2012 Mozilla Foundation
-#
-# 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.
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-bookmark.title=СÑылка на текущий вид (Ñкопировать или открыть в новом окне)
-previous.title=ÐŸÑ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ Ñтраница
-next.title=Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ñтраница
-print.title=Печать
-download.title=Загрузить
-zoom_out.title=Уменьшить
-zoom_in.title=Увеличить
-error_more_info=Детали
-error_less_info=Скрыть детали
-error_close=Закрыть
-error_build=PDF.JS компилÑциÑ: {{build}}
-error_message=Сообщение: {{message}}
-error_stack=Стeк: {{stack}}
-error_file=Файл: {{file}}
-error_line=Строка: {{line}}
-page_scale_width=По ширине Ñтраницы
-page_scale_fit=Во вÑÑŽ Ñтраницу
-page_scale_auto=Ðвто
-page_scale_actual=ÐаÑтоÑщий размер
-toggle_slider.title=Открыть/закрыть вÑпомогательную панель
-thumbs.title=Показать уменьшенные изображениÑ
-outline.title=Показать Ñодержание документа
-loading=Загрузка... {{percent}}%
-loading_error_indicator=Ошибка
-loading_error=Произошла ошибка во Ð²Ñ€ÐµÐ¼Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ¸ PDF.
-rendering_error=Произошла ошибка во Ð²Ñ€ÐµÐ¼Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñтраницы.
-page_label=Страница:
-page_of=из {{pageCount}}
-open_file.title=Открыть файл
-text_annotation_type.alt=[ÐÐ½Ð½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ {{type}}]
-toggle_slider_label=Ð’ÑÐ¿Ð¾Ð¼Ð¾Ð³Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¿Ð°Ð½ÐµÐ»ÑŒ
-thumbs_label=Уменьшенные изображениÑ
-outline_label=Содержание документа
-bookmark_label=Текущий вид
-previous_label=ПредыдущаÑ
-next_label=СледующаÑ
-print_label=Печать
-download_label=Загрузить
-zoom_out_label=Уменьшить
-zoom_in_label=Увеличить
-zoom.title=МаÑштаб
-thumb_page_title=Страница {{page}}
-thumb_page_canvas=Уменьшенное изображение Ñтраницы {{page}}
-request_password=PDF защищён паролем:
-fullscreen.title=Полный Ñкран
-fullscreen_label=Полный Ñкран
-page_rotate_cw.label=Повернуть по чаÑовой Ñтрелке
-page_rotate_ccw.label=Повернуть против чаÑовой Ñтрелки
+previous.title = ÐŸÑ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ Ñтраница
+previous_label = ПредыдущаÑ
+next.title = Ð¡Ð»ÐµÐ´ÑƒÑŽÑ‰Ð°Ñ Ñтраница
+next_label = СледующаÑ
+page_label = Страница:
+page_of = из {{pageCount}}
+zoom_out.title = Уменьшить
+zoom_out_label = Уменьшить
+zoom_in.title = Увеличить
+zoom_in_label = Увеличить
+zoom.title = МаÑштаб
+presentation_mode.title = Перейти в режим презентации
+presentation_mode_label = Режим презентации
+open_file.title = Открыть файл
+open_file_label = Открыть
+print.title = Печать
+print_label = Печать
+download.title = Загрузить
+download_label = Загрузить
+bookmark.title = СÑылка на текущий вид (Ñкопировать или открыть в новом окне)
+bookmark_label = Текущий вид
+tools.title = ИнÑтрументы
+tools_label = ИнÑтрументы
+first_page.title = Перейти на первую Ñтраницу
+first_page.label = Перейти на первую Ñтраницу
+first_page_label = Перейти на первую Ñтраницу
+last_page.title = Перейти на поÑледнюю Ñтраницу
+last_page.label = Перейти на поÑледнюю Ñтраницу
+last_page_label = Перейти на поÑледнюю Ñтраницу
+page_rotate_cw.title = Повернуть по чаÑовой Ñтрелке
+page_rotate_cw.label = Повернуть по чаÑовой Ñтрелке
+page_rotate_cw_label = Повернуть по чаÑовой Ñтрелке
+page_rotate_ccw.title = Повернуть против чаÑовой Ñтрелки
+page_rotate_ccw.label = Повернуть против чаÑовой Ñтрелки
+page_rotate_ccw_label = Повернуть против чаÑовой Ñтрелки
+hand_tool_enable.title = Включить ИнÑтрумент «Рука»
+hand_tool_enable_label = Включить ИнÑтрумент «Рука»
+hand_tool_disable.title = Отключить ИнÑтрумент «Рука»
+hand_tool_disable_label = Отключить ИнÑтрумент «Рука»
+document_properties.title = СвойÑтва документа…
+document_properties_label = СвойÑтва документа…
+document_properties_file_name = Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°:
+document_properties_file_size = Размер файла:
+document_properties_kb = {{size_kb}} КБ ({{size_b}} байт)
+document_properties_mb = {{size_mb}} МБ ({{size_b}} байт)
+document_properties_title = Заголовок:
+document_properties_author = Ðвтор:
+document_properties_subject = Тема:
+document_properties_keywords = Ключевые Ñлова:
+document_properties_creation_date = Дата ÑозданиÑ:
+document_properties_modification_date = Дата изменениÑ:
+document_properties_date_string = {{date}}, {{time}}
+document_properties_creator = Приложение:
+document_properties_producer = Производитель PDF:
+document_properties_version = ВерÑÐ¸Ñ PDF:
+document_properties_page_count = ЧиÑло Ñтраниц:
+document_properties_close = Закрыть
+toggle_sidebar.title = Открыть/закрыть боковую панель
+toggle_sidebar_label = Открыть/закрыть боковую панель
+outline.title = Показать Ñодержание документа
+outline_label = Содержание документа
+attachments.title = Показать вложениÑ
+attachments_label = ВложениÑ
+thumbs.title = Показать миниатюры
+thumbs_label = Миниатюры
+findbar.title = Ðайти в документе
+findbar_label = Ðайти
+thumb_page_title = Страница {{page}}
+thumb_page_canvas = Миниатюра Ñтраницы {{page}}
+find_label = Ðайти:
+find_previous.title = Ðайти предыдущее вхождение фразы в текÑÑ‚
+find_previous_label = Ðазад
+find_next.title = Ðайти Ñледующее вхождение фразы в текÑÑ‚
+find_next_label = Далее
+find_highlight = ПодÑветить вÑе
+find_match_case_label = С учётом региÑтра
+find_reached_top = ДоÑтигнут верх документа, продолжено Ñнизу
+find_reached_bottom = ДоÑтигнут конец документа, продолжено Ñверху
+find_not_found = Фраза не найдена
+error_more_info = Детали
+error_less_info = Скрыть детали
+error_close = Закрыть
+error_version_info = PDF.js v{{version}} (Ñборка: {{build}})
+error_message = Сообщение: {{message}}
+error_stack = Стeк: {{stack}}
+error_file = Файл: {{file}}
+error_line = Строка: {{line}}
+rendering_error = При Ñоздании Ñтраницы произошла ошибка.
+page_scale_width = По ширине Ñтраницы
+page_scale_fit = По размеру Ñтраницы
+page_scale_auto = ÐвтоматичеÑки
+page_scale_actual = Реальный размер
+loading_error_indicator = Ошибка
+loading_error = При загрузке PDF произошла ошибка.
+invalid_file_error = Ðекорректный или повреждённый PDF-файл.
+missing_file_error = PDF-файл отÑутÑтвует.
+text_annotation_type.alt = [ÐÐ½Ð½Ð¾Ñ‚Ð°Ñ†Ð¸Ñ {{type}}]
+password_label = Введите пароль, чтобы открыть Ñтот PDF-файл.
+password_invalid = Ðеверный пароль. ПожалуйÑта, попробуйте Ñнова.
+password_ok = OK
+password_cancel = Отмена
+printing_not_supported = Предупреждение: Ð’ Ñтом браузере не полноÑтью поддерживаетÑÑ Ð¿ÐµÑ‡Ð°Ñ‚ÑŒ.
+printing_not_ready = Предупреждение: PDF не полноÑтью загружен Ð´Ð»Ñ Ð¿ÐµÑ‡Ð°Ñ‚Ð¸.
+web_fonts_disabled = Веб-шрифты отключены: невозможно иÑпользовать вÑтроенные PDF-шрифты.
+document_colors_disabled = PDF-документам не разрешено иÑпользовать Ñвои цвета: в браузере отключён параметр «Разрешить веб-Ñайтам иÑпользовать Ñвои цвета».
diff --git a/static/pdf.js/locale/rw/viewer.properties b/static/pdf.js/locale/rw/viewer.properties
new file mode 100644
index 000000000..993c48483
--- /dev/null
+++ b/static/pdf.js/locale/rw/viewer.properties
@@ -0,0 +1,123 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Previous Page
+previous_label=Previous
+next.title=Next Page
+next_label=Next
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Page:
+page_of=of {{pageCount}}
+
+zoom_out.title=Zoom Out
+zoom_out_label=Zoom Out
+zoom_in.title=Zoom In
+zoom_in_label=Zoom In
+zoom.title=Ihindurangano
+print.title=Print
+print_label=Print
+presentation_mode.title=Switch to Presentation Mode
+presentation_mode_label=Presentation Mode
+open_file.title=Gufungura Dosiye
+open_file_label=Gufungura
+download.title=Download
+download_label=Download
+bookmark.title=Current view (copy or open in new window)
+bookmark_label=Current View
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Toggle Sidebar
+toggle_sidebar_label=Toggle Sidebar
+outline.title=Show Document Outline
+outline_label=Document Outline
+thumbs.title=Show Thumbnails
+thumbs_label=Thumbnails
+findbar.title=Find in Document
+findbar_label=Gushakisha
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Page {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Thumbnail of Page {{page}}
+
+# Context menu
+first_page.label=Go to First Page
+last_page.label=Go to Last Page
+page_rotate_cw.label=Rotate Clockwise
+page_rotate_ccw.label=Rotate Counterclockwise
+
+# Find panel button title and messages
+find_label="Gushaka:"
+find_previous.title=Gushaka aho uyu murongo ugaruka mbere y'aha
+find_previous_label=Previous
+find_next.title=Gushaka aho uyu murongo wongera kugaruka
+find_next_label=Next
+find_highlight=Highlight all
+find_match_case_label=Match case
+find_reached_top=Reached top of document, continued from bottom
+find_reached_bottom=Reached end of document, continued from top
+find_not_found=Umurongo ntubonetse
+
+# Error panel labels
+error_more_info=More Information
+error_less_info=Less Information
+error_close=Gufunga
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Message: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=File: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Line: {{line}}
+rendering_error=An error occurred while rendering the page.
+
+# Predefined zoom values
+page_scale_width=Page Width
+page_scale_fit=Page Fit
+page_scale_auto=Automatic Zoom
+page_scale_actual=Actual Size
+
+# Loading indicator messages
+loading_error_indicator=Ikosa
+loading_error=An error occurred while loading the PDF.
+invalid_file_error=Invalid or corrupted PDF file.
+missing_file_error=Missing PDF file.
+
+# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type=[{{type}} Annotation]
+request_password=PDF is protected by a password:
+
+printing_not_supported=Warning: Printing is not fully supported by this browser.
+printing_not_ready=Warning: The PDF is not fully loaded for printing.
+web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts.
+web_colors_disabled=Web colors are disabled.
diff --git a/static/pdf.js/locale/sah/viewer.properties b/static/pdf.js/locale/sah/viewer.properties
new file mode 100644
index 000000000..49d1f49ba
--- /dev/null
+++ b/static/pdf.js/locale/sah/viewer.properties
@@ -0,0 +1,122 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Инники ÑирÑй
+previous_label=ИннинÑÑҕи
+next.title=ÐныгыÑкы ÑирÑй
+next_label=ÐныгыÑкы
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=СирÑй:
+page_of=мантан {{pageCount}}
+
+zoom_out.title=Куччат
+zoom_out_label=Куччат
+zoom_in.title=Улаатыннар
+zoom_in_label=Улаатыннар
+zoom.title=Улаатыннар
+presentation_mode.title=Көрдөрөр ÑÑ€ÑÑиимҥÑ
+presentation_mode_label=Көрдөрөр ÑÑ€ÑÑиим
+open_file.title=БилÑни арый
+open_file_label=ÐÑ
+print.title=БÑчÑÑÑ‚
+print_label=БÑчÑÑÑ‚
+download.title=Хачайдааһын
+download_label=Хачайдааһын
+bookmark.title=Билиҥҥи көÑÑ‚Ò¯Ò¯Ñ‚Ñ (хатылаа ÑбÑÑ‚ÑÑ€ Ñаҥа Ñ‚Ò¯Ð½Ð½Ò¯ÐºÐºÑ Ð°Ñ€Ñ‹Ð¹)
+bookmark_label=Билиҥҥи көÑтүүтÑ
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_title=Баһа:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=ÐžÐ¹Ð¾Ò•Ð¾Ñ Ñ…Ð°Ð¿Ñ‚Ð°Ð»Ñ‹ арый/Ñап
+toggle_sidebar_label=ÐžÐ¹Ð¾Ò•Ð¾Ñ Ñ…Ð°Ð¿Ñ‚Ð°Ð»Ñ‹ арый/Ñап
+outline.title=Дөкүмүөн иһинÑÑҕитин көрдөр
+outline_label=Дөкүмүөн иһинÑÑҕитÑ
+thumbs.title=Ойуучааннары көрдөр
+thumbs_label=Ойуучааннар
+findbar.title=ДөкүмүөнтÑн бул
+findbar_label=Бул
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=СирÑй {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=СирÑй ойуучаана {{page}}
+
+# Find panel button title and messages
+find_label=Бул:
+find_previous.title=Ðтии тиÑкиÑÐºÑ Ð±Ñƒ иннинÑÑҕи киириитин бул
+find_previous_label=ИннинÑÑҕи
+find_next.title=Ðтии тиÑкиÑÐºÑ Ð±Ñƒ кÑннинÑÑҕи киириитин бул
+find_next_label=ÐныгыÑкы
+find_highlight=Барытын Ñырдатан көрдөр
+find_match_case_label=Буукуба улаханын-кыратын араар
+find_reached_top=СирÑй үрдүгÑÑ€ тиийдиҥ, Ñалгыыта аллара
+find_reached_bottom=СирÑй бүттÑ, Ò¯Ó©Ò»Ñ Ñалҕанна
+find_not_found=Ðтии көÑтүбÑÑ‚Ñ
+
+# Error panel labels
+error_more_info=Сиһилии
+error_less_info=Сиһилиитин киÑÑ‚ÑÑ
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (хомуйуута: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Ðтии: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Стeк: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=БилÑ: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=УÑтуруока: {{line}}
+rendering_error=СирÑйи айарга Ð°Ð»Ò•Ð°Ñ Ñ‚Ð°Ò•Ñ‹Ñта.
+
+# Predefined zoom values
+page_scale_width=СирÑй кÑтитинÑн
+page_scale_fit=СирÑй кÑÑмÑйинÑн
+page_scale_auto=Ðптамаатынан
+page_scale_actual=ДьиҥнÑÑÑ… кÑÑмÑйÑ
+
+# Loading indicator messages
+loading_error_indicator=ÐлҕаÑ
+loading_error=PDF-билÑни хачайдыырга Ð°Ð»Ò•Ð°Ñ Ñ‚Ð°Ò•Ñ‹Ñта.
+invalid_file_error=Туох ÑÑ€Ñ Ð°Ð»Ò•Ð°Ñтаах ÑбÑÑ‚ÑÑ€ алдьаммыт PDF-билÑ.
+missing_file_error=PDF-Ð±Ð¸Ð»Ñ Ñуох.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} туһунан]
+password_cancel=Салҕаама
+
+printing_not_supported=СÑÑ€Ñтии: Бу браузер бÑчÑÑттиири толору өйөөбөт.
+printing_not_ready=СÑÑ€Ñтии: PDF бÑчÑÑÑ‚Ñ‚Ð¸Ð¸Ñ€Ð³Ñ Ñ‚Ð¾Ð»Ð¾Ñ€Ñƒ хачайдана илик.
+web_fonts_disabled=Ситим-бичиктÑÑ€ араарыллыахтара: PDF бичиктÑÑ€Ñ ÐºÑ‹Ð°Ð¹Ð°Ð½ көÑтүбÑÑ‚Ñ‚ÑÑ€.
+document_colors_disabled=PDF-дөкүмүөүннÑÑ€Ð³Ñ Ð±ÑйÑлÑрин өҥнөрүн туттар көҥүллÑммÑÑ‚Ñ: "Ситим-ÑирдÑÑ€ бÑйÑлÑрин өҥнөрүн тутталларын көҥүллүүргÑ" диÑн браузерга арахÑа Ñылдьар Ñбит.
diff --git a/static/pdf.js/locale/si/viewer.properties b/static/pdf.js/locale/si/viewer.properties
new file mode 100644
index 000000000..84e5c89c0
--- /dev/null
+++ b/static/pdf.js/locale/si/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=මීට පෙර පිටුව
+previous_label=පෙර
+next.title=මීළඟ පිටුව
+next_label=මීළඟ
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=පිටුව:
+page_of={{pageCount}} කින්
+
+zoom_out.title=කුඩ෠කරන්න
+zoom_out_label=කුඩ෠කරන්න
+zoom_in.title=විà·à·à¶½ කරන්න
+zoom_in_label=විà·à·à¶½ කරන්න
+zoom.title=විà·à·à¶½à¶«à¶º
+presentation_mode.title=ඉදිරිපà¶à·Šà¶šà·’රීම් ප්â€à¶»à¶šà·à¶»à¶º වෙචමà·à¶»à·”වන්න
+presentation_mode_label=ඉදිරිපà¶à·Šà¶šà·’රීම් ප්â€à¶»à¶šà·à¶»à¶º
+open_file.title=ගොනුව විවෘචකරන්න
+open_file_label=විවෘචකරන්න
+print.title=මුද්â€à¶»à¶«à¶º
+print_label=මුද්â€à¶»à¶«à¶º
+download.title=බà·à¶œà¶±à·Šà¶±
+download_label=බà·à¶œà¶±à·Šà¶±
+bookmark.title=දà·à¶±à¶§ ඇà¶à·’ දසුන (පිටපà¶à·Š කරන්න හ෠නව කවුළුවක විවෘචකරන්න)
+bookmark_label=දà·à¶±à¶§ ඇà¶à·’ දසුන
+
+# Secondary toolbar and context menu
+tools.title=මෙවලම්
+tools_label=මෙවලම්
+first_page.title=මුල් පිටුවට යන්න
+first_page.label=මුල් පිටුවට යන්න
+first_page_label=මුල් පිටුවට යන්න
+last_page.title=අවසන් පිටුවට යන්න
+last_page.label=අවසන් පිටුවට යන්න
+last_page_label=අවසන් පිටුවට යන්න
+page_rotate_cw.title=දක්à·à·’ණà·à·€à¶»à·Šà¶à·€ භ්â€à¶»à¶¸à¶«à¶º
+page_rotate_cw.label=දක්à·à·’ණà·à·€à¶»à·Šà¶à·€ භ්â€à¶»à¶¸à¶«à¶º
+page_rotate_cw_label=දක්à·à·’ණà·à·€à¶»à·Šà¶à·€ භ්â€à¶»à¶¸à¶«à¶º
+page_rotate_ccw.title=à·€à·à¶¸à·à·€à¶»à·Šà¶à·€ භ්â€à¶»à¶¸à¶«à¶º
+page_rotate_ccw.label=à·€à·à¶¸à·à·€à¶»à·Šà¶à·€ භ්â€à¶»à¶¸à¶«à¶º
+page_rotate_ccw_label=à·€à·à¶¸à·à·€à¶»à·Šà¶à·€ භ්â€à¶»à¶¸à¶«à¶º
+
+hand_tool_enable.title=හස්චමෙවලම සක්â€à¶»à·“ය
+hand_tool_enable_label=හස්චමෙවලම සක්â€à¶»à·“ය
+hand_tool_disable.title=හස්චමෙවලම අක්â€à¶»à·“ය
+hand_tool_disable_label=හස්චමෙවලම අක්â€à¶»à·“ය
+
+# Document properties dialog box
+document_properties.title=ලේඛන à·€à¶à·Šà¶šà¶¸à·Š...
+document_properties_label=ලේඛන à·€à¶à·Šà¶šà¶¸à·Š...
+document_properties_file_name=ගොනු නම:
+document_properties_file_size=ගොනු ප්â€à¶»à¶¸à·à¶«à¶º:
+document_properties_kb={{size_kb}} KB ({{size_b}} බයිට)
+document_properties_mb={{size_mb}} MB ({{size_b}} බයිට)
+document_properties_title=සිරස්à¶à¶½à¶º:
+document_properties_author=කà¶à·²
+document_properties_subject=මà·à¶à·˜à¶šà·à·€:
+document_properties_keywords=යà¶à·”රු වදන්:
+document_properties_creation_date=නිර්මිචදිනය:
+document_properties_modification_date=වෙනස්කල දිනය:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=නිර්මà·à¶´à¶š:
+document_properties_producer=PDF නිà·à·Šà¶´à·à¶¯à¶š:
+document_properties_version=PDF නිකුà¶à·”à·€:
+document_properties_page_count=පිටු ගණන:
+document_properties_close=වසන්න
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=පà·à¶à·’ à¶à·“රුවට මà·à¶»à·”වන්න
+toggle_sidebar_label=පà·à¶à·’ à¶à·“රුවට මà·à¶»à·”වන්න
+outline.title=ලේඛනයේ පිට මà·à¶ºà·’ම පෙන්වන්න
+outline_label=ලේඛනයේ පිට මà·à¶ºà·’ම
+attachments.title=ඇමිණුම් පෙන්වන්න
+attachments_label=ඇමිණුම්
+thumbs.title=සිඟිà¶à·’ රූ පෙන්වන්න
+thumbs_label=සිඟිà¶à·’ රූ
+findbar.title=ලේඛනය à¶à·”à·… සොයන්න
+findbar_label=සොයන්න
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=පිටුව {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=පිටුවෙ සිඟිචරූව {{page}}
+
+# Find panel button title and messages
+find_label=සොයන්න:
+find_previous.title=මේ à·€à·à¶šà·Šâ€à¶º ඛණ්ඩය මීට පෙර යෙදුණු ස්ථà·à¶±à¶º සොයන්න
+find_previous_label=පෙර:
+find_next.title=මේ à·€à·à¶šà·Šâ€à¶º ඛණ්ඩය මීළඟට යෙදෙන ස්ථà·à¶±à¶º සොයන්න
+find_next_label=මීළඟ
+find_highlight=සියල්ල උද්දීපනය
+find_match_case_label=අකුරු ගළපන්න
+find_reached_top=පිටුවේ ඉහළ කෙළවරට ලගà·à·€à·’ය, පහළ සිට ඉදිරියට යමින්
+find_reached_bottom=පිටුවේ පහළ කෙළවරට ලගà·à·€à·’ය, ඉහළ සිට ඉදිරියට යමින්
+find_not_found=ඔබ සෙව් වචන හමු නොවීය
+
+# Error panel labels
+error_more_info=බොහ෠à¶à·œà¶»à¶à·”රු
+error_less_info=අවම à¶à·œà¶»à¶à·”රු
+error_close=වසන්න
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (නිකුà¶à·”à·€: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=පණිවිඩය: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ගොනුව: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=පේළිය: {{line}}
+rendering_error=පිටුව රෙන්ඩර් විමේදි ගà·à¶§à¶½à·”වක් හට ගà·à¶±à·”ණි.
+
+# Predefined zoom values
+page_scale_width=පිටුවේ පළල
+page_scale_fit=පිටුවට සුදුසු ලෙස
+page_scale_auto=ස්වයංක්â€à¶»à·“ය විà·à·à¶½à¶«à¶º
+page_scale_actual=නියමිචප්â€à¶»à¶¸à·à¶«à¶º
+
+# Loading indicator messages
+loading_error_indicator=දà·à·‚ය
+loading_error=PDF පූරණය විමේදි දà·à·‚යක් හට ගà·à¶±à·”ණි.
+invalid_file_error=දූà·à·’චහ෠සà·à·€à¶¯à·Šâ€à¶º PDF ගොනුව.
+missing_file_error=නà·à¶à·’වූ PDF ගොනුව.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} විස්à¶à¶»à¶º]
+password_label=මෙම PDF ගොනුව විවෘචකිරීමට මුරපදය ඇà¶à·”à·…à¶à·Š කරන්න.
+password_invalid=à·€à·à¶»à¶¯à·’ මුරපදයක්. කරුණà·à¶šà¶» නà·à·€à¶ උà¶à·Šà·ƒà·„ කරන්න.
+password_ok=හරි
+password_cancel=එපà·
+
+printing_not_supported=අවවà·à¶¯à¶ºà¶ºà·’: මෙම ගවේà·à¶šà¶º මුද්â€à¶»à¶«à¶º සඳහ෠සම්පූර්ණයෙන් සහය නොදක්වයි.
+printing_not_ready=අවවà·à¶¯à¶ºà¶ºà·’: මුද්â€à¶»à¶«à¶º සඳහ෠PDF සම්පූර්ණයෙන් පූර්ණය වී නොමà·à¶.
+web_fonts_disabled=ජà·à¶½ අකුරු අක්â€à¶»à·“යයි: à¶à·’à·…à·à¶½à·’ PDF අකුරු භà·à·€à·’චකළ නොහà·à¶š.
+document_colors_disabled=PDF ලේඛනයට ඔවුන්ගේම වර්ණ භà·à·€à·’à¶à¶ºà¶§ ඉඩ නොලà·à¶¶à·š: 'පිටු වෙචඔවුන්ගේම වර්ණ භà·à·€à·’à¶à¶ºà¶§ ඉඩදෙන්න' ගවේà·à¶šà¶º මචඅක්â€à¶»à·“ය කර ඇà¶.
diff --git a/static/pdf.js/locale/sk/viewer.properties b/static/pdf.js/locale/sk/viewer.properties
new file mode 100644
index 000000000..13da450b8
--- /dev/null
+++ b/static/pdf.js/locale/sk/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Predchádzajúca strana
+previous_label=Predchádzajúca
+next.title=Nasledujúca strana
+next_label=Nasledujúca
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Strana:
+page_of=z {{pageCount}}
+
+zoom_out.title=Vzdialiť
+zoom_out_label=Vzdialiť
+zoom_in.title=PriblÞiť
+zoom_in_label=PriblÞiť
+zoom.title=Lupa
+presentation_mode.title=Prepnúť na režim Prezentácia
+presentation_mode_label=Režim Prezentácia
+open_file.title=Otvoriť súbor
+open_file_label=Otvoriť
+print.title=TlaÄiÅ¥
+print_label=TlaÄiÅ¥
+download.title=Prevziať
+download_label=Prevziať
+bookmark.title=Aktuálne zobrazenie (kopÃrovaÅ¥ alebo otvoriÅ¥ v novom okne)
+bookmark_label=Aktuálne zobrazenie
+
+# Secondary toolbar and context menu
+tools.title=Nástroje
+tools_label=Nástroje
+first_page.title=Prejsť na prvú stranu
+first_page.label=Prejsť na prvú stranu
+first_page_label=Prejsť na prvú stranu
+last_page.title=Prejsť na poslednú stranu
+last_page.label=Prejsť na poslednú stranu
+last_page_label=Prejsť na poslednú stranu
+page_rotate_cw.title=OtoÄiÅ¥ v smere hodinových ruÄiÄiek
+page_rotate_cw.label=OtoÄiÅ¥ v smere hodinových ruÄiÄiek
+page_rotate_cw_label=OtoÄiÅ¥ v smere hodinových ruÄiÄiek
+page_rotate_ccw.title=OtoÄiÅ¥ proti smeru hodinových ruÄiÄiek
+page_rotate_ccw.label=OtoÄiÅ¥ proti smeru hodinových ruÄiÄiek
+page_rotate_ccw_label=OtoÄiÅ¥ proti smeru hodinových ruÄiÄiek
+
+hand_tool_enable.title=Zapnúť nástroj Ruka
+hand_tool_enable_label=Zapnúť nástroj Ruka
+hand_tool_disable.title=Vypnúť nástroj Ruka
+hand_tool_disable_label=Vypnúť nástroj Ruka
+
+# Document properties dialog box
+document_properties.title=Vlastnosti dokumentu…
+document_properties_label=Vlastnosti dokumentu…
+document_properties_file_name=Názov súboru:
+document_properties_file_size=Veľkosť súboru:
+document_properties_kb={{size_kb}} kB ({{size_b}} bajtov)
+document_properties_mb={{size_mb}} MB ({{size_b}} bajtov)
+document_properties_title=Názov:
+document_properties_author=Autor:
+document_properties_subject=Predmet:
+document_properties_keywords=KľúÄové slová:
+document_properties_creation_date=Dátum vytvorenia:
+document_properties_modification_date=Dátum úpravy:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Vytvoril:
+document_properties_producer=Tvorca PDF:
+document_properties_version=Verzia PDF:
+document_properties_page_count=PoÄet strán:
+document_properties_close=Zavrieť
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Prepnúť boÄný panel
+toggle_sidebar_label=Prepnúť boÄný panel
+outline.title=Zobraziť prehľad dokumentu
+outline_label=Prehľad dokumentu
+attachments.title=ZobraziÅ¥ prÃlohy
+attachments_label=PrÃlohy
+thumbs.title=Zobraziť miniatúry
+thumbs_label=Miniatúry
+findbar.title=Hľadať v dokumente
+findbar_label=Hľadať
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Strana {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatúra strany {{page}}
+
+# Find panel button title and messages
+find_label=Hľadať:
+find_previous.title=Vyhľadať predchádzajúci výskyt reťazca
+find_previous_label=Predchádzajúce
+find_next.title=VyhľadaÅ¥ ÄalÅ¡Ã výskyt reÅ¥azca
+find_next_label=Ďalšie
+find_highlight=Zvýrazniť všetky
+find_match_case_label=RozliÅ¡ovaÅ¥ malé/veľké pÃsmená
+find_reached_top=Bol dosiahnutý zaÄiatok stránky, pokraÄuje sa od konca
+find_reached_bottom=Bol dosiahnutý koniec stránky, pokraÄuje sa od zaÄiatku
+find_not_found=Výraz nebol nájdený
+
+# Error panel labels
+error_more_info=Viac informáciÃ
+error_less_info=Menej informáciÃ
+error_close=Zavrieť
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (zostavenie: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Správa: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ZásobnÃk: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Súbor: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Riadok: {{line}}
+rendering_error=Pri vykresľovanà stránky sa vyskytla chyba.
+
+# Predefined zoom values
+page_scale_width=Na Å¡Ãrku strany
+page_scale_fit=Na veľkosť strany
+page_scale_auto=Automatická veľkosť
+page_scale_actual=SkutoÄná veľkosÅ¥
+
+# Loading indicator messages
+loading_error_indicator=Chyba
+loading_error=PoÄas naÄÃtavania dokumentu PDF sa vyskytla chyba.
+invalid_file_error=Neplatný alebo poškodený súbor PDF.
+missing_file_error=Chýbajúci súbor PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Anotácia typu {{type}}]
+password_label=Ak chcete otvoriť tento súbor PDF, zadajte jeho heslo.
+password_invalid=Heslo nie je platné. Skúste to znova.
+password_ok=OK
+password_cancel=Zrušiť
+
+printing_not_supported=Upozornenie: tlaÄ nie je v tomto prehliadaÄi plne podporovaná.
+printing_not_ready=Upozornenie: súbor PDF nie je plne naÄÃtaný pre tlaÄ.
+web_fonts_disabled=Webové pÃsma sú vypnuté: nie je možné použiÅ¥ pÃsma vložené do súboru PDF.
+document_colors_disabled=Dokumenty PDF nemajú povolené použÃvaÅ¥ vlastné farby, pretože voľba "PovoliÅ¥ stránkam použÃvaÅ¥ vlastné farby" je v nastaveniach prehliadaÄa vypnutá.
diff --git a/static/pdf.js/locale/sl/viewer.properties b/static/pdf.js/locale/sl/viewer.properties
new file mode 100644
index 000000000..5e091078e
--- /dev/null
+++ b/static/pdf.js/locale/sl/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Prejšnja stran
+previous_label=Nazaj
+next.title=Naslednja stran
+next_label=Naprej
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Stran:
+page_of=od {{pageCount}}
+
+zoom_out.title=Pomanjšaj
+zoom_out_label=Pomanjšaj
+zoom_in.title=PoveÄaj
+zoom_in_label=PoveÄaj
+zoom.title=PoveÄava
+presentation_mode.title=Preklopi v naÄin predstavitve
+presentation_mode_label=NaÄin predstavitve
+open_file.title=Odpri datoteko
+open_file_label=Odpri
+print.title=Natisni
+print_label=Natisni
+download.title=Prenesi
+download_label=Prenesi
+bookmark.title=Trenutni pogled (kopiraj ali odpri v novem oknu)
+bookmark_label=Trenutni pogled
+
+# Secondary toolbar and context menu
+tools.title=Orodja
+tools_label=Orodja
+first_page.title=Pojdi na prvo stran
+first_page.label=Pojdi na prvo stran
+first_page_label=Pojdi na prvo stran
+last_page.title=Pojdi na zadnjo stran
+last_page.label=Pojdi na zadnjo stran
+last_page_label=Pojdi na zadnjo stran
+page_rotate_cw.title=Zavrti v smeri urninega kazalca
+page_rotate_cw.label=Zavrti v smeri urninega kazalca
+page_rotate_cw_label=Zavrti v smeri urninega kazalca
+page_rotate_ccw.title=Zavrti v nasprotni smeri urninega kazalca
+page_rotate_ccw.label=Zavrti v nasprotni smeri urninega kazalca
+page_rotate_ccw_label=Zavrti v nasprotni smeri urninega kazalca
+
+hand_tool_enable.title=OmogoÄi roko
+hand_tool_enable_label=OmogoÄi roko
+hand_tool_disable.title=OnemogoÄi roko
+hand_tool_disable_label=OnemogoÄi roko
+
+# Document properties dialog box
+document_properties.title=Lastnosti dokumenta …
+document_properties_label=Lastnosti dokumenta …
+document_properties_file_name=Ime datoteke:
+document_properties_file_size=Velikost datoteke:
+document_properties_kb={{size_kb}} KB ({{size_b}} bajtov)
+document_properties_mb={{size_mb}} MB ({{size_b}} bajtov)
+document_properties_title=Ime:
+document_properties_author=Avtor:
+document_properties_subject=Tema:
+document_properties_keywords=KljuÄne besede:
+document_properties_creation_date=Datum nastanka:
+document_properties_modification_date=Datum spremembe:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Ustvaril:
+document_properties_producer=Izdelovalec PDF:
+document_properties_version=RazliÄica PDF:
+document_properties_page_count=Å tevilo strani:
+document_properties_close=Zapri
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Preklopi stransko vrstico
+toggle_sidebar_label=Preklopi stransko vrstico
+outline.title=Prikaži oris dokumenta
+outline_label=Oris dokumenta
+attachments.title=Prikaži priponke
+attachments_label=Priponke
+thumbs.title=Prikaži sliÄice
+thumbs_label=SliÄice
+findbar.title=Iskanje po dokumentu
+findbar_label=Iskanje
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Stran {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=SliÄica strani {{page}}
+
+# Find panel button title and messages
+find_label=Najdi:
+find_previous.title=Najdi prejšnjo ponovitev iskanega
+find_previous_label=Najdi nazaj
+find_next.title=Najdi naslednjo ponovitev iskanega
+find_next_label=Najdi naprej
+find_highlight=OznaÄi vse
+find_match_case_label=Razlikuj velike/male Ärke
+find_reached_top=Dosežen zaÄetek dokumenta iz smeri konca
+find_reached_bottom=Doseženo konec dokumenta iz smeri zaÄetka
+find_not_found=Iskanega ni mogoÄe najti
+
+# Error panel labels
+error_more_info=VeÄ informacij
+error_less_info=Manj informacij
+error_close=Zapri
+# LOCALIZATION NOTE (error_build): "{{build}}" will be replaced by the PDF.JS
+# build ID.
+error_version_info=PDF.js r{{version}} (graditev: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=SporoÄilo: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Sklad: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Datoteka: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Vrstica: {{line}}
+rendering_error=Med pripravljanjem strani je prišlo do napake!
+
+# Predefined zoom values
+page_scale_width=Å irina strani
+page_scale_fit=Prilagodi stran
+page_scale_auto=Samodejno
+page_scale_actual=Dejanska velikost
+
+# Loading indicator messages
+loading_error_indicator=Napaka
+loading_error=Med nalaganjem datoteke PDF je prišlo do napake.
+invalid_file_error=Neveljavna ali pokvarjena datoteka PDF.
+missing_file_error=Ni datoteke PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Opomba vrste {{type}}]
+password_label=Vnesite geslo za odpiranje te datoteke PDF.
+password_invalid=Neveljavno geslo. Poskusite znova.
+password_ok=V redu
+password_cancel=PrekliÄi
+
+printing_not_supported=Opozorilo: ta brskalnik ne podpira vseh možnosti tiskanja.
+printing_not_ready=Opozorilo: PDF ni v celoti naložen za tiskanje.
+web_fonts_disabled=Spletne pisave so onemogoÄene: vgradnih pisav za PDF ni mogoÄe uporabiti.
+document_colors_disabled=Dokumenti PDF ne smejo uporabljati svojih lastnih barv: možnost 'Dovoli stranem uporabo lastnih barv' je v brskalniku onemogoÄena.
diff --git a/static/pdf.js/locale/son/viewer.properties b/static/pdf.js/locale/son/viewer.properties
new file mode 100644
index 000000000..54a6d2675
--- /dev/null
+++ b/static/pdf.js/locale/son/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Moo bisante
+previous_label=Bisante
+next.title=Jinehere moo
+next_label=Jine
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=&Moo:
+page_of={{pageCount}} ga
+
+zoom_out.title=Nakasandi
+zoom_out_label=Nakasandi
+zoom_in.title=Bebbeerandi
+zoom_in_label=Bebbeerandi
+zoom.title=Bebbeerandi
+presentation_mode.title=Bere cebeyan alhaali
+presentation_mode_label=Cebeyan alhaali
+open_file.title=Tuku feeri
+open_file_label=Feeri
+print.title=Kar
+print_label=Kar
+download.title=Zumandi
+download_label=Zumandi
+bookmark.title=Sohõ gunarro (bere wala feeri zanfun taaga ra)
+bookmark_label=Sohõ gunaroo
+
+# Secondary toolbar and context menu
+tools.title=Goyjinawey
+tools_label=Goyjinawey
+first_page.title=Koy moo jinaa ga
+first_page.label=Koy moo jinaa ga
+first_page_label=Koy moo jinaa ga
+last_page.title=Koy moo koraa ga
+last_page.label=Koy moo koraa ga
+last_page_label=Koy moo koraa ga
+page_rotate_cw.title=Kuubi kanbe guma here
+page_rotate_cw.label=Kuubi kanbe guma here
+page_rotate_cw_label=Kuubi kanbe guma here
+page_rotate_ccw.title=Kuubi kanbe wowa here
+page_rotate_ccw.label=Kuubi kanbe wowa here
+page_rotate_ccw_label=Kuubi kanbe wowa here
+
+hand_tool_enable.title=Kanbe goyjinay tunandi
+hand_tool_enable_label=Kanbe goyjinay tunandi
+hand_tool_disable.title=Kanbe joyjinay kaa
+hand_tool_disable_label=Kanbe goyjinay kaa
+
+# Document properties dialog box
+document_properties.title=Takadda mayrawey…
+document_properties_label=Takadda mayrawey…
+document_properties_file_name=Tuku maa:
+document_properties_file_size=Tuku adadu:
+document_properties_kb=KB {{size_kb}} (cebsu-ize {{size_b}})
+document_properties_mb=MB {{size_kb}} (cebsu-ize {{size_b}})
+document_properties_title=Tiiramaa:
+document_properties_author=Hantumkaw:
+document_properties_subject=Dalil:
+document_properties_keywords=Kufalkalimawey:
+document_properties_creation_date=Teeyan han:
+document_properties_modification_date=Barmayan han:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Teekaw:
+document_properties_producer=PDF berandikaw:
+document_properties_version=PDF dumi:
+document_properties_page_count=Moo hinna:
+document_properties_close=Daabu
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Kanjari ceraw zuu
+toggle_sidebar_label=Kanjari ceraw zuu
+outline.title=Takadda filla-boŋ cebe
+outline_label=Takadda filla-boŋ
+attachments.title=Hangarey cebe
+attachments_label=Hangarey
+thumbs.title=Kabeboy biyey cebe
+thumbs_label=Kabeboy biyey
+findbar.title=Ceeci takaddaa ra
+findbar_label=Ceeci
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title={{page}} moo
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Kabeboy bii {{page}} moo Å¡e
+
+# Find panel button title and messages
+find_label=Ceeci:
+find_previous.title=Kalimaɲaŋoo bangayri bisantaa ceeci
+find_previous_label=Bisante
+find_next.title=Kalimaɲaŋoo hiino bangayroo ceeci
+find_next_label=Jine
+find_highlight=Ikul Å¡ilbay
+find_match_case_label=Harfu-beeriyan hawgay
+find_reached_top=A too moŋoo boŋoo, koy jine ka šinitin nda cewoo
+find_reached_bottom=A too moɲoo cewoo, koy jine šintioo ga
+find_not_found=Kalimaɲaa mana duwandi
+
+# Error panel labels
+error_more_info=Alhabar tontoni
+error_less_info=Alhabar tontoni
+error_close=Daabu
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Alhabar: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Dekeri: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Tuku: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Žeeri: {{line}}
+rendering_error=Firka bangay kaŋ moɲoo goo ma willandi.
+
+# Predefined zoom values
+page_scale_width=Mooo hayyan
+page_scale_fit=Moo sawayan
+page_scale_auto=Boŋše azzaati barmayyan
+page_scale_actual=Adadu cimi
+
+# Loading indicator messages
+loading_error_indicator=Firka
+loading_error=Firka bangay kaŋ PDF goo ma zumandi.
+invalid_file_error=PDF tuku laala wala laybante.
+missing_file_error=PDF tuku kumante.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt={{type}} maasa-caw]
+password_label=Å ennikufal dam ka PDF tukoo woo feeri.
+password_invalid=Å ennikufal laalo. Ceeci koyne taare.
+password_ok=Ayyo
+password_cancel=Naŋ
+
+printing_not_supported=Yaamar: Karyan Å¡i tee ka timme nda ceecikaa woo.
+printing_not_ready=Yaamar: PDF Å¡i zunbu ka timme karyan Å¡e.
+web_fonts_disabled=Interneti Å¡igirawey kay: Å¡i hin ka goy nda PDF Å¡igira hurantey.
+document_colors_disabled=PDF takaddawey ši duu fondo ka ngey boŋ noonawey zaa: 'Naŋ moɲey ma ngey boŋ noonawey suuba' ši dira ceecikaa ga.
diff --git a/static/pdf.js/locale/sq/viewer.properties b/static/pdf.js/locale/sq/viewer.properties
new file mode 100644
index 000000000..79cd381d4
--- /dev/null
+++ b/static/pdf.js/locale/sq/viewer.properties
@@ -0,0 +1,161 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Faqja e Mëparshme
+previous_label=E mëparshmja
+next.title=Faqja Pasuese
+next_label=Pasuesja
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Faqja:
+page_of=nga {{pageCount}}
+
+zoom_out.title=Zoom Out
+zoom_out_label=Zoom Out
+zoom_in.title=Zoom In
+zoom_in_label=Zoom In
+zoom.title=Zoom
+print.title=Shtype
+print_label=Shtypeni
+presentation_mode.title=Kalo te Mënyra Paraqitje
+presentation_mode_label=Mënyra Paraqitje
+open_file.title=Hapni Kartelë
+open_file_label=Hapeni
+download.title=Shkarkim
+download_label=Shkarkojeni
+bookmark.title=Pamja e tanishme (kopjojeni ose hapeni në dritare të re)
+bookmark_label=Pamja e Tanishme
+
+# Secondary toolbar and context menu
+tools.title=Mjete
+tools_label=Mjete
+first_page.title=Shkoni te Faqja e Parë
+first_page.label=Shkoni te Faqja e Parë
+first_page_label=Shkoni te Faqja e Parë
+last_page.title=Shkoni te Faqja e Fundit
+last_page.label=Shkoni te Faqja e Fundit
+last_page_label=Shkoni te Faqja e Fundit
+page_rotate_cw.title=Rrotullojeni Në Kahun Orar
+page_rotate_cw.label=Rrotullojeni Në Kahun Orar
+page_rotate_cw_label=Rrotullojeni Në Kahun Orar
+page_rotate_ccw.title=Rrotullojeni Në Kahun Kundërorar
+page_rotate_ccw.label=Rrotullojeni Në Kahun Kundërorar
+page_rotate_ccw_label=Rrotullojeni Në Kahun Kundërorar
+
+hand_tool_enable.title=Aktivizoni mjet dore
+hand_tool_enable_label=Aktivizoni mjet dore
+hand_tool_disable.title=Çaktivizoni mjet dore
+hand_tool_disable_label=Çaktivizoni mjet dore
+
+# Document properties dialog box
+document_properties.title=Veti Dokumenti…
+document_properties_label=Veti Dokumenti…
+document_properties_file_name=Emër kartele:
+document_properties_file_size=Madhësi kartele:
+document_properties_kb={{size_kb}} KB ({{size_b}} bajte)
+document_properties_mb={{size_mb}} MB ({{size_b}} bajte)
+document_properties_title=Titull:
+document_properties_author=Autor:
+document_properties_subject=Subjekt:
+document_properties_keywords=Fjalëkyçe:
+document_properties_creation_date=Datë Krijimi:
+document_properties_modification_date=Datë Ndryshimi:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Krijues:
+document_properties_producer=Prodhues PDF-je:
+document_properties_version=Version PDF-je:
+document_properties_page_count=Numër Faqesh:
+document_properties_close=Mbylle
+
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Shfaqni/Fshihni Anështyllën
+toggle_sidebar_label=Shfaqni/Fshihni Anështyllën
+outline.title=Shfaq Përvijim Dokumenti
+outline_label=Shfaq Përvijim Dokumenti
+attachments.title=Shfaq Bashkëngjitje
+attachments_label=Bashkëngjitje
+thumbs.title=Shfaq Miniatura
+thumbs_label=Miniatura
+findbar.title=Gjej në Dokument
+findbar_label=Gjej
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Faqja {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniaturë e Faqes {{page}}
+
+# Context menu
+first_page.label=Kalo te Faqja e Parë
+last_page.label=Kalo te Faqja e Fundit
+page_rotate_cw.label=Rrotulloje Në Kahun Orar
+page_rotate_ccw.label=Rrotulloje Në Kahun Antiorar
+
+# Find panel button title and messages
+find_label=Gjej:
+find_previous.title=Gjeni hasjen e mëparshme të togfjalëshit
+find_previous_label=E mëparshmja
+find_next.title=Gjeni hasjen pasuese të togfjalëshit
+find_next_label=Pasuesja
+find_highlight=Theksoji të gjitha
+find_match_case_label=Siç është shkruar
+find_reached_top=U mbërrit në krye të dokumentit, vazhduar prej fundit
+find_reached_bottom=U mbërrit në fund të dokumentit, vazhduar prej kreut
+find_not_found=Nuk u gjet togfjalëshi
+
+# Error panel labels
+error_more_info=Më Tepër të Dhëna
+error_less_info=Më Pak të Dhëna
+error_close=Mbylle
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mesazh: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Kartelë: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rresht: {{line}}
+rendering_error=Ndodhi një gabim gjatë riprodhimit të faqes.
+
+# Predefined zoom values
+page_scale_width=Gjerësi Faqeje
+page_scale_fit=Sa Nxë Faqja
+page_scale_auto=Zoom i Vetvetishëm
+page_scale_actual=Madhësia Faktike
+
+# Loading indicator messages
+# LOCALIZATION NOTE (error_line): "{{[percent}}" will be replaced with a percentage
+loading_error_indicator=Gabim
+loading_error=Ndodhi një gabim gjatë ngarkimit të PDF-së.
+invalid_file_error=Kartelë PDF e pavlefshme ose e dëmtuar.
+missing_file_error=Kartelë PDF që mungon.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Nënvizim {{type}}]
+password_label=Jepni fjalëkalimin që të hapet kjo kartelë PDF.
+password_invalid=Fjalëkalim i pavlefshëm. Ju lutemi, riprovoni.
+password_ok=OK
+password_cancel=Anuloje
+
+printing_not_supported=Kujdes: Shtypja nuk mbulohet plotësisht nga ky shfletues.
+printing_not_ready=Kujdes: PDF-ja nuk është ngarkuar plotësisht që ta shtypni.
+web_fonts_disabled=Shkronjat Web janë të çaktivizuara: i pazoti të përdorë shkronja të trupëzuara në PDF.
+document_colors_disabled=Dokumenteve PDF nuk u është lejuar të përdorin ngjyrat e veta: 'Lejoji faqet t'i zgjedhin vetë ngjyrat', te shfletuesi, është e çaktivizuar.
diff --git a/static/pdf.js/locale/sr/viewer.properties b/static/pdf.js/locale/sr/viewer.properties
index 9fe3666e2..f91a33be0 100644
--- a/static/pdf.js/locale/sr/viewer.properties
+++ b/static/pdf.js/locale/sr/viewer.properties
@@ -12,44 +12,152 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-bookmark.title=Тренутни приказ (Умножити или отворити у новом прозору)
-previous.title=Предходна Ñтрана
-next.title=Следећа Ñтрана
-print.title=Штампај
-download.title=Преузми
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Претходна Ñтраница
+previous_label=Претходна
+next.title=Следећа Ñтраница
+next_label=Следећа
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Страница:
+page_of=од {{pageCount}}
+
zoom_out.title=Умањи
-zoom_in.title=Увећај
+zoom_out_label=Умањи
+zoom_in.title=Увеличај
+zoom_in_label=Увеличај
+zoom.title=Зумирање
+presentation_mode.title=Промени на приказ у режиму презентације
+presentation_mode_label=Режим презентације
+open_file.title=Отвори датотеку
+open_file_label=Отвори
+print.title=Штампај
+print_label=Штампај
+download.title=Преузми
+download_label=Преузми
+bookmark.title=Тренутни приказ (копирај или отвори нови прозор)
+bookmark_label=Тренутни приказ
+
+# Secondary toolbar and context menu
+tools.title=Ðлатке
+tools_label=Ðлатке
+first_page.title=Иди на прву Ñтраницу
+first_page.label=Иди на прву Ñтраницу
+first_page_label=Иди на прву Ñтраницу
+last_page.title=Иди на поÑледњу Ñтраницу
+last_page.label=Иди на поÑледњу Ñтраницу
+last_page_label=Иди на поÑледњу Ñтраницу
+page_rotate_cw.title=Ротирај у Ñмеру казаљке на Ñату
+page_rotate_cw.label=Ротирај у Ñмеру казаљке на Ñату
+page_rotate_cw_label=Ротирај у Ñмеру казаљке на Ñату
+page_rotate_ccw.title=Ротирај у Ñмеру Ñупротном од казаљке на Ñату
+page_rotate_ccw.label=Ротирај у Ñмеру Ñупротном од казаљке на Ñату
+page_rotate_ccw_label=Ротирај у Ñмеру Ñупротном од казаљке на Ñату
+
+hand_tool_enable.title=Омогући алатку за померање
+hand_tool_enable_label=Омогући алатку за померање
+hand_tool_disable.title=Онемогући алатку за померање
+hand_tool_disable_label=Онемогући алатку за померање
+
+# Document properties dialog box
+document_properties.title=Параметри документа…
+document_properties_label=Параметри документа…
+document_properties_file_name=Име датотеке:
+document_properties_file_size=Величина датотеке:
+document_properties_kb={{size_kb}} KB ({{size_b}} B)
+document_properties_mb={{size_mb}} MB ({{size_b}} B)
+document_properties_title=ÐаÑлов:
+document_properties_author=Ðутор:
+document_properties_subject=Тема:
+document_properties_keywords=Кључне речи:
+document_properties_creation_date=Датум креирања:
+document_properties_modification_date=Датум модификације:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Стваралац:
+document_properties_producer=PDF произвођач:
+document_properties_version=PDF верзија:
+document_properties_page_count=Број Ñтраница:
+document_properties_close=Затвори
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Прикажи додатну палету
+toggle_sidebar_label=Прикажи додатну палету
+outline.title=Прикажи контуру документа
+outline_label=Контура документа
+attachments.title=Прикажи прилоге
+attachments_label=Прилози
+thumbs.title=Прикажи Ñличице
+thumbs_label=Сличице
+findbar.title=Пронађи у документу
+findbar_label=Пронађи
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Страница {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Сличица од Ñтранице {{page}}
+
+# Find panel button title and messages
+find_label=Пронађи:
+find_previous.title=Пронађи претходну појаву фразе
+find_previous_label=Претходна
+find_next.title=Пронађи Ñледећу појаву фразе
+find_next_label=Следећа
+find_highlight=ИÑтакнути Ñве
+find_match_case_label=Подударања
+find_reached_top=ДоÑтигнут врх документа, наÑтавио Ñа дна
+find_reached_bottom=ДоÑтигнуто дно документа, наÑтавио Ñа врха
+find_not_found=Фраза није пронађена
+
+# Error panel labels
error_more_info=Више информација
error_less_info=Мање информација
error_close=Затвори
-error_build=PDF.JS Build: {{build}}
-error_message=Message: {{message}}
-error_stack=Stack: {{stack}}
-error_file=File: {{file}}
-error_line=Line: {{line}}
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Порука: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Стек: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Датотека: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Линија: {{line}}
+rendering_error=Дошло је до грешке приликом рендеровања ове Ñтранице.
+
+# Predefined zoom values
page_scale_width=Ширина Ñтранице
-page_scale_fit=Уклопи
-page_scale_auto=Увећај аутоматÑки
+page_scale_fit=Уклапање Ñтранице
+page_scale_auto=ÐутоматÑко увеличавање
page_scale_actual=Стварна величина
-toggle_slider.title=Клизач
-thumbs.title=Прикажи у Ñличицама
-outline.title=Прикажи у линијама
-loading=Учитавање... {{percent}}%
+
+# Loading indicator messages
loading_error_indicator=Грешка
-loading_error=Дошло је до грешке током учитавања ПДФ-а.
-rendering_error=Дошло је до грешке приликом приказивања Ñтране.
-page_label=Страна:
-page_of=од {{pageCount}}
-open_file.title=Отвори датотеку
-text_annotation_type.alt=[{{type}} Annotation]
-toggle_slider_label=Клизач
-thumbs_label=Сличице
-outline_label=Документи у линијама
-bookmark_label=Тренутни приказ
-previous_label=Предходна
-next_label=Следећа
-print_label=Штампај
-download_label=Преузми
-zoom_out_label=Умањи
-zoom_in_label=Увећај
-zoom.title=Скала
+loading_error=Дошло је до грешке приликом учитавање PDF.
+invalid_file_error=PDF датотека је оштећена или је неиÑправна.
+missing_file_error=PDF датотека није пронађена.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} коментар]
+password_label=_УнеÑите лозинку да биÑте отворили овај PDF докуменат.
+password_invalid=ÐеиÑправна лозинка. Покушајте поново.
+password_ok=У реду
+password_cancel=Откажи
+
+printing_not_supported=Упозорење: Штампање није у потпуноÑти подржано у овом прегледачу.
+printing_not_ready=Упозорење: PDF није у потпуноÑти учитан за штампу.
+web_fonts_disabled=Веб фонтови Ñу онемогућени: не могу кориÑтити уграђене PDF фонтове.
+document_colors_disabled=PDF документи не могу да кориÑте ÑопÑтвене боје: “Дозволи Ñтраницама да одаберу Ñвоје боје†је деактивирано у прегледачу.
diff --git a/static/pdf.js/locale/sv-SE/viewer.properties b/static/pdf.js/locale/sv-SE/viewer.properties
new file mode 100644
index 000000000..a88edbd4f
--- /dev/null
+++ b/static/pdf.js/locale/sv-SE/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Föregående sida
+previous_label=Föregående
+next.title=Nästa sida
+next_label=Nästa
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Sida:
+page_of=av {{pageCount}}
+
+zoom_out.title=Zooma ut
+zoom_out_label=Zooma ut
+zoom_in.title=Zooma in
+zoom_in_label=Zooma in
+zoom.title=Zoom
+presentation_mode.title=Byt till presentationsläge
+presentation_mode_label=Presentationsläge
+open_file.title=Öppna fil
+open_file_label=Öppna
+print.title=Skriv ut
+print_label=Skriv ut
+download.title=Hämta
+download_label=Hämta
+bookmark.title=Aktuell vy (kopiera eller öppna i nytt fönster)
+bookmark_label=Aktuell vy
+
+# Secondary toolbar and context menu
+tools.title=Verktyg
+tools_label=Verktyg
+first_page.title=Gå till första sidan
+first_page.label=Gå till första sidan
+first_page_label=Gå till första sidan
+last_page.title=GÃ¥ till sista sidan
+last_page.label=GÃ¥ till sista sidan
+last_page_label=GÃ¥ till sista sidan
+page_rotate_cw.title=Rotera medurs
+page_rotate_cw.label=Rotera medurs
+page_rotate_cw_label=Rotera medurs
+page_rotate_ccw.title=Rotera moturs
+page_rotate_ccw.label=Rotera moturs
+page_rotate_ccw_label=Rotera moturs
+
+hand_tool_enable.title=Aktivera handverktyg
+hand_tool_enable_label=Aktivera handverktyg
+hand_tool_disable.title=Inaktivera handverktyg
+hand_tool_disable_label=Inaktivera handverktyg
+
+# Document properties dialog box
+document_properties.title=Dokumentegenskaper…
+document_properties_label=Dokumentegenskaper…
+document_properties_file_name=Filnamn:
+document_properties_file_size=Filstorlek:
+document_properties_kb={{size_kb}} kB ({{size_b}} byte)
+document_properties_mb={{size_mb}} MB ({{size_b}} byte)
+document_properties_title=Titel:
+document_properties_author=Författare:
+document_properties_subject=Ämne:
+document_properties_keywords=Nyckelord:
+document_properties_creation_date=Skapades:
+document_properties_modification_date=Ändrades:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Skapare:
+document_properties_producer=PDF-producent:
+document_properties_version=PDF-version:
+document_properties_page_count=Sidantal:
+document_properties_close=Stäng
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Visa/dölj sidofält
+toggle_sidebar_label=Visa/dölj sidofält
+outline.title=Visa dokumentöversikt
+outline_label=Dokumentöversikt
+attachments.title=Visa Bilagor
+attachments_label=Bilagor
+thumbs.title=Visa miniatyrer
+thumbs_label=Miniatyrer
+findbar.title=Sök i dokument
+findbar_label=Sök
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Sida {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Miniatyr av sida {{page}}
+
+# Find panel button title and messages
+find_label=Sök:
+find_previous.title=Hitta föregående förekomst av frasen
+find_previous_label=Föregående
+find_next.title=Hitta nästa förekomst av frasen
+find_next_label=Nästa
+find_highlight=Markera alla
+find_match_case_label=Matcha versal/gemen
+find_reached_top=Nådde början av dokumentet, började från slutet
+find_reached_bottom=Nådde slutet på dokumentet, började från början
+find_not_found=Frasen hittades inte
+
+# Error panel labels
+error_more_info=Mer information
+error_less_info=Mindre information
+error_close=Stäng
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Meddelande: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Stack: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Fil: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rad: {{line}}
+rendering_error=Ett fel uppstod vid visning av sidan.
+
+# Predefined zoom values
+page_scale_width=Sidbredd
+page_scale_fit=Anpassa sida
+page_scale_auto=Automatisk zoom
+page_scale_actual=Verklig storlek
+
+# Loading indicator messages
+loading_error_indicator=Fel
+loading_error=Ett fel uppstod vid laddning av PDF-filen.
+invalid_file_error=Ogiltig eller korrupt PDF-fil.
+missing_file_error=Saknad PDF-fil.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}}-annotering]
+password_label=Skriv in lösenordet för att öppna PDF-filen.
+password_invalid=Ogiltigt lösenord. Försök igen.
+password_ok=OK
+password_cancel=Avbryt
+
+printing_not_supported=Varning: Utskrifter stöds inte helt av den här webbläsaren.
+printing_not_ready=Varning: PDF:en är inte klar för utskrift.
+web_fonts_disabled=Webbtypsnitt är inaktiverade: kan inte använda inbäddade PDF-typsnitt.
+document_colors_disabled=PDF-dokument tillåts inte använda egna färger: 'Låt sidor använda egna färger' är inaktiverat i webbläsaren.
diff --git a/static/pdf.js/locale/sw/viewer.properties b/static/pdf.js/locale/sw/viewer.properties
new file mode 100644
index 000000000..8f9f7dd84
--- /dev/null
+++ b/static/pdf.js/locale/sw/viewer.properties
@@ -0,0 +1,121 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Ukurasa Uliotangulia
+previous_label=Iliyotangulia
+next.title=Ukurasa Ufuatao
+next_label=Ifuatayo
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Ukurasa:
+page_of=ya {{Hesabu ya ukurasa}}
+
+zoom_out.title=Kuza Nje
+zoom_out_label=Kuza Nje
+zoom_in.title=Kuza Ndani
+zoom_in_label=Kuza Ndani
+zoom.title=Kuza
+presentation_mode.title=Badili kwa Hali ya Uwasilishaji
+presentation_mode_label=Hali ya Uwasilishaji
+open_file.title=Fungua Faili
+open_file_label=Fungua
+print.title=Chapisha
+print_label=Chapisha
+download.title=Pakua
+download_label=Pakua
+bookmark.title=Mwonekano wa sasa (nakili au ufungue katika dirisha mpya)
+bookmark_label=Mwonekano wa Sasa
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_title=Kichwa:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Kibiano cha Upau wa Kando
+toggle_sidebar_label=Kibiano cha Upau wa Kando
+outline.title=Onyesha Ufupisho wa Waraka
+outline_label=Ufupisho wa Waraka
+thumbs.title=Onyesha Kijipicha
+thumbs_label=Vijipicha
+findbar.title=Pata katika Waraka
+findbar_label=Tafuta
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Ukurasa {{ukurasa}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Kijipicha cha ukurasa {{ukurasa}}
+
+# Find panel button title and messages
+find_label=Tafuta:
+find_previous.title=Tafuta tukio kabla ya msemo huu
+find_previous_label=Iliyotangulia
+find_next.title=Tafuta tukio linalofuata la msemo
+find_next_label=Ifuatayo
+find_highlight=Angazia yote
+find_match_case_label=Linganisha herufi
+find_reached_top=Imefika juu ya waraka, imeendelea kutoka chini
+find_reached_bottom=Imefika mwisho wa waraka, imeendelea kutoka juu
+find_not_found=Msemo hukupatikana
+
+# Error panel labels
+error_more_info=Maelezo Zaidi
+error_less_info=Maelezo Kidogo
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (jenga: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Ujumbe: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Panganya: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Faili: {{faili}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Laini: {{laini}}
+rendering_error=Hitilafu lilitokea wajati wa kutoa ukurasa
+
+# Predefined zoom values
+page_scale_width=Upana wa Ukurasa
+page_scale_fit=Usawa wa Ukurasa
+page_scale_auto=Ukuzaji wa Kiotomatiki
+page_scale_actual=Ukubwa Halisi
+
+# Loading indicator messages
+loading_error_indicator=Hitilafu
+loading_error=Hitilafu lilitokea wakati wa kupakia PDF.
+invalid_file_error=Faili ya PDF isiyohalali au potofu.
+missing_file_error=Faili ya PDF isiyopo.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Ufafanuzi]
+password_ok=SAWA
+password_cancel=Ghairi
+
+printing_not_supported=Onyo: Uchapishaji hauauniwi kabisa kwa kivinjari hiki.
+web_fonts_disabled=Fonti za tovuti zimelemazwa: haziwezi kutumia fonti za PDF zilizopachikwa.
diff --git a/static/pdf.js/locale/ta-LK/viewer.properties b/static/pdf.js/locale/ta-LK/viewer.properties
new file mode 100644
index 000000000..77c9f4f28
--- /dev/null
+++ b/static/pdf.js/locale/ta-LK/viewer.properties
@@ -0,0 +1,64 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+
+zoom.title=அளவà¯
+open_file.title=கோபà¯à®ªà®¿à®©à¯ˆà®¤à¯ திறகà¯à®•
+open_file_label=திறகà¯à®•
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+
+# Find panel button title and messages
+find_previous.title=இநà¯à®¤ சொறà¯à®±à¯Šà®Ÿà®°à®¿à®©à¯ à®®à¯à®©à¯à®©à¯ˆà®¯ நிகழà¯à®µà¯ˆ தேடà¯
+find_next.title=இநà¯à®¤ சொறà¯à®±à¯Šà®Ÿà®°à®¿à®©à¯ அடà¯à®¤à¯à®¤ நிகழà¯à®µà¯ˆà®¤à¯ தேடà¯
+
+# Error panel labels
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+
+# Predefined zoom values
+
+# Loading indicator messages
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+password_ok=ஆமà¯
+
diff --git a/static/pdf.js/locale/ta/viewer.properties b/static/pdf.js/locale/ta/viewer.properties
new file mode 100644
index 000000000..8643a688d
--- /dev/null
+++ b/static/pdf.js/locale/ta/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=à®®à¯à®¨à¯à®¤à¯ˆà®¯ பகà¯à®•à®®à¯
+previous_label=à®®à¯à®¨à¯à®¤à¯ˆà®¯à®¤à¯
+next.title=அடà¯à®¤à¯à®¤ பகà¯à®•à®®à¯
+next_label=அடà¯à®¤à¯à®¤à¯
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=பகà¯à®•à®®à¯:
+page_of=இல௠{{pageCount}}
+
+zoom_out.title=சிறிதாகà¯à®•à¯
+zoom_out_label=சிறிதாகà¯à®•à¯
+zoom_in.title=பெரிதாகà¯à®•à¯
+zoom_in_label=பெரிதாகà¯à®•à¯
+zoom.title=பெரிதாகà¯à®•à¯
+presentation_mode.title=விளகà¯à®•à®•à®¾à®Ÿà¯à®šà®¿ பயனà¯à®®à¯à®±à¯ˆà®•à¯à®•à¯ மாறà¯
+presentation_mode_label=விளகà¯à®•à®•à®¾à®Ÿà¯à®šà®¿ பயனà¯à®®à¯à®±à¯ˆ
+open_file.title=கோபà¯à®ªà®¿à®©à¯ˆ திற
+open_file_label=திற
+print.title=அசà¯à®šà®¿à®Ÿà¯
+print_label=அசà¯à®šà®¿à®Ÿà¯
+download.title=பதிவிறகà¯à®•à¯
+download_label=பதிவிறகà¯à®•à¯
+bookmark.title=தறà¯à®ªà¯‹à®¤à¯ˆà®¯ காடà¯à®šà®¿ (பà¯à®¤à®¿à®¯ சாளரதà¯à®¤à®¿à®±à¯à®•à¯ நகலெட௠அலà¯à®²à®¤à¯ பà¯à®¤à®¿à®¯ சாளரதà¯à®¤à®¿à®²à¯ திற)
+bookmark_label=தறà¯à®ªà¯‹à®¤à¯ˆà®¯ காடà¯à®šà®¿
+
+# Secondary toolbar and context menu
+tools.title=கரà¯à®µà®¿à®•à®³à¯
+tools_label=கரà¯à®µà®¿à®•à®³à¯
+first_page.title=à®®à¯à®¤à®²à¯ பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ செலà¯à®²à®µà¯à®®à¯
+first_page.label=à®®à¯à®¤à®²à¯ பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ செலà¯à®²à®µà¯à®®à¯
+first_page_label=à®®à¯à®¤à®²à¯ பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ செலà¯à®²à®µà¯à®®à¯
+last_page.title=கடைசி பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ செலà¯à®²à®µà¯à®®à¯
+last_page.label=கடைசி பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ செலà¯à®²à®µà¯à®®à¯
+last_page_label=கடைசி பகà¯à®•à®¤à¯à®¤à®¿à®±à¯à®•à¯ செலà¯à®²à®µà¯à®®à¯
+page_rotate_cw.title=வலஞà¯à®šà¯à®´à®¿à®¯à®¾à®• சà¯à®´à®±à¯à®±à¯
+page_rotate_cw.label=வலஞà¯à®šà¯à®´à®¿à®¯à®¾à®• சà¯à®´à®±à¯à®±à¯
+page_rotate_cw_label=வலஞà¯à®šà¯à®´à®¿à®¯à®¾à®• சà¯à®´à®±à¯à®±à¯
+page_rotate_ccw.title=இடஞà¯à®šà¯à®´à®¿à®¯à®¾à®• சà¯à®´à®±à¯à®±à¯
+page_rotate_ccw.label=இடஞà¯à®šà¯à®´à®¿à®¯à®¾à®• சà¯à®´à®±à¯à®±à¯
+page_rotate_ccw_label=இடஞà¯à®šà¯à®´à®¿à®¯à®¾à®• சà¯à®´à®±à¯à®±à¯
+
+hand_tool_enable.title=கை கரà¯à®µà®¿à®¯à¯ˆ செயலாகà¯à®•à¯
+hand_tool_enable_label=கை கரà¯à®µà®¿à®¯à¯ˆ செயலாகà¯à®•à¯
+hand_tool_disable.title=கை கரà¯à®µà®¿à®¯à¯ˆ à®®à¯à®Ÿà®•à¯à®•à¯
+hand_tool_disable_label=கை கரà¯à®µà®¿à®¯à¯ˆ à®®à¯à®Ÿà®•à¯à®•à¯
+
+# Document properties dialog box
+document_properties.title=ஆவண பணà¯à®ªà¯à®•à®³à¯...
+document_properties_label=ஆவண பணà¯à®ªà¯à®•à®³à¯...
+document_properties_file_name=கோபà¯à®ªà¯ பெயரà¯:
+document_properties_file_size=கோபà¯à®ªà®¿à®©à¯ அளவà¯:
+document_properties_kb={{size_kb}} கிபை ({{size_b}} பைடà¯à®Ÿà¯à®•à®³à¯)
+document_properties_mb={{size_mb}} மெபை ({{size_b}} பைடà¯à®Ÿà¯à®•à®³à¯)
+document_properties_title=தலைபà¯à®ªà¯:
+document_properties_author=எழà¯à®¤à®¿à®¯à®µà®°à¯
+document_properties_subject=பொரà¯à®³à¯:
+document_properties_keywords=à®®à¯à®•à¯à®•à®¿à®¯ வாரà¯à®¤à¯à®¤à¯ˆà®•à®³à¯:
+document_properties_creation_date=படைதà¯à®¤ தேதி :
+document_properties_modification_date=திரà¯à®¤à¯à®¤à®¿à®¯ தேதி:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=உரà¯à®µà®¾à®•à¯à®•à¯à®ªà®µà®°à¯:
+document_properties_producer=பிடிஎஃப௠தயாரிபà¯à®ªà®¾à®³à®°à¯:
+document_properties_version=PDF பதிபà¯à®ªà¯:
+document_properties_page_count=பகà¯à®• எணà¯à®£à®¿à®•à¯à®•à¯ˆ:
+document_properties_close=மூடà¯à®•
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=பகà¯à®•à®ªà¯ படà¯à®Ÿà®¿à®¯à¯ˆ நிலைமாறà¯à®±à¯
+toggle_sidebar_label=பகà¯à®•à®ªà¯ படà¯à®Ÿà®¿à®¯à¯ˆ நிலைமாறà¯à®±à¯
+outline.title=ஆவண வெளிவரையைக௠காணà¯à®ªà®¿
+outline_label=ஆவண வெளிவரை
+attachments.title=இணைபà¯à®ªà¯à®•à®³à¯ˆ காணà¯à®ªà®¿
+attachments_label=இணைபà¯à®ªà¯à®•à®³à¯
+thumbs.title=சிறà¯à®ªà®Ÿà®™à¯à®•à®³à¯ˆà®•à¯ காணà¯à®ªà®¿
+thumbs_label=சிறà¯à®ªà®Ÿà®™à¯à®•à®³à¯
+findbar.title=ஆவணதà¯à®¤à®¿à®²à¯ கணà¯à®Ÿà®±à®¿
+findbar_label=கணà¯à®Ÿà¯à®ªà®¿à®Ÿà®¿
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=பகà¯à®•à®®à¯ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=பகà¯à®•à®¤à¯à®¤à®¿à®©à¯ சிறà¯à®ªà®Ÿà®®à¯ {{page}}
+
+# Find panel button title and messages
+find_label=கணà¯à®Ÿà®±à®¿:
+find_previous.title=இநà¯à®¤ சொறà¯à®±à¯Šà®Ÿà®°à®¿à®©à¯ à®®à¯à®¨à¯à®¤à¯ˆà®¯ நிகழà¯à®µà¯ˆ தேடà¯
+find_previous_label=à®®à¯à®¨à¯à®¤à¯ˆà®¯à®¤à¯
+find_next.title=இநà¯à®¤ சொறà¯à®±à¯Šà®Ÿà®°à®¿à®©à¯ அடà¯à®¤à¯à®¤ நிகழà¯à®µà¯ˆ தேடà¯
+find_next_label=அடà¯à®¤à¯à®¤à¯
+find_highlight=அனைதà¯à®¤à¯ˆà®¯à¯à®®à¯ தனிபà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯
+find_match_case_label=பேரெழà¯à®¤à¯à®¤à®¾à®•à¯à®•à®¤à¯à®¤à¯ˆ உணரà¯
+find_reached_top=ஆவணதà¯à®¤à®¿à®©à¯ மேல௠பகà¯à®¤à®¿à®¯à¯ˆ அடைநà¯à®¤à®¤à¯, அடிபà¯à®ªà®•à¯à®•à®¤à¯à®¤à®¿à®²à®¿à®°à¯à®¨à¯à®¤à¯ தொடரà¯à®¨à¯à®¤à®¤à¯
+find_reached_bottom=ஆவணதà¯à®¤à®¿à®©à¯ à®®à¯à®Ÿà®¿à®µà¯ˆ அடைநà¯à®¤à®¤à¯, மேலிரà¯à®¨à¯à®¤à¯ தொடரà¯à®¨à¯à®¤à®¤à¯
+find_not_found=சொறà¯à®±à¯Šà®Ÿà®°à¯ காணவிலà¯à®²à¯ˆ
+
+# Error panel labels
+error_more_info=கூடà¯à®¤à®²à¯ தகவலà¯
+error_less_info=கà¯à®±à¯ˆà®¨à¯à®¤ தகவலà¯
+error_close=மூடà¯à®•
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=செயà¯à®¤à®¿: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=ஸà¯à®Ÿà¯‡à®•à¯: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=கோபà¯à®ªà¯: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=வரி: {{line}}
+rendering_error=இநà¯à®¤à®ªà¯ பகà¯à®•à®¤à¯à®¤à¯ˆ காடà¯à®šà®¿à®ªà¯à®ªà®Ÿà¯à®¤à¯à®¤à¯à®®à¯ போத௠ஒர௠பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯.
+
+# Predefined zoom values
+page_scale_width=பகà¯à®• அகலமà¯
+page_scale_fit=பகà¯à®•à®ªà¯ பொரà¯à®¤à¯à®¤à®®à¯
+page_scale_auto=தானியகà¯à®• பெரிதாகà¯à®•à®²à¯
+page_scale_actual=உணà¯à®®à¯ˆà®¯à®¾à®© அளவà¯
+
+# Loading indicator messages
+loading_error_indicator=பிழை
+loading_error=PDF à® à®à®±à¯à®±à¯à®®à¯ போத௠ஒர௠பிழை à®à®±à¯à®ªà®Ÿà¯à®Ÿà®¤à¯.
+invalid_file_error=செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®¾à®¤ அலà¯à®²à®¤à¯ சிதைநà¯à®¤ PDF கோபà¯à®ªà¯.
+missing_file_error=PDF கோபà¯à®ªà¯ காணவிலà¯à®²à¯ˆ.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} விளகà¯à®•à®®à¯]
+password_label=இநà¯à®¤ PDF கோபà¯à®ªà¯ˆ திறகà¯à®• கடவà¯à®šà¯à®šà¯†à®¾à®²à¯à®²à¯ˆ உளà¯à®³à®¿à®Ÿà®µà¯à®®à¯.
+password_invalid=செலà¯à®²à¯à®ªà®Ÿà®¿à®¯à®¾à®•à®¾à®¤ கடவà¯à®šà¯à®šà¯Šà®²à¯, தயை செயà¯à®¤à¯ மீணà¯à®Ÿà¯à®®à¯ à®®à¯à®¯à®±à¯à®šà®¿ செயà¯à®•.
+password_ok=சரி
+password_cancel=இரதà¯à®¤à¯
+
+printing_not_supported=எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆ: இநà¯à®¤ உலாவி அசà¯à®šà®¿à®Ÿà¯à®¤à®²à¯ˆ à®®à¯à®´à¯à®®à¯ˆà®¯à®¾à®• ஆதரிகà¯à®•à®µà®¿à®²à¯à®²à¯ˆ.
+printing_not_ready=எசà¯à®šà®°à®¿à®•à¯à®•à¯ˆ: PDF அசà¯à®šà®¿à®Ÿ à®®à¯à®´à¯à®µà®¤à¯à®®à®¾à®• à®à®±à¯à®±à®ªà¯à®ªà®Ÿà®µà®¿à®²à¯à®²à¯ˆ.
+web_fonts_disabled=வலை எழà¯à®¤à¯à®¤à¯à®°à¯à®•à¯à®•à®³à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®©: உடà¯à®ªà¯Šà®¤à®¿à®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿ PDF எழà¯à®¤à¯à®¤à¯à®°à¯à®•à¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ à®®à¯à®Ÿà®¿à®¯à®µà®¿à®²à¯à®²à¯ˆ.
+document_colors_disabled=PDF ஆவணஙà¯à®•à®³à¯à®•à¯à®•à¯ அவறà¯à®±à®¿à®©à¯ சொநà¯à®¤ நிறஙà¯à®•à®³à¯ˆà®ªà¯ பயனà¯à®ªà®Ÿà¯à®¤à¯à®¤ அனà¯à®®à®¤à®¿à®¯à®¿à®²à¯à®²à¯ˆ: உலாவியில௠'பகà¯à®•à®™à¯à®•à®³à¯ தஙà¯à®•à®³à¯ சொநà¯à®¤ நிறஙà¯à®•à®³à¯ˆà®¤à¯ தேரà¯à®µà¯ செயà¯à®¤à¯à®•à¯Šà®³à¯à®³ அனà¯à®®à®¤à®¿' எனà¯à®©à¯à®®à¯ விரà¯à®ªà¯à®ªà®®à¯ à®®à¯à®Ÿà®•à¯à®•à®ªà¯à®ªà®Ÿà¯à®Ÿà¯à®³à¯à®³à®¤à¯.
diff --git a/static/pdf.js/locale/te/viewer.properties b/static/pdf.js/locale/te/viewer.properties
new file mode 100644
index 000000000..da549f6e7
--- /dev/null
+++ b/static/pdf.js/locale/te/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=à°•à±à°°à°¿à°¤à°‚ పేజీ
+previous_label=à°•à±à°°à°¿à°¤à°‚
+next.title=తరà±à°µà°¾à°¤ పేజీ
+next_label=తరà±à°µà°¾à°¤
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=పేజీ:
+page_of=మొతà±à°¤à°‚ {{pageCount}} లో
+
+zoom_out.title=జూమౠతగà±à°—à°¿à°‚à°šà±
+zoom_out_label=జూమౠతగà±à°—à°¿à°‚à°šà±
+zoom_in.title=జూమౠచేయి
+zoom_in_label=జూమౠచేయి
+zoom.title=జూమà±
+presentation_mode.title=à°ªà±à°°à°¦à°°à±à°¶à°¨à°¾ రీతికి మారà±
+presentation_mode_label=à°ªà±à°°à°¦à°°à±à°¶à°¨à°¾ రీతి
+open_file.title=ఫైలౠతెరà±à°µà±
+open_file_label=తెరà±à°µà±
+print.title=à°®à±à°¦à±à°°à°¿à°‚à°šà±
+print_label=à°®à±à°¦à±à°°à°¿à°‚à°šà±
+download.title=డౌనà±à°²à±‹à°¡à±
+download_label=డౌనà±à°²à±‹à°¡à±
+bookmark.title=à°ªà±à°°à°¸à±à°¤à±à°¤ దరà±à°¶à°¨à°‚ (నకలà±à°¤à±€à°¯à°¿ లేదా కొతà±à°¤ విండోనందౠతెరà±à°µà±à°®à±)
+bookmark_label=à°ªà±à°°à°¸à±à°¤à±à°¤ దరà±à°¶à°¨à°‚
+
+# Secondary toolbar and context menu
+tools.title=పనిమà±à°Ÿà±à°²à±
+tools_label=పనిమà±à°Ÿà±à°²à±
+first_page.title=మొదటి పేజీకి వెళà±à°³à±
+first_page.label=మొదటి పేజీకి వెళà±à°³à±
+first_page_label=మొదటి పేజీకి వెళà±à°³à±
+last_page.title=చివరి పేజీకి వెళà±à°³à±
+last_page.label=చివరి పేజీకి వెళà±à°³à±
+last_page_label=చివరి పేజీకి వెళà±à°³à±
+page_rotate_cw.title=సవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±à°®à±
+page_rotate_cw.label=సవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±à°®à±
+page_rotate_cw_label=సవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±à°®à±
+page_rotate_ccw.title=అపసవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±à°®à±
+page_rotate_ccw.label=అపసవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±à°®à±
+page_rotate_ccw_label=అపసవà±à°¯à°¦à°¿à°¶à°²à±‹ తిపà±à°ªà±à°®à±
+
+hand_tool_enable.title=చేతి సాధనం చేతనించà±
+hand_tool_enable_label=చేతి సాధనం చేతనించà±
+hand_tool_disable.title=చేతి సాధనం అచేతనించà±
+hand_tool_disable_label=చేతి సాధనం అచేతనించà±
+
+# Document properties dialog box
+document_properties.title=పతà±à°°à°®à± లకà±à°·à°£à°¾à°²à±...
+document_properties_label=పతà±à°°à°®à± లకà±à°·à°£à°¾à°²à±...
+document_properties_file_name=దసà±à°¤à±à°°à°‚ పేరà±:
+document_properties_file_size=దసà±à°¤à±à°°à°‚ పరిమాణం:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=శీరà±à°·à°¿à°•:
+document_properties_author=మూలకరà±à°¤:
+document_properties_subject=విషయం:
+document_properties_keywords=కీపదాలà±:
+document_properties_creation_date=సృషà±à°Ÿà°¿à°‚à°šà°¿à°¨ తేదీ:
+document_properties_modification_date=సవరించిన తేదీ:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=సృషà±à°Ÿà°¿à°•à°°à±à°¤:
+document_properties_producer=PDF ఉతà±à°ªà°¾à°¦à°•à°¿:
+document_properties_version=PDF వరà±à°·à°¨à±:
+document_properties_page_count=పేజీల సంఖà±à°¯:
+document_properties_close=మూసివేయి
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=పకà±à°•à°ªà°Ÿà±à°Ÿà±€ మారà±à°šà±
+toggle_sidebar_label=పకà±à°•à°ªà°Ÿà±à°Ÿà±€ మారà±à°šà±
+outline.title=పతà±à°°à°®à± à°…à°µà±à°Ÿà±â€Œà°²à±ˆà°¨à± చూపà±
+outline_label=పతà±à°°à°®à± à°…à°µà±à°Ÿà±â€Œà°²à±ˆà°¨à±
+attachments.title=à°…à°¨à±à°¬à°‚ధాలౠచూపà±
+attachments_label=à°…à°¨à±à°¬à°‚ధాలà±
+thumbs.title=థంబà±â€Œà°¨à±ˆà°²à±à°¸à± చూపà±
+thumbs_label=థంబà±â€Œà°¨à±ˆà°²à±à°¸à±
+findbar.title=à°ˆ పతà±à°°à°®à±à°¨à°‚దౠకనà±à°—ొనà±à°®à±
+findbar_label=à°•à°¨à±à°—ొనà±
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=పేజీ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=పేజీ {{page}} యొకà±à°• థంబà±â€Œà°¨à±ˆà°²à±
+
+# Find panel button title and messages
+find_label=à°•à°¨à±à°—ొనà±:
+find_previous.title=పదంయొకà±à°• à°®à±à°‚దలి సంà°à°µà°¾à°¨à±à°¨à°¿ à°•à°¨à±à°—ొనà±
+find_previous_label=à°®à±à°¨à±à°ªà°Ÿà°¿
+find_next.title=పదం యొకà±à°• తరà±à°µà°¾à°¤à°¿ సంà°à°µà°¾à°¨à±à°¨à°¿ à°•à°¨à±à°—ొనà±
+find_next_label=తరà±à°µà°¾à°¤
+find_highlight=à°…à°¨à±à°¨à°¿à°Ÿà°¿à°¨à°¿ ఉదà±à°¦à±€à°ªà°¨à°‚ చేయà±à°®à±
+find_match_case_label=à°…à°•à±à°·à°°à°®à±à°²à°¤à±‡à°¡à°¾à°¤à±‹ పోలà±à°šà±à°®à±
+find_reached_top=పేజీ పైకి చేరà±à°•à±à°¨à±à°¨à°¦à°¿, à°•à±à°°à°¿à°‚ది à°¨à±à°‚à°¡à°¿ కొనసాగించండి
+find_reached_bottom=పేజీ చివరకౠచేరà±à°•à±à°¨à±à°¨à°¦à°¿, పైనà±à°‚à°¡à°¿ కొనసాగించండి
+find_not_found=పదం కనబడలేదà±
+
+# Error panel labels
+error_more_info=మరింత సమాచారం
+error_less_info=తకà±à°•à±à°µ సమాచారం
+error_close=మూసివేయి
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=సందేశం: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=à°¸à±à°Ÿà°¾à°•à±: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=ఫైలà±: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=వరà±à°¸: {{line}}
+rendering_error=పేజీనౠరెండరౠచేయà±à°Ÿà°²à±‹ వొక దోషం యెదà±à°°à±ˆà°‚ది.
+
+# Predefined zoom values
+page_scale_width=పేజీ వెడలà±à°ªà±
+page_scale_fit=పేజీ అమరà±à°ªà±
+page_scale_auto=à°¸à±à°µà°¯à°‚చాలక జూమà±
+page_scale_actual=యథారà±à°§ పరిమాణం
+
+# Loading indicator messages
+loading_error_indicator=దోషం
+loading_error=PDF లోడవà±à°šà±à°¨à±à°¨à°ªà±à°ªà±à°¡à± వొక దోషం యెదà±à°°à±ˆà°‚ది.
+invalid_file_error=చెలà±à°²à°¨à°¿ లేదా పాడైన PDF ఫైలà±.
+missing_file_error=దొరకని PDF ఫైలà±.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} టీకా]
+password_label=à°ˆ PDF ఫైలౠతెరà±à°šà±à°Ÿà°•à± సంకేతపదం à°ªà±à°°à°µà±‡à°¶à°ªà±†à°Ÿà±à°Ÿà±à°®à±
+password_invalid=సంకేతపదం చెలà±à°²à°¦à±. దయచేసి మళà±à°³à±€ à°ªà±à°°à°¯à°¤à±à°¨à°¿à°‚à°šà°‚à°¡à°¿.
+password_ok=సరే
+password_cancel=à°°à°¦à±à°¦à±à°šà±‡à°¯à°¿
+
+printing_not_supported=హెచà±à°šà°°à°¿à°•: à°ˆ విహారిణి చేత à°®à±à°¦à±à°°à°£ పూరà±à°¤à°¿à°—à°¾ తోడà±à°ªà°¾à°Ÿà±à°¨à±€à°¯à°¬à°¡à±à°Ÿ లేదà±
+printing_not_ready=హెచà±à°šà°°à°¿à°•: à°®à±à°¦à±à°°à°£ కొరకౠఈ PDF పూరà±à°¤à°¿à°—à°¾ లోడవలేదà±.
+web_fonts_disabled=వెబౠఫాంటà±à°²à± అచేతనపరచ బడెనà±: ఎంబెడెడౠPDF ఫాంటà±à°²à± à°µà±à°ªà°¯à±‹à°—ించలేక పోయింది.
+document_colors_disabled=PDF పతà±à°°à°¾à°²à± వాటి à°¸à±à°µà°‚à°¤ à°°à°‚à°—à±à°²à°¨à± à°µà±à°ªà°¯à±‹à°—à°¿à°‚à°šà±à°•à±Šà°¨à±à°Ÿà°•à± à°…à°¨à±à°®à°¤à°¿à°‚చబడవà±: విహరణి నందౠ'పేజీలనౠవాటి à°¸à±à°µà°‚à°¤ à°°à°‚à°—à±à°²à°¨à± యెంచà±à°•à±Šà°¨à±à°Ÿà°•à± à°…à°¨à±à°®à°¤à°¿à°‚à°šà±' à°…à°¨à±à°¨à°¦à°¿ అచేతనం చేయబడివà±à°‚ది.
diff --git a/static/pdf.js/locale/th/viewer.properties b/static/pdf.js/locale/th/viewer.properties
new file mode 100644
index 000000000..eae74960b
--- /dev/null
+++ b/static/pdf.js/locale/th/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=หน้าà¸à¹ˆà¸à¸™à¸«à¸™à¹‰à¸²
+previous_label=à¸à¹ˆà¸à¸™à¸«à¸™à¹‰à¸²
+next.title=หน้าถัดไป
+next_label=ถัดไป
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=หน้า:
+page_of=จาภ{{pageCount}}
+
+zoom_out.title=ย่à¸
+zoom_out_label=ย่ภOut
+zoom_in.title=ขยาย
+zoom_in_label=ขยาย
+zoom.title=ย่à¸-ขยาย
+presentation_mode.title=สลับเข้าสู่รูปà¹à¸šà¸šà¸à¸²à¸£à¸™à¸³à¹€à¸ªà¸™à¸
+presentation_mode_label=รูปà¹à¸šà¸šà¸à¸²à¸£à¸™à¸³à¹€à¸ªà¸™à¸
+open_file.title=เปิดà¹à¸Ÿà¹‰à¸¡
+open_file_label=เปิด
+print.title=พิมพ์
+print_label=พิมพ์
+download.title=ดาวน์โหลด
+download_label=ดาวน์โหลด
+bookmark.title=มุมมà¸à¸‡à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™ (คัดลà¸à¸à¸«à¸£à¸·à¸à¹€à¸›à¸´à¸”ในหน้าต่างใหม่)
+bookmark_label=มุมมà¸à¸‡à¸›à¸±à¸ˆà¸ˆà¸¸à¸šà¸±à¸™
+
+# Secondary toolbar and context menu
+tools.title=เครื่à¸à¸‡à¸¡à¸·à¸
+tools_label=เครื่à¸à¸‡à¸¡à¸·à¸
+first_page.title=ไปยังหน้าà¹à¸£à¸
+first_page.label=ไปยังหน้าà¹à¸£à¸
+first_page_label=ไปยังหน้าà¹à¸£à¸
+last_page.title=ไปยังหน้าสุดท้าย
+last_page.label=ไปยังหน้าสุดท้าย
+last_page_label=ไปยังหน้าสุดท้าย
+page_rotate_cw.title=หมุนตามเข็มนาฬิà¸à¸²
+page_rotate_cw.label=หมุนตามเข็มนาฬิà¸à¸²
+page_rotate_cw_label=หมุนตามเข็มนาฬิà¸à¸²
+page_rotate_ccw.title=หมุนทวนเข็มนาฬิà¸à¸²
+page_rotate_ccw.label=หมุนทวนเข็มนาฬิà¸à¸²
+page_rotate_ccw_label=หมุนทวนเข็มนาฬิà¸à¸²
+
+hand_tool_enable.title=เปิดใช้งานเครื่à¸à¸‡à¸¡à¸·à¸à¸£à¸¹à¸›à¸¡à¸·à¸
+hand_tool_enable_label=เปิดใช้งานเครื่à¸à¸‡à¸¡à¸·à¸à¸£à¸¹à¸›à¸¡à¸·à¸
+hand_tool_disable.title=ปิดใช้งานเครื่à¸à¸‡à¸¡à¸·à¸à¸£à¸¹à¸›à¸¡à¸·à¸
+hand_tool_disable_label=ปิดใช้งานเครื่à¸à¸‡à¸¡à¸·à¸à¸£à¸¹à¸›à¸¡à¸·à¸
+
+# Document properties dialog box
+document_properties.title=คุณสมบัติเà¸à¸à¸ªà¸²à¸£â€¦
+document_properties_label=คุณสมบัติเà¸à¸à¸ªà¸²à¸£â€¦
+document_properties_file_name=ชื่à¸à¹à¸Ÿà¹‰à¸¡ :
+document_properties_file_size=ขนาดà¹à¸Ÿà¹‰à¸¡ :
+document_properties_kb={{size_kb}} à¸à¸´à¹‚ลไบต์ ({{size_b}} ไบต์)
+document_properties_mb={{size_mb}} เมà¸à¸°à¹„บต์ ({{size_b}} ไบต์)
+document_properties_title=หัวเรื่à¸à¸‡ :
+document_properties_author=ผู้à¹à¸•à¹ˆà¸‡ :
+document_properties_subject=หัวข้ภ:
+document_properties_keywords=คำสำคัภ:
+document_properties_creation_date=วันที่สร้าง :
+document_properties_modification_date=วันที่à¹à¸à¹‰à¹„ข :
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=สร้างโดย :
+document_properties_producer=ผู้ผลิต PDF :
+document_properties_version=รุ่น PDF :
+document_properties_page_count=จำนวนหน้า :
+document_properties_close=ปิด
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=สลับà¹à¸–บข้าง
+toggle_sidebar_label=สลับà¹à¸–บข้าง
+outline.title=à¹à¸ªà¸”งโครงเà¸à¸à¸ªà¸²à¸£
+outline_label=โครงเà¸à¸à¸ªà¸²à¸£
+attachments.title=à¹à¸ªà¸”งสิ่งที่à¹à¸™à¸šà¸¡à¸²
+attachments_label=สิ่งที่à¹à¸™à¸šà¸¡à¸²
+thumbs.title=à¹à¸ªà¸”งภาพขนาดย่à¸
+thumbs_label=ภาพขนาดย่à¸
+findbar.title=ค้นหาในเà¸à¸à¸ªà¸²à¸£
+findbar_label=ค้นหา
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=หน้า {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=ภาพขนาดย่à¸à¸‚à¸à¸‡à¸«à¸™à¹‰à¸² {{page}}
+
+# Find panel button title and messages
+find_label=ค้นหา:
+find_previous.title=หาตำà¹à¸«à¸™à¹ˆà¸‡à¸à¹ˆà¸à¸™à¸«à¸™à¹‰à¸²à¸‚à¸à¸‡à¸„ำค้น
+find_previous_label=à¸à¹ˆà¸à¸™à¸«à¸™à¹‰à¸²
+find_next.title=หาตำà¹à¸«à¸™à¹ˆà¸‡à¸–ัดไปขà¸à¸‡à¸„ำค้น
+find_next_label=ถัดไป
+find_highlight=เน้นสีทั้งหมด
+find_match_case_label=ตัวพิมพ์ตรงà¸à¸±à¸™
+find_reached_top=ค้นหาถึงจุดเริ่มต้นขà¸à¸‡à¸«à¸™à¹‰à¸² เริ่มค้นต่à¸à¸ˆà¸²à¸à¸”้านล่าง
+find_reached_bottom=ค้นหาถึงจุดสิ้นสุดหน้า เริ่มค้นต่à¸à¸ˆà¸²à¸à¸”้านบน
+find_not_found=ไม่พบวลีที่ต้à¸à¸‡à¸à¸²à¸£
+
+# Error panel labels
+error_more_info=ข้à¸à¸¡à¸¹à¸¥à¹€à¸žà¸´à¹ˆà¸¡à¹€à¸•à¸´à¸¡
+error_less_info=ข้à¸à¸¡à¸¹à¸¥à¸™à¹‰à¸à¸¢
+error_close=ปิด
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=ข้à¸à¸„วาม: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=สà¹à¸•à¹‡à¸: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=à¹à¸Ÿà¹‰à¸¡: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=บรรทัด: {{line}}
+rendering_error=เà¸à¸´à¸”ข้à¸à¸œà¸´à¸”พลาดขณะà¸à¸³à¸¥à¸±à¸‡à¸„ำนวณà¸à¸²à¸£à¹à¸ªà¸”งผลขà¸à¸‡à¸«à¸™à¹‰à¸²
+
+# Predefined zoom values
+page_scale_width=ความà¸à¸§à¹‰à¸²à¸‡à¸«à¸™à¹‰à¸²
+page_scale_fit=พà¸à¸”ีหน้า
+page_scale_auto=ย่à¸-ขยายà¸à¸±à¸•à¹‚นมัติ
+page_scale_actual=ขนาดเท่าจริง
+
+# Loading indicator messages
+loading_error_indicator=ข้à¸à¸œà¸´à¸”พลาด
+loading_error=เà¸à¸´à¸”ข้à¸à¸œà¸´à¸”พลาดขณะà¸à¸³à¸¥à¸±à¸‡à¹‚หลด PDF
+invalid_file_error=à¹à¸Ÿà¹‰à¸¡ PDF ไม่ถูà¸à¸•à¹‰à¸à¸‡à¸«à¸£à¸·à¸à¹„ม่สมบูรณ์
+missing_file_error=à¹à¸Ÿà¹‰à¸¡ PDF หาย
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[คำà¸à¸˜à¸´à¸šà¸²à¸¢à¸›à¸£à¸°à¸à¸à¸š {{type}}]
+password_label=ใส่รหัสผ่านเพื่à¸à¹€à¸›à¸´à¸”ไฟล์ PDF นี้
+password_invalid=รหัสผ่านไม่ถูà¸à¸•à¹‰à¸à¸‡ โปรดลà¸à¸‡à¸à¸µà¸à¸„รั้ง
+password_ok=ตà¸à¸¥à¸‡
+password_cancel=ยà¸à¹€à¸¥à¸´à¸
+
+printing_not_supported=คำเตืà¸à¸™: เบราเซà¸à¸£à¹Œà¸™à¸µà¹‰à¹„ม่ได้สนับสนุนà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œà¸à¸¢à¹ˆà¸²à¸‡à¹€à¸•à¹‡à¸¡à¸—ี่
+printing_not_ready=คำเตืà¸à¸™: PDF ไม่ได้รับà¸à¸²à¸£à¹‚หลดà¸à¸¢à¹ˆà¸²à¸‡à¹€à¸•à¹‡à¸¡à¸—ี่สำหรับà¸à¸²à¸£à¸žà¸´à¸¡à¸žà¹Œ
+web_fonts_disabled=à¹à¸šà¸šà¸à¸±à¸à¸©à¸£à¹€à¸§à¹‡à¸šà¸–ูà¸à¸›à¸´à¸”à¸à¸²à¸£à¹ƒà¸Šà¹‰à¸‡à¸²à¸™: ไม่สามารถใช้à¹à¸šà¸šà¸à¸±à¸à¸©à¸£à¸à¸±à¸‡à¸•à¸±à¸§à¹ƒà¸™ PDF
+document_colors_disabled=เà¸à¸à¸ªà¸²à¸£ PDF ไม่ได้รับà¸à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰à¹ƒà¸Šà¹‰à¸ªà¸µà¸‚à¸à¸‡à¸•à¸±à¸§à¹€à¸à¸‡: 'à¸à¸™à¸¸à¸à¸²à¸•à¹ƒà¸«à¹‰à¸«à¸™à¹‰à¸²à¹€à¸à¸à¸ªà¸²à¸£à¸ªà¸²à¸¡à¸²à¸£à¸–เลืà¸à¸à¸ªà¸µà¸‚à¸à¸‡à¸•à¸±à¸§à¹€à¸à¸‡' ถูà¸à¸›à¸´à¸”ใช้งานในเบราเซà¸à¸£à¹Œ
diff --git a/static/pdf.js/locale/tl/viewer.properties b/static/pdf.js/locale/tl/viewer.properties
new file mode 100644
index 000000000..07d86eb14
--- /dev/null
+++ b/static/pdf.js/locale/tl/viewer.properties
@@ -0,0 +1,83 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Naunang Pahina
+next.title=Sunod na Pahina
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Pahina:
+page_of=ng {{bilangngPahina}}
+
+open_file.title=Magbukas ng file
+open_file_label=Buksan
+bookmark.title=Kasalukuyang tingin (kopyahin o buksan sa bagong window)
+bookmark_label=Kasalukuyang tingin
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_title=Pamagat:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+outline.title=Ipakita ang banghay ng dokumento
+outline_label=Banghay ng dokumento
+thumbs.title=Ipakita ang mga Thumbnails
+findbar_label=Hanapin
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Pahina {{pahina}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Thumbnail ng Pahina {{pahina}}
+
+# Find panel button title and messages
+
+# Error panel labels
+error_more_info=Maraming Inpormasyon
+error_less_info=Maikling Inpormasyon
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Mensahe: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Linya: { { linya } }
+rendering_error=May naganap na pagkakamali habang pagsasalin sa pahina.
+
+# Predefined zoom values
+page_scale_width=Haba ng Pahina
+page_scale_fit=ang pahina ay angkop
+page_scale_auto=awtomatikong pag-imbulog
+
+# Loading indicator messages
+loading_error=May maling nangyari habang kinakarga ang PDF.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+password_ok=OK
+
diff --git a/static/pdf.js/locale/tn/viewer.properties b/static/pdf.js/locale/tn/viewer.properties
new file mode 100644
index 000000000..805a688c0
--- /dev/null
+++ b/static/pdf.js/locale/tn/viewer.properties
@@ -0,0 +1,72 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Tsebe:
+
+zoom.title=Zuma/gogela
+open_file.title=Bula Faele
+open_file_label=Bula
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_file_name=Leina la faele:
+document_properties_title=Leina:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+findbar_label=Batla
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+
+# Find panel button title and messages
+find_previous.title=Batla tiragalo e e fetileng ya setlhopha sa mafoko
+find_next.title=Batla tiragalo e e latelang ya setlhopha sa mafoko
+find_not_found=Setlhopha sa mafoko ga se a bonwa
+
+# Error panel labels
+error_more_info=Tshedimosetso e Nngwe
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+
+# Predefined zoom values
+
+# Loading indicator messages
+loading_error_indicator=Phoso
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+password_ok=Siame
+password_cancel=Khansela
+
diff --git a/static/pdf.js/locale/tr/viewer.properties b/static/pdf.js/locale/tr/viewer.properties
index c4b172c7f..6eefe2760 100644
--- a/static/pdf.js/locale/tr/viewer.properties
+++ b/static/pdf.js/locale/tr/viewer.properties
@@ -13,9 +13,9 @@
# limitations under the License.
# Main toolbar buttons (tooltips and alt text for images)
-previous.title=Önceki Sayfa
+previous.title=Önceki sayfa
previous_label=Önceki
-next.title=Sonraki Sayfa
+next.title=Sonraki sayfa
next_label=Sonraki
# LOCALIZATION NOTE (page_label, page_of):
@@ -23,48 +23,77 @@ next_label=Sonraki
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
page_label=Sayfa:
-page_of=- {{pageCount}}
+page_of=/ {{pageCount}}
-zoom_out.title=UzaklaÅŸ
-zoom_out_label=UzaklaÅŸ
-zoom_in.title=Yakınlaş
-zoom_in_label=Yakınlaş
-zoom.title=Yakınlaştır
-presentation_mode.title=Sunum moduna geçiş yap
+zoom_out.title=UzaklaÈ™
+zoom_out_label=UzaklaÈ™
+zoom_in.title=YaklaÅŸ
+zoom_in_label=YaklaÅŸ
+zoom.title=Yakınlaştırma
+presentation_mode.title=Sunum moduna geç
presentation_mode_label=Sunum Modu
-open_file.title=Dosya Aç
+open_file.title=Dosya aç
open_file_label=Aç
print.title=Yazdır
print_label=Yazdır
download.title=Ä°ndir
download_label=Ä°ndir
-bookmark.title=Mevcut görünüm (kopyala yada yeni sayfada aç)
-bookmark_label=Mevcut Görünüm
+bookmark.title=Geçerli görünüm (kopyala veya yeni pencerede aç)
+bookmark_label=Geçerli görünüm
# Secondary toolbar and context menu
-first_page.title=Ä°lk Sayfaya Git
-first_page.label=Ä°lk Sayfaya Git
-first_page_label=Ä°lk Sayfaya Git
-last_page.title=Son Sayfaya Git
-last_page.label=Son Sayfaya Git
-last_page_label=Son Sayfaya Git
-page_rotate_cw.title=Sağa Çevir
-page_rotate_cw.label=Sağa Çevir
-page_rotate_cw_label=Sağa Çevir
-page_rotate_ccw.title=Sola Çevir
-page_rotate_ccw.label=Sola Çevir
-page_rotate_ccw_label=Sola Çevir
+tools.title=Araçlar
+tools_label=Araçlar
+first_page.title=Ä°lk sayfaya git
+first_page.label=Ä°lk sayfaya git
+first_page_label=Ä°lk sayfaya git
+last_page.title=Son sayfaya git
+last_page.label=Son sayfaya git
+last_page_label=Son sayfaya git
+page_rotate_cw.title=Saat yönünde döndür
+page_rotate_cw.label=Saat yönünde döndür
+page_rotate_cw_label=Saat yönünde döndür
+page_rotate_ccw.title=Saat yönünün tersine döndür
+page_rotate_ccw.label=Saat yönünün tersine döndür
+page_rotate_ccw_label=Saat yönünün tersine döndür
+
+hand_tool_enable.title=El aracını etkinleştir
+hand_tool_enable_label=El aracını etkinleştir
+hand_tool_disable.title=El aracını kapat
+hand_tool_disable_label=El aracını kapat
+
+# Document properties dialog box
+document_properties.title=Belge özellikleri…
+document_properties_label=Belge özellikleri…
+document_properties_file_name=Dosya adı:
+document_properties_file_size=Dosya boyutu:
+document_properties_kb={{size_kb}} KB ({{size_b}} bayt)
+document_properties_mb={{size_mb}} MB ({{size_b}} bayt)
+document_properties_title=Başlık:
+document_properties_author=Yazar:
+document_properties_subject=Konu:
+document_properties_keywords=Anahtar kelimeler:
+document_properties_creation_date=Oluturma tarihi:
+document_properties_modification_date=DeÄŸiÅŸtirme tarihi:
+document_properties_date_string={{date}} {{time}}
+document_properties_creator=OluÅŸturan:
+document_properties_producer=PDF üreticisi:
+document_properties_version=PDF sürümü:
+document_properties_page_count=Sayfa sayısı:
+document_properties_close=Kapat
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Yan Menü Aç/Kapa
-toggle_sidebar_label=Yan Menü
-outline.title=Sayfa kenarlıklarını döster
-outline_label=Sayfa Kenarlıkları
-thumbs.title=Önizleme resimlerini göster
-thumbs_label=Önizleme
-findbar.title=Döküman içerisinde bul
+toggle_sidebar.title=Kenar çubuğunu aç/kapat
+toggle_sidebar_label=Kenar çubuğunu aç/kapat
+outline.title=Belge şemasını göster
+outline_label=Belge şeması
+attachments.title=Ekleri göster
+attachments_label=Ekler
+thumbs.title=Küçük resimleri göster
+thumbs_label=Küçük resimler
+findbar.title=Belgede bul
findbar_label=Bul
# Thumbnails panel item (tooltip and alt text for images)
@@ -73,30 +102,30 @@ findbar_label=Bul
thumb_page_title=Sayfa {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas={{page}} sayfasının ön izlemesi
+thumb_page_canvas={{page}}. sayfanın küçük hâli
# Find panel button title and messages
find_label=Bul:
-find_previous.title=Önceki cümleyi bul
+find_previous.title=Önceki eşleşmeyi bul
find_previous_label=Önceki
-find_next.title=Sonraki cümleyi bul
+find_next.title=Sonraki eÅŸleÅŸmeyi bul
find_next_label=Sonraki
-find_highlight=Hepsini belirt
-find_match_case_label=harf eÅŸleme
-find_reached_top=Dosyanın en üstüne varıldı. Sonundan devam ediliyor
-find_reached_bottom=Dosyanın sonuna varıldı. Başından devam ediliyor
-find_not_found=Aramanızla eşleşen sonuç yok
+find_highlight=Tümünü vurgula
+find_match_case_label=Büyük-küçük harf eşleştir
+find_reached_top=Belgenin başına ulaşıldı, sonundan devam edildi
+find_reached_bottom=Belgenin sonuna ulaşıldı, başından devam edildi
+find_not_found=Eşleşme bulunamadı
# Error panel labels
-error_more_info=Daha falza bilgi
-error_less_info=daha az bilgi
+error_more_info=Daha fazla bilgi
+error_less_info=Daha az bilgi
error_close=Kapat
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (build: {{build}})
+error_version_info=PDF.js sürüm {{version}} (yapı: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=Mesaj: {{message}}
+error_message=Ä°leti: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
error_stack=Yığın: {{stack}}
@@ -104,26 +133,31 @@ error_stack=Yığın: {{stack}}
error_file=Dosya: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Satır: {{line}}
-rendering_error=Sayfa oluÅŸturulurken bir hata meydana geldi.
+rendering_error=Sayfa yorumlanırken bir hata oluştu.
# Predefined zoom values
-page_scale_width=Sayfa GeniÅŸliÄŸi
-page_scale_fit=Sayfayı Sığdır
-page_scale_auto=Otomatik Yakınlaşma
+page_scale_width=Sayfa geniÅŸliÄŸi
+page_scale_fit=Sayfayı sığdır
+page_scale_auto=Otomatik yakınlaştır
page_scale_actual=Gerçek boyut
# Loading indicator messages
loading_error_indicator=Hata
-loading_error=PDF yüklenirken hata.
-invalid_file_error=Geçersiz yada bozuk dosya.
-missing_file_error=PDF dosyası bulunamadı.
+loading_error=PDF yüklenirken bir hata oluştu.
+invalid_file_error=Geçersiz veya bozulmuş PDF dosyası.
+missing_file_error=PDF dosyası eksik.
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type.alt=[{{type}} Not]
-request_password=PDF Åžifre ile korunmakta:
+text_annotation_type.alt=[{{type}} iÅŸareti]
+password_label=Bu PDF dosyasını açmak için parolasını girin.
+password_invalid=Geçersiz parola. Lütfen tekrar deneyin.
+password_ok=Tamam
+password_cancel=Ä°ptal
-printing_not_supported=Uyarı: Yazdırma işlemi bu tarayıcı ile tam desteklenmiyor.
-web_fonts_disabled=Web Fontları devre dışı. Web fontlar yüklenemiyor.
+printing_not_supported=Uyarı: Yazdırma bu tarayıcı tarafından tam olarak desteklenmemektedir.
+printing_not_ready=Uyarı: PDF tamamen yüklenmedi ve yazdırmaya hazır değil.
+web_fonts_disabled=Web fontları devre dışı: Gömülü PDF fontları kullanılamıyor.
+document_colors_disabled=PDF belgelerinin kendi renklerini kullanması için izin verilmiyor: 'Sayfalara kendi renklerini seçmesi için izin ver' tarayıcıda etkinleştirilmemiş.
diff --git a/static/pdf.js/locale/uk/viewer.properties b/static/pdf.js/locale/uk/viewer.properties
new file mode 100644
index 000000000..6bfcc7674
--- /dev/null
+++ b/static/pdf.js/locale/uk/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð½Ñ Ñторінка
+previous_label=ПопереднÑ
+next.title=ÐаÑтупна Ñторінка
+next_label=ÐаÑтупна
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Сторінка:
+page_of=з {{pageCount}}
+
+zoom_out.title=Зменшити
+zoom_out_label=Зменшити
+zoom_in.title=Збільшити
+zoom_in_label=Збільшити
+zoom.title=МаÑштаб
+presentation_mode.title=Перейти в режим презентації
+presentation_mode_label=Режим презентації
+open_file.title=Відкрити файл
+open_file_label=Відкрити
+print.title=Друк
+print_label=Друк
+download.title=Завантажити
+download_label=Завантажити
+bookmark.title=Поточний виглÑд (копіювати чи відкрити у новому вікні)
+bookmark_label=Поточний виглÑд
+
+# Secondary toolbar and context menu
+tools.title=ІнÑтрументи
+tools_label=ІнÑтрументи
+first_page.title=Ðа першу Ñторінку
+first_page.label=Ðа першу Ñторінку
+first_page_label=Ðа першу Ñторінку
+last_page.title=Ðа оÑтанню Ñторінку
+last_page.label=Ðа оÑтанню Ñторінку
+last_page_label=Ðа оÑтанню Ñторінку
+page_rotate_cw.title=Повернути за годинниковою Ñтрілкою
+page_rotate_cw.label=Повернути за годинниковою Ñтрілкою
+page_rotate_cw_label=Повернути за годинниковою Ñтрілкою
+page_rotate_ccw.title=Повернути проти годинникової Ñтрілки
+page_rotate_ccw.label=Повернути проти годинникової Ñтрілки
+page_rotate_ccw_label=Повернути проти годинникової Ñтрілки
+
+hand_tool_enable.title=Увімкнути інÑтрумент «Рука»
+hand_tool_enable_label=Увімкнути інÑтрумент «Рука»
+hand_tool_disable.title=Вимкнути інÑтрумент «Рука»
+hand_tool_disable_label=Вимкнути інÑтрумент «Рука»
+
+# Document properties dialog box
+document_properties.title=ВлаÑтивоÑÑ‚Ñ– документа…
+document_properties_label=ВлаÑтивоÑÑ‚Ñ– документа…
+document_properties_file_name=Ðазва файла:
+document_properties_file_size=Розмір файла:
+document_properties_kb={{size_kb}} КБ ({{size_b}} bytes)
+document_properties_mb={{size_mb}} МБ ({{size_b}} bytes)
+document_properties_title=Заголовок:
+document_properties_author=Ðвтор:
+document_properties_subject=Тема:
+document_properties_keywords=Ключові Ñлова:
+document_properties_creation_date=Дата ÑтвореннÑ:
+document_properties_modification_date=Дата зміни:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Створено:
+document_properties_producer=Виробник PDF:
+document_properties_version=ВерÑÑ–Ñ PDF:
+document_properties_page_count=КількіÑÑ‚ÑŒ Ñторінок:
+document_properties_close=Закрити
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Перемкнути бічну панель
+toggle_sidebar_label=Перемкнути бічну панель
+outline.title=Показувати Ñхему документа
+outline_label=Схема документа
+attachments.title=Показати прикріпленнÑ
+attachments_label=ПрикріпленнÑ
+thumbs.title=Показувати еÑкізи
+thumbs_label=ЕÑкізи
+findbar.title=Шукати в документі
+findbar_label=Пошук
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Сторінка {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=ЕÑкіз Ñторінки {{page}}
+
+# Find panel button title and messages
+find_label=Знайти:
+find_previous.title=Знайти попереднє Ð²Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ñ„Ñ€Ð°Ð·Ð¸
+find_previous_label=Попереднє
+find_next.title=Знайти наÑтупне Ð²Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ñ„Ñ€Ð°Ð·Ð¸
+find_next_label=ÐаÑтупне
+find_highlight=ПідÑвітити вÑе
+find_match_case_label=З урахуваннÑм регіÑтру
+find_reached_top=ДоÑÑгнуто початку документу, продовжено з кінцÑ
+find_reached_bottom=ДоÑÑгнуто ÐºÑ–Ð½Ñ†Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ñƒ, продовжено з початку
+find_not_found=Фразу не знайдено
+
+# Error panel labels
+error_more_info=Більше інформації
+error_less_info=Менше інформації
+error_close=Закрити
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=ПовідомленнÑ: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Стек: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Файл: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Ð Ñдок: {{line}}
+rendering_error=Під Ñ‡Ð°Ñ Ñ€ÐµÐ½Ð´ÐµÑ€Ñƒ Ñторінки ÑталаÑÑŒ помилка.
+
+# Predefined zoom values
+page_scale_width=За шириною
+page_scale_fit=УміÑтити
+page_scale_auto=Ðвто-маÑштаб
+page_scale_actual=ДійÑний розмір
+
+# Loading indicator messages
+loading_error_indicator=Помилка
+loading_error=Під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ PDF ÑталаÑÑŒ помилка.
+invalid_file_error=ÐедійÑний або пошкоджений PDF-файл.
+missing_file_error=ВідÑутній PDF-файл.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}}-аннотаціÑ]
+password_label=Введіть пароль Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ†ÑŒÐ¾Ð³Ð¾ PDF-файла.
+password_invalid=Ðевірний пароль. Спробуйте ще.
+password_ok=Гаразд
+password_cancel=СкаÑувати
+
+printing_not_supported=ПопередженнÑ: Цей браузер не повніÑÑ‚ÑŽ підтримує друк.
+printing_not_ready=ПопередженнÑ: PDF не повніÑÑ‚ÑŽ завантажений Ð´Ð»Ñ Ð´Ñ€ÑƒÐºÑƒ.
+web_fonts_disabled=Веб-шрифти вимкнено: неможливо викориÑтати вбудовані у PDF шрифти.
+document_colors_disabled=PDF-документам не дозволено викориÑтовувати Ñвої влаÑні кольори: в браузері вимкнено «Дозволити Ñторінкам викориÑтовувати Ñвої влаÑні кольори».
diff --git a/static/pdf.js/locale/ur/viewer.properties b/static/pdf.js/locale/ur/viewer.properties
new file mode 100644
index 000000000..c52220f17
--- /dev/null
+++ b/static/pdf.js/locale/ur/viewer.properties
@@ -0,0 +1,161 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=پچھلا صÙØÛ
+previous_label=پچھلا
+next.title=اگلا صÙØÛ
+next_label=Ø¢Ú¯Û’
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=صÙØÛ:
+page_of={{pageCount}} کا
+
+zoom_out.title=باÛر زوم کریں
+zoom_out_label=باÛر زوم کریں
+zoom_in.title=اندر زوم کریں
+zoom_in_label=اندر زوم کریں
+zoom.title=زوم
+presentation_mode.title=پیشکش موڈ میں چلے جائیں
+presentation_mode_label=پیشکش موڈ
+open_file.title=مسل کھولیں
+open_file_label=کھولیں
+print.title=چھاپیں
+print_label=چھاپیں
+download.title=ڈاؤن لوڈ
+download_label=ڈاؤن لوڈ
+bookmark.title=ØØ§Ù„ÛŒÛ Ù†Ø¸Ø§Ø±Û (Ù†Û“ Ø¯Ø±ÛŒÚ†Û Ù…ÛŒÚº نقل کریں یا کھولیں)
+bookmark_label=ØØ§Ù„ÛŒÛ Ù†Ø¸Ø§Ø±Û
+
+# Secondary toolbar and context menu
+tools.title=آلات
+tools_label=آلات
+first_page.title=Ù¾ÛÙ„Û’ صÙØÛ Ù¾Ø± جائیں
+first_page.label=Ù¾ÛÙ„Û’ صÙØÛ Ù¾Ø± جائیں
+first_page_label=Ù¾ÛÙ„Û’ صÙØÛ Ù¾Ø± جائیں
+last_page.title=آخری صÙØÛ Ù¾Ø± جائیں
+last_page.label=آخری صÙØÛ Ù¾Ø± جائیں
+last_page_label=آخری صÙØÛ Ù¾Ø± جائیں
+page_rotate_cw.title=گھڑی وار گھمائیں
+page_rotate_cw.label=گھڑی وار گھمائیں
+page_rotate_cw_label=گھڑی وار گھمائیں
+page_rotate_ccw.title=ضد گھڑی وار گھمائیں
+page_rotate_ccw.label=ضد گھڑی وار گھمائیں
+page_rotate_ccw_label=ضد گھڑی وار گھمائیں
+
+hand_tool_enable.title=Ûاتھ ٹول اÛÙ„ بنائیں
+hand_tool_enable_label=Ûاتھ ٹول اÛÙ„ بنائیں
+hand_tool_disable.title=Ûاتھ ٹول nنااÛÙ„ بنائیں
+hand_tool_disable_label=Ûاتھ ٹول نااÛÙ„ بنائیں
+
+# Document properties dialog box
+document_properties.title=دستاویز خواص…
+document_properties_label=دستاویز خواص…
+document_properties_file_name=نام مسل:
+document_properties_file_size=مسل سائز:
+document_properties_kb={{size_kb}} KB ({{size_b}} bytes)
+document_properties_mb={{size_mb}} MB ({{size_b}} bytes)
+document_properties_title=عنوان:
+document_properties_author=تخلیق کار:
+document_properties_subject=موضوع:
+document_properties_keywords=کلیدی الÙاظ:
+document_properties_creation_date=تخلیق کی تاریخ:
+document_properties_modification_date=ترمیم کی تاریخ:
+document_properties_date_string={{date}}، {{time}}
+document_properties_creator=تخلیق کار:
+document_properties_producer=PDF پیدا کار:
+document_properties_version=PDF ورژن:
+document_properties_page_count=صÙØÛ Ø´Ù…Ø§Ø±:
+document_properties_close=بند کریں
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=سلائیڈ ٹوگل کریں
+toggle_sidebar_label=سلائیڈ ٹوگل کریں
+outline.title=دستاویز آؤٹ لائن دکھائیں
+outline_label=دستاویز آؤٹ لائن
+thumbs.title=تھمبنیل دکھائیں
+thumbs_label=مجمل
+findbar.title=دستاویز میں ڈھونڈیں
+findbar_label=ڈھونڈیں
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=صÙØÛ {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=صÙØÛ’ کا مجمل {{page}}
+
+# Find panel button title and messages
+find_label=ڈھونڈیں:
+find_previous.title=Ùقرے کا پچھلا وقوع ڈھونڈیں
+find_previous_label=پچھلا
+find_next.title=Ùقرے کا Ø§Ú¯Ù„Û ÙˆÙ‚ÙˆØ¹ ڈھونڈیں
+find_next_label=Ø¢Ú¯Û’
+find_highlight=تمام نمایاں کریں
+find_match_case_label=ØØ±ÙˆÙ Ù…Ø´Ø§Ø¨Û Ú©Ø±ÛŒÚº
+find_reached_top=صÙØÛ Ú©Û’ شروع پر Ù¾ÛÙ†Ú† گیا، نیچے سے جاری کیا
+find_reached_bottom=صÙØÛ Ú©Û’ اختتام پر Ù¾ÛÙ†Ú† گیا، اوپر سے جاری کیا
+find_not_found=Ùقرا Ù†Ûیں ملا
+
+# Error panel labels
+error_more_info=مزید معلومات
+error_less_info=کم معلومات
+error_close=بند کریں
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=پیغام: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=سٹیک: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=مسل: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=لائن: {{line}}
+rendering_error=صÙØÛ Ø¨Ù†Ø§ØªÛ’ Ûوئے نقص Ø¢ گیا۔
+
+# Predefined zoom values
+page_scale_width=صÙØÛ Ú†ÙˆÚ‘Ø§Ø¦ÛŒ
+page_scale_fit=صÙØÛ Ùٹنگ
+page_scale_auto=خودکار زوم
+page_scale_actual=اصل سائز
+
+# Loading indicator messages
+loading_error_indicator=نقص
+loading_error=PDF لوڈ کرتے وقت نقص آ گیا۔
+invalid_file_error=ناجائز یا خراب PDF مسل
+missing_file_error=PDF مسل غائب ÛÛ’Û”
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} نوٹ]
+password_label=PDF مسل کھولنے کے لیے پاس ورڈ داخل کریں.
+password_invalid=ناجائز پاس ورڈ. براےؑ کرم Ø¯ÙˆØ¨Ø§Ø±Û Ú©ÙˆØ´Ø´ کریں.
+password_ok=سÛÛŒ
+password_cancel=منسوخ کریں
+
+printing_not_supported=تنبیÛ:چھاپنا اس براؤزر پر پوری Ø·Ø±Ø Ù…Ø¹Ø§ÙˆÙ†Øª Ø´Ø¯Û Ù†Ûیں ÛÛ’Û”
+printing_not_ready=تنبیÛ: PDF چھپائی Ú©Û’ لیے پوری Ø·Ø±Ø Ù„ÙˆÚˆ Ù†Ûیں Ûوئی۔
+web_fonts_disabled=ویب Ùانٹ نا اÛÙ„ Ûیں: شامل PDF Ùانٹ استعمال کرنے میں ناکام۔
+document_colors_disabled=PDF دستاویزات Ú©Ùˆ اپنے رنگ استعمال کرنے Ú©ÛŒ اجازت Ù†Ûیں: 'صÙØات Ú©Ùˆ اپنے رنگ چنیں' Ú©ÛŒ اÙجازت براؤزر میں بے عمل ÛÛ’Û”
diff --git a/static/pdf.js/locale/vi/viewer.properties b/static/pdf.js/locale/vi/viewer.properties
index a92af2537..15acc8efa 100644
--- a/static/pdf.js/locale/vi/viewer.properties
+++ b/static/pdf.js/locale/vi/viewer.properties
@@ -15,7 +15,7 @@
# Main toolbar buttons (tooltips and alt text for images)
previous.title=Trang TrÆ°á»›c
previous_label=TrÆ°á»›c
-next.title=Trang Tiếp
+next.title=Trang Sau
next_label=Tiếp
# LOCALIZATION NOTE (page_label, page_of):
@@ -23,109 +23,121 @@ next_label=Tiếp
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
page_label=Trang:
-page_of=trên {{pageCount}}
+page_of=thuá»™c vá» {{pageCount}}
-zoom_out.title=Phóng to
-zoom_out_label=Phóng to
-zoom_in.title=Thu nhá»
-zoom_in_label=Thu nhá»
+zoom_out.title=Thu nhá»
+zoom_out_label=Thu nhá»
+zoom_in.title=Phóng to
+zoom_in_label=Phóng to
zoom.title=Thu phóng
-presentation_mode.title=Chuyển sang chế độ thuyết trình
-presentation_mode_label=Chế độ Thuyết trình
-open_file.title=Mở Tệp
-open_file_label=Tệp
+presentation_mode.title=Chuyển sang chế độ trình chiếu
+presentation_mode_label=Chế độ trình chiếu
+open_file.title=Mở Táºp Tin
+open_file_label=Mở táºp tin
print.title=In
print_label=In
download.title=Tải xuống
download_label=Tải xuống
-bookmark.title=Äánh dấu (sao chép hoặc mở cá»a sổ má»›i)
-bookmark_label=Äánh dấu
+bookmark.title=Góc nhìn hiện tại (copy hoặc mở trong cá»a sổ má»›i)
+bookmark_label=Chế độ xem hiện tại
# Secondary toolbar and context menu
-first_page.title=Äến trang đầu tiên
-first_page.label=Äến trang đầu tiên
-first_page_label=Äến trang đầu tiên
-last_page.title=Äến trang cuối cùng
-last_page.label=Äến trang cuối cùng
-last_page_label=Äến trang cuối cùng
-page_rotate_cw.title=Quay sang phải
-page_rotate_cw.label=Quay sang phải
-page_rotate_cw_label=Quay sang phải
-page_rotate_ccw.title=Quay sang trái
-page_rotate_ccw.label=Quay sang trái
-page_rotate_ccw_label=Quay sang trái
+tools.title=Công cụ
+page_rotate_cw.title=Xoay theo chiá»u kim đồng hồ
+page_rotate_cw.label=Xoay theo chiá»u kim đồng hồ
+page_rotate_cw_label=Xoay theo chiá»u kim đồng hồ
+page_rotate_ccw.title=Xoay ngược chiá»u kim đồng hồ
+page_rotate_ccw.label=Xoay ngược chiá»u kim đồng hồ
+page_rotate_ccw_label=Xoay ngược chiá»u kim đồng hồ
+
+
+# Document properties dialog box
+document_properties_file_size=KÃch thÆ°á»›c táºp tin:
+document_properties_title=Tiêu Ä‘á»:
+document_properties_author=Tác giả:
+document_properties_subject=Chủ Ä‘á»:
+document_properties_keywords=Từ khóa:
+document_properties_creation_date=Ngà y tạo:
+document_properties_modification_date=Ngà y sá»a đổi:
+document_properties_producer=Nhà sản xuất PDF:
+document_properties_version=Phiên bản PDF:
+document_properties_page_count=Tổng số trang:
+document_properties_close=Ãóng
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
-toggle_sidebar.title=Äóng báºt thanh lá»
-toggle_sidebar_label=Báºt tắt thanh lá»
-outline.title=Hiện thị giản lược tà i liệu
-outline_label=Giản lược
-thumbs.title=hiện tà i liệu ở dạng ảnh thu nhá»
-thumbs_label=Ảnh thu nhá»
-findbar.title=Tìm trong văn bản
-findbar_label=Tìm kiếm
+toggle_sidebar.title=Báºt/Tắt Thanh Lá»
+toggle_sidebar_label=Báºt/Tắt Thanh Lá»
+outline.title=Hiển thị bản phác tà i liệu
+outline_label=Bản phác há»a Tà i liệu
+thumbs.title=Hiển thị Thumbnails
+thumbs_label=Thumbnails (hình biểu diá»…n nhá»)
+findbar.title=Tìm trong tà i liệu
+findbar_label=Tìm
# Thumbnails panel item (tooltip and alt text for images)
# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
# number.
-thumb_page_title=Page {{page}}
+thumb_page_title=Trang {{page}}
# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
# number.
-thumb_page_canvas=Thumbnail of Page {{page}}
+thumb_page_canvas=Hình ảnh thu nhỠcủa trang {{page}}
# Find panel button title and messages
-find_label=Tìm:
-find_previous.title=Tìm kiếm câu xuất hiện phÃa trÆ°á»›c
-find_previous_label=Vá» trÆ°á»›c
-find_next.title=Tìm kiếm câu xuất hiện phÃa sau
-find_next_label=Tiếp theo
-find_highlight=Tô sáng toà n bộ
-find_match_case_label=Giống chữ
-find_reached_top=Äến cuối đầu tà i liệu, tiếp tục từ cuối
-find_reached_bottom=Äến cuối tà i liệu, tiếp tục từ đầu
-find_not_found=Không tìm thấy
+find_label=Tìm kiếm:
+find_previous.title=Tìm cụm từ ở phần trước
+find_previous_label=TrÆ°á»›c
+find_next.title=Tìm cụm từ ở phần sau
+find_next_label=Tiếp
+find_highlight=Tô sáng tất cả
+find_match_case_label=Phân biệt chữ hoa, chữ thÆ°á»ng
+find_reached_top=Äã đến phần đầu tà i liệu, quay trở lại từ cuối
+find_reached_bottom=Äã đến phần cuối của tà i liệu, quay trở lại từ đầu
+find_not_found=Không tìm thấy cụm từ
# Error panel labels
-error_more_info=Thông tim thêm
-error_less_info=Thông tin giản lược
+error_more_info=Thông tin thêm
+error_less_info=Hiển thị Ãt thông tin hÆ¡n
error_close=Äóng
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (dịch: {{build}})
+error_version_info=PDF.js v{{version}} (build: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=Thông báo: {{message}}
+error_message=Thông điệp: {{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
-error_stack=Ngăn xếp: {{stack}}
+error_stack=Stack: {{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
error_file=Tệp: {{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
error_line=Dòng: {{line}}
-rendering_error=An error occurred while rendering the page.
+rendering_error=Lỗi khi hiển thị trang.
# Predefined zoom values
-page_scale_width=Ngang
-page_scale_fit=Xem Toà n Trang
-page_scale_auto=Tá»± Äá»™ng
+page_scale_width=Chiá»u rá»™ng trang
+page_scale_fit=Äá»™ vừa của trang
+page_scale_auto=Tự động thu/phóng
page_scale_actual=KÃch thÆ°á»›c thá»±c
# Loading indicator messages
loading_error_indicator=Lá»—i
-loading_error=Lỗi khi mở tệp PDF.
-invalid_file_error=Tệp PDF bị há»ng hoặc lá»—i.
-missing_file_error=Thiếu tệp tin PDF.
+loading_error=Lỗi khi tải tà i liệu PDF.
+invalid_file_error=Táºp tin PDF há»ng hoặc không hợp lệ.
+missing_file_error=Thiếu táºp tin PDF.
-# LOCALIZATION NOTE (text_annotation_type): This is used as a tooltip.
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
-text_annotation_type=[{{type}} Äánh dấu]
-request_password=PDF được bảo vệ bởi máºt mã:
+text_annotation_type.alt=[{{type}} Chú thÃch]
+password_label=Nháºp máºt khẩu để mở táºp tin PDF nà y.
+password_invalid=Máºt khẩu không đúng. Vui lòng thá» lại.
+password_ok=OK
+password_cancel=Hủy bá»
-printing_not_supported=Chú ý: Công việc in ẩn không được hỗ trợ bởi trình duyệt.
-printing_not_ready=Chú ý: Tệp PDF không sẵn sà ng cho in ấn.
-web_fonts_disabled=Phồng chữ cho Web bị vô tác dụng: không thể dùng phông chữ kèm theo tệp PDF.
-web_colors_disabled=Mà u cho Wev bị vô tác dụng.
+printing_not_supported=Cảnh báo: In ấn không được hỗ trợ đầy đủ ở trình duyệt nà y.
+printing_not_ready=Cảnh báo: PDF chưa được tải hết để in.
+web_fonts_disabled=Phông chữ Web bị vô hiệu hóa: không thể sỠdụng các phông chữ PDF được nhúng.
+document_colors_disabled=Tà i liệu PDF không được cho phép dùng mà u riêng: 'Cho phép trang chá»n mà u riêng' đã bị tắt trên trình duyệt.
diff --git a/static/pdf.js/locale/wo/viewer.properties b/static/pdf.js/locale/wo/viewer.properties
new file mode 100644
index 000000000..94965ab96
--- /dev/null
+++ b/static/pdf.js/locale/wo/viewer.properties
@@ -0,0 +1,116 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Xët wi jiitu
+previous_label=Bi jiitu
+next.title=Xët wi ci topp
+next_label=Bi ci topp
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Xët:
+page_of=ci {{pageCount}}
+
+zoom_out.title=Wà ññi
+zoom_out_label=Wà ññi
+zoom_in.title=Yaatal
+zoom_in_label=Yaatal
+zoom.title=Yambalaŋ
+presentation_mode.title=Wañarñil ci anamu wone
+presentation_mode_label=Anamu Wone
+open_file.title=Ubbi benn dencukaay
+open_file_label=Ubbi
+print.title=Móol
+print_label=Móol
+download.title=Yeb yi
+download_label=Yeb yi
+bookmark.title=Wone bi taxaw (duppi walla ubbi palanteer bu bees)
+bookmark_label=Wone bi feeñ
+
+# Secondary toolbar and context menu
+
+
+# Document properties dialog box
+document_properties_title=Bopp:
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+outline.title=Wone takku yi
+outline_label=Takku jukki yi
+thumbs.title=Wone nataal yu ndaw yi
+thumbs_label=Nataal yu ndaw yi
+findbar.title=Gis ci biir jukki bi
+findbar_label=Wut
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Xët {{xët}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Wiñet bu xët{{xët}}
+
+# Find panel button title and messages
+find_label=Wut:
+find_previous.title=Seet beneen kaddu bu ni mel te jiitu
+find_previous_label=Bi jiitu
+find_next.title=Seet beneen kaddu bu ni mel
+find_next_label=Bi ci topp
+find_highlight=Melaxal lépp
+find_match_case_label=Sà mm jëmmalin wi
+find_reached_top=Jot nañu ndorteel xët wi, kontine dale ko ci suuf
+find_reached_bottom=Jot nañu jeexitalu xët wi, kontine ci ndorte
+find_not_found=Gisiñu kaddu gi
+
+# Error panel labels
+error_more_info=Xibaar yu gën bari
+error_less_info=Xibaar yu gën bari
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Bataaxal: {{bataaxal}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Juug: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Dencukaay: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Rëdd : {{line}}
+rendering_error=Am njumte bu am bi xët bi di wonewu.
+
+# Predefined zoom values
+page_scale_width=Yaatuwaay bu mët
+page_scale_fit=Xët lëmm
+page_scale_auto=Yambalaŋ ci saa si
+page_scale_actual=Dayo bi am
+
+# Loading indicator messages
+loading_error_indicator=Njumte
+loading_error=Am na njumte ci yebum dencukaay PDF bi.
+invalid_file_error=Dencukaay PDF bi baaxul walla mu sankar.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Karmat {{type}}]
+password_ok=OK
+password_cancel=Neenal
+
+printing_not_supported=Artu: Joowkat bii nanguwul lool mool.
diff --git a/static/pdf.js/locale/xh/viewer.properties b/static/pdf.js/locale/xh/viewer.properties
new file mode 100644
index 000000000..89c9e8d23
--- /dev/null
+++ b/static/pdf.js/locale/xh/viewer.properties
@@ -0,0 +1,163 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Iphepha langaphambili
+previous_label=Okwangaphambili
+next.title=Iphepha elilandelayo
+next_label=Okulandelayo
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Iphepha:
+page_of=kwali- {{pageCount}}
+
+zoom_out.title=Bhekelisela Kudana
+zoom_out_label=Bhekelisela Kudana
+zoom_in.title=Sondeza Kufuphi
+zoom_in_label=Sondeza Kufuphi
+zoom.title=Yandisa / Nciphisa
+presentation_mode.title=Tshintshela kwimo yonikezelo
+presentation_mode_label=Imo yonikezelo
+open_file.title=Vula Ifayile
+open_file_label=Vula
+print.title=Printa
+print_label=Printa
+download.title=Khuphela
+download_label=Khuphela
+bookmark.title=Imbonakalo ekhoyo (kopa okanye vula kwifestile entsha)
+bookmark_label=Imbonakalo ekhoyo
+
+# Secondary toolbar and context menu
+tools.title=Izixhobo zemiyalelo
+tools_label=Izixhobo zemiyalelo
+first_page.title=Yiya kwiphepha lokuqala
+first_page.label=Yiya kwiphepha lokuqala
+first_page_label=Yiya kwiphepha lokuqala
+last_page.title=Yiya kwiphepha lokugqibela
+last_page.label=Yiya kwiphepha lokugqibela
+last_page_label=Yiya kwiphepha lokugqibela
+page_rotate_cw.title=Jikelisa ngasekunene
+page_rotate_cw.label=Jikelisa ngasekunene
+page_rotate_cw_label=Jikelisa ngasekunene
+page_rotate_ccw.title=Jikelisa ngasekhohlo
+page_rotate_ccw.label=Jikelisa ngasekhohlo
+page_rotate_ccw_label=Jikelisa ngasekhohlo
+
+hand_tool_enable.title=Yenza isixhobo sesandla sisebenze
+hand_tool_enable_label=Yenza isixhobo sesandla sisebenze
+hand_tool_disable.title=Yenza isixhobo sesandla singasebenzi
+hand_tool_disable_label=Yenza isixhobo sesandla singasebenzi
+
+# Document properties dialog box
+document_properties.title=Iipropati zoxwebhu…
+document_properties_label=Iipropati zoxwebhu…
+document_properties_file_name=Igama lefayile:
+document_properties_file_size=Isayizi yefayile:
+document_properties_kb={{size_kb}} KB (iibhayiti{{size_b}})
+document_properties_mb={{size_mb}} MB (iibhayithi{{size_b}})
+document_properties_title=Umxholo:
+document_properties_author=Umbhali:
+document_properties_subject=Umbandela:
+document_properties_keywords=Amagama aphambili:
+document_properties_creation_date=Umhla wokwenziwa kwayo:
+document_properties_modification_date=Umhla wokulungiswa kwayo:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=Umntu oyenzileyo:
+document_properties_producer=Umvelisi we-PDF:
+document_properties_version=Uhlelo lwe-PDF:
+document_properties_page_count=Inani lamaphepha:
+document_properties_close=Vala
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=Togola ngebha eseCaleni
+toggle_sidebar_label=Togola ngebha eseCaleni
+outline.title=Bonisa isishwankathelo soxwebhu
+outline_label=Isishwankathelo soxwebhu
+attachments.title=Bonisa iziqhotyoshelwa
+attachments_label=Iziqhoboshelo
+thumbs.title=Bonisa ukrobiso kumfanekiso
+thumbs_label=Ukrobiso kumfanekiso
+findbar.title=Fumana kuXwebhu
+findbar_label=Fumana
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Iphepha {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Ukrobiso kumfanekiso wephepha {{page}}
+
+# Find panel button title and messages
+find_label=Fumanisa:
+find_previous.title=Fumanisa isenzeko sangaphambili sebinzana lamagama
+find_previous_label=Okwangaphambili
+find_next.title=Fumanisa isenzeko esilandelayo sebinzana lamagama
+find_next_label=Okulandelayo
+find_highlight=Qaqambisa konke
+find_match_case_label=Tshatisa ngobukhulu bukanobumba
+find_reached_top=Ufike ngaphezulu ephepheni, kusukwa ngezantsi
+find_reached_bottom=Ufike ekupheleni kwephepha, kusukwa ngaphezulu
+find_not_found=Ibinzana alifunyenwanga
+
+# Error panel labels
+error_more_info=Inkcazelo Engakumbi
+error_less_info=Inkcazelo Encinane
+error_close=Vala
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=I-PDF.js v{{uhlelo}} (yakha: {{yakha}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Umyalezo: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Imfumba: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Ifayile: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Umgca: {{line}}
+rendering_error=Imposiso yenzekile xa bekunikezelwa iphepha.
+
+# Predefined zoom values
+page_scale_width=Ububanzi bephepha
+page_scale_fit=Ukulinganiswa kwephepha
+page_scale_auto=Ukwandisa/Ukunciphisa Ngokwayo
+page_scale_actual=Ubungakanani bokwenene
+
+# Loading indicator messages
+loading_error_indicator=Imposiso
+loading_error=Imposiso yenzekile xa kulayishwa i-PDF.
+invalid_file_error=Ifayile ye-PDF engeyiyo okanye eyonakalisiweyo.
+missing_file_error=Ifayile ye-PDF edukileyo.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[{{type}} Ubhalo-nqaku]
+password_label=Faka ipasiwedi ukuze uvule le fayile yePDF.
+password_invalid=Ipasiwedi ayisebenzi. Nceda uzame kwakhona.
+password_ok=KULUNGILE
+password_cancel=Rhoxisa
+
+printing_not_supported=Isilumkiso: Ukuprinta akuxhaswa ngokupheleleyo yile bhrawuza.
+printing_not_ready=Isilumkiso: IPDF ayihlohlwanga ngokupheleleyo ukwenzela ukuprinta.
+web_fonts_disabled=Iifonti zewebhu ziqhwalelisiwe: ayikwazi ukusebenzisa iifonti ze-PDF ezincanyathelisiweyo.
+document_colors_disabled=Amaxwebhu ePDF akavumelekanga ukuba asebenzise imibala yawo: 'Ukuvumela amaphepha ukuba asebenzise eyawo imibala' kuvaliwe ukuba kungasebenzi kwibhrawuza.
diff --git a/static/pdf.js/locale/zh-CN/viewer.properties b/static/pdf.js/locale/zh-CN/viewer.properties
index bbc77c270..878c5f210 100644
--- a/static/pdf.js/locale/zh-CN/viewer.properties
+++ b/static/pdf.js/locale/zh-CN/viewer.properties
@@ -14,15 +14,15 @@
# Main toolbar buttons (tooltips and alt text for images)
previous.title=上一页
-previous_label=å‘上
+previous_label=上一页
next.title=下一页
-next_label=å‘下
+next_label=下一页
# LOCALIZATION NOTE (page_label, page_of):
# These strings are concatenated to form the "Page: X of Y" string.
# Do not translate "{{pageCount}}", it will be substituted with a number
# representing the total number of pages.
-page_label=页ç :
+page_label=页é¢ï¼š
page_of=/ {{pageCount}}
zoom_out.title=缩å°
@@ -30,8 +30,8 @@ zoom_out_label=缩å°
zoom_in.title=放大
zoom_in_label=放大
zoom.title=缩放
-presentation_mode.title=切æ¢è‡³å¹»ç¯æ¨¡å¼
-presentation_mode_label=å¹»ç¯æ¨¡å¼
+presentation_mode.title=切æ¢åˆ°æ¼”示模å¼
+presentation_mode_label=演示模å¼
open_file.title=打开文件
open_file_label=打开
print.title=打å°
@@ -47,9 +47,9 @@ tools_label=工具
first_page.title=转到第一页
first_page.label=转到第一页
first_page_label=转到第一页
-last_page.title=转到结尾页
-last_page.label=转到结尾页
-last_page_label=转到结尾页
+last_page.title=转到最åŽä¸€é¡µ
+last_page.label=转到最åŽä¸€é¡µ
+last_page_label=转到最åŽä¸€é¡µ
page_rotate_cw.title=顺时针旋转
page_rotate_cw.label=顺时针旋转
page_rotate_cw_label=顺时针旋转
@@ -57,10 +57,30 @@ page_rotate_ccw.title=逆时针旋转
page_rotate_ccw.label=逆时针旋转
page_rotate_ccw_label=逆时针旋转
-hand_tool_enable.title=å¯ç”¨æŽŒåž‹å·¥å…·
-hand_tool_enable_label=å¯ç”¨æŽŒåž‹å·¥å…·
-hand_tool_disable.title=ç¦ç”¨æŽŒåž‹å·¥å…·
-hand_tool_disable_label=ç¦ç”¨æŽŒåž‹å·¥å…·
+hand_tool_enable.title=å¯ç”¨æ‰‹å½¢å·¥å…·
+hand_tool_enable_label=å¯ç”¨æ‰‹å½¢å·¥å…·
+hand_tool_disable.title=ç¦ç”¨æ‰‹å½¢å·¥å…·
+hand_tool_disable_label=ç¦ç”¨æ‰‹å½¢å·¥å…·
+
+# Document properties dialog box
+document_properties.title=文档属性…
+document_properties_label=文档属性…
+document_properties_file_name=文件å:
+document_properties_file_size=文件大å°:
+document_properties_kb={{size_kb}} KB ({{size_b}} å—节)
+document_properties_mb={{size_mb}} MB ({{size_b}} å—节)
+document_properties_title=æ ‡é¢˜:
+document_properties_author=作者:
+document_properties_subject=主题:
+document_properties_keywords=关键è¯:
+document_properties_creation_date=创建日期:
+document_properties_modification_date=修改日期:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=创建者:
+document_properties_producer=PDF 制作者:
+document_properties_version=PDF 版本:
+document_properties_page_count=页数:
+document_properties_close=å…³é—
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
@@ -69,9 +89,11 @@ toggle_sidebar.title=切æ¢ä¾§æ
toggle_sidebar_label=切æ¢ä¾§æ
outline.title=显示文档大纲
outline_label=文档大纲
+attachments.title=显示附件
+attachments_label=附件
thumbs.title=显示缩略图
thumbs_label=缩略图
-findbar.title=在该文档内查找
+findbar.title=在文档ä¸æŸ¥æ‰¾
findbar_label=查找
# Thumbnails panel item (tooltip and alt text for images)
@@ -83,59 +105,59 @@ thumb_page_title=页ç {{page}}
thumb_page_canvas=é¡µé¢ {{page}} 的缩略图
# Find panel button title and messages
-find_label=查找:
-find_previous.title=查找该çŸè¯ä¸Šä¸€æ¬¡å‡ºçŽ°çš„ä½ç½®
-find_previous_label=上一个
-find_next.title=查找该çŸè¯ä¸‹ä¸€æ¬¡å‡ºçŽ°çš„ä½ç½®
-find_next_label=下一个
-find_highlight=全部高亮
+find_label=查找:
+find_previous.title=查找è¯è¯ä¸Šä¸€æ¬¡å‡ºçŽ°çš„ä½ç½®
+find_previous_label=上一页
+find_next.title=查找è¯è¯åŽä¸€æ¬¡å‡ºçŽ°çš„ä½ç½®
+find_next_label=下一页
+find_highlight=全部高亮显示
find_match_case_label=区分大å°å†™
-find_reached_top=已查找至文档的开始ä½ç½®ï¼Œå°†ä»Žæ–‡æ¡£æœ«å°¾ç»§ç»æŸ¥æ‰¾
-find_reached_bottom=已查找至文档的末尾ä½ç½®ï¼Œå°†ä»Žæ–‡æ¡£çš„开始ä½ç½®ç»§ç»æŸ¥æ‰¾
-find_not_found=找ä¸åˆ°
+find_reached_top=到达文档开头,从末尾继ç»
+find_reached_bottom=到达文档末尾,从开头继ç»
+find_not_found=è¯è¯æœªæ‰¾åˆ°
# Error panel labels
error_more_info=更多信æ¯
-error_less_info=简略信æ¯
+error_less_info=æ›´å°‘ä¿¡æ¯
error_close=å…³é—
# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
# replaced by the PDF.JS version and build ID.
-error_version_info=PDF.js v{{version}} (构建版本: {{build}})
+error_version_info=PDF.js v{{version}} (build: {{build}})
# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
# english string describing the error.
-error_message=错误信æ¯: {{message}}
+error_message=ä¿¡æ¯ï¼š{{message}}
# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
# trace.
-error_stack=å †æ ˆ: {{stack}}
+error_stack=å †æ ˆï¼š{{stack}}
# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
-error_file=文件: {{file}}
+error_file=文件:{{file}}
# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
-error_line=行数: {{line}}
-rendering_error=渲染页é¢æ—¶å‡ºé”™ã€‚
+error_line=è¡Œå·ï¼š{{line}}
+rendering_error=渲染页é¢æ—¶å‘生错误。
# Predefined zoom values
-page_scale_width=符åˆé¡µå®½
-page_scale_fit=符åˆé¡µé¢
+page_scale_width=适åˆé¡µå®½
+page_scale_fit=适åˆé¡µé¢
page_scale_auto=自动缩放
page_scale_actual=实际大å°
# Loading indicator messages
loading_error_indicator=错误
-loading_error=åŠ è½½ PDF 文件时出错。
-invalid_file_error=PDF æ–‡ä»¶æ— æ•ˆæˆ–å·²æŸå。
-missing_file_error=缺失 PDF 文件。
+loading_error=载入PDFæ—¶å‘生错误。
+invalid_file_error=æ— æ•ˆæˆ–æŸåçš„PDF文件。
+missing_file_error=缺少PDF文件。
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
# the PDF spec (32000-1:2008 Table 169 – Annotation types).
# Some common types are e.g.: "Check", "Text", "Comment", "Note"
text_annotation_type.alt=[{{type}} 注解]
-password_label=输入 PDF 文件的密ç 。
-password_invalid=密ç æ— æ•ˆï¼Œè¯·é‡æ–°è¾“入。
+password_label=输入密ç ä»¥æ‰“å¼€æ¤ PDF 文件。
+password_invalid=密ç æ— æ•ˆã€‚è¯·é‡è¯•ã€‚
password_ok=确定
password_cancel=å–消
-printing_not_supported=è¦å‘Šï¼šè¯¥æµè§ˆå™¨ä¸èƒ½å®Œå…¨æ”¯æŒæ‰“å°ã€‚
-printing_not_ready=è¦å‘Šï¼šæ¤ PDF 没有完全被载入以供打å°ã€‚
-web_fonts_disabled=Web 页é¢å—体已被ç¦ç”¨ï¼Œæ— 法使用嵌入到 PDF ä¸çš„å—体。
-document_colors_disabled=PDF 文件ä¸è¢«å…许使用自己的颜色:\‘å…许页é¢é€‰æ‹©è‡ªå·±çš„颜色’\没有在该æµè§ˆå™¨ä¸è¢«æ¿€æ´»ã€‚
+printing_not_supported=è¦å‘Šï¼šæ‰“å°åŠŸèƒ½ä¸å®Œå…¨æ”¯æŒæ¤æµè§ˆå™¨ã€‚
+printing_not_ready=è¦å‘Šï¼šè¯¥ PDF æœªå®Œå…¨åŠ è½½ä»¥ä¾›æ‰“å°ã€‚
+web_fonts_disabled=Web å—体已被ç¦ç”¨ï¼šæ— 法使用嵌入的PDFå—体。
+document_colors_disabled=ä¸å…许 PDF 文档使用自己的颜色:æµè§ˆå™¨ä¸â€œå…许页é¢é€‰æ‹©è‡ªå·±çš„颜色â€çš„选项已åœç”¨ã€‚
diff --git a/static/pdf.js/locale/zh-TW/viewer.properties b/static/pdf.js/locale/zh-TW/viewer.properties
index 345649547..80b88142d 100644
--- a/static/pdf.js/locale/zh-TW/viewer.properties
+++ b/static/pdf.js/locale/zh-TW/viewer.properties
@@ -62,6 +62,26 @@ hand_tool_enable_label=啟用掌型工具
hand_tool_disable.title=åœç”¨æŽŒåž‹å·¥å…·
hand_tool_disable_label=åœç”¨æŽŒåž‹å·¥å…·
+# Document properties dialog box
+document_properties.title=文件內容…
+document_properties_label=文件內容…
+document_properties_file_name=檔案å稱:
+document_properties_file_size=檔案大å°:
+document_properties_kb={{size_kb}} KB({{size_b}} ä½å…ƒçµ„)
+document_properties_mb={{size_kb}} MB({{size_b}} ä½å…ƒçµ„)
+document_properties_title=標題:
+document_properties_author=作者:
+document_properties_subject=主旨:
+document_properties_keywords=é—œéµå—:
+document_properties_creation_date=建立日期:
+document_properties_modification_date=修改日期:
+document_properties_date_string={{date}}, {{time}}
+document_properties_creator=建立者:
+document_properties_producer=PDF 產生器:
+document_properties_version=PDF 版本:
+document_properties_page_count=é 數:
+document_properties_close=關閉
+
# Tooltips and alt text for side panel toolbar buttons
# (the _label strings are alt text for the buttons, the .title strings are
# tooltips)
@@ -69,6 +89,8 @@ toggle_sidebar.title=切æ›å´é‚Šæ¬„
toggle_sidebar_label=切æ›å´é‚Šæ¬„
outline.title=顯示文件大綱
outline_label=文件大綱
+attachments.title=顯示附件
+attachments_label=附件
thumbs.title=顯示縮圖
thumbs_label=縮圖
findbar.title=在文件ä¸å°‹æ‰¾
@@ -124,6 +146,7 @@ loading_error_indicator=錯誤
loading_error=載入 PDF 時發生錯誤。
invalid_file_error=無效或毀æçš„ PDF 檔案。
missing_file_error=找ä¸åˆ° PDF 檔案。
+unexpected_response_error=伺æœå™¨å‚³å›žæœªé 期的回應。
# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
# "{{type}}" will be replaced with an annotation type from a list defined in
@@ -139,3 +162,4 @@ printing_not_supported=è¦å‘Š: æ¤ç€è¦½å™¨æœªå®Œæ•´æ”¯æ´åˆ—å°åŠŸèƒ½ã€‚
printing_not_ready=è¦å‘Š: æ¤ PDF 未完æˆä¸‹è¼‰ä»¥ä¾›åˆ—å°ã€‚
web_fonts_disabled=å·²åœç”¨ç¶²è·¯å—åž‹ (Web fonts): 無法使用 PDF 內嵌å—型。
document_colors_disabled=ç€è¦½å™¨çš„「優先使用網é 指定的色彩ã€æœªè¢«å‹¾é¸ï¼ŒPDF 文件無法使用自己的色彩。
+
diff --git a/static/pdf.js/locale/zu/viewer.properties b/static/pdf.js/locale/zu/viewer.properties
new file mode 100644
index 000000000..bd7a08f6d
--- /dev/null
+++ b/static/pdf.js/locale/zu/viewer.properties
@@ -0,0 +1,124 @@
+# Copyright 2012 Mozilla Foundation
+#
+# 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.
+
+# Main toolbar buttons (tooltips and alt text for images)
+previous.title=Ikhasi eledlule
+previous_label=Okudlule
+next.title=Ikhasi elilandelayo
+next_label=Okulandelayo
+
+# LOCALIZATION NOTE (page_label, page_of):
+# These strings are concatenated to form the "Page: X of Y" string.
+# Do not translate "{{pageCount}}", it will be substituted with a number
+# representing the total number of pages.
+page_label=Ikhasi:
+page_of=kwe-{{pageCount}}
+
+zoom_out.title=Hlehlisela emuva
+zoom_out_label=Hlehlisela emuva
+zoom_in.title=Sondeza eduze
+zoom_in_label=Sondeza eduze
+zoom.title=Lwiza
+print.title=Phrinta
+print_label=Phrinta
+presentation_mode.title=Guqulela kwindlela yesethulo
+presentation_mode_label=Indlelo yesethulo
+open_file.title=Vula ifayela
+open_file_label=Vula
+download.title=Landa
+download_label=Landa
+bookmark.title=Ukubuka kwamanje (kopisha noma vula kwifasitela elisha)
+bookmark_label=Ukubuka kwamanje
+
+# Tooltips and alt text for side panel toolbar buttons
+# (the _label strings are alt text for the buttons, the .title strings are
+# tooltips)
+toggle_sidebar.title=I-toggle yebha yaseceleni
+toggle_sidebar_label=i-toggle yebha yaseceleni
+outline.title=Bonisa umugqa waseceleni wedokhumenti
+outline_label=Umugqa waseceleni wedokhumenti
+thumbs.title=Bonisa izithombe ezincane
+thumbs_label=Izithonjana
+findbar.title=Thola kwidokhumenti
+findbar_label=Thola
+
+# Thumbnails panel item (tooltip and alt text for images)
+# LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page
+# number.
+thumb_page_title=Ikhasi {{page}}
+# LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page
+# number.
+thumb_page_canvas=Isithonjana sekhasi {{page}}
+
+# Context menu
+first_page.label=Yiya kwikhasi lokuqala
+last_page.label=Yiya kwikhasi lokugcina
+page_rotate_cw.label=Jikisela ngendlela yewashi
+page_rotate_ccw.label=Jikisela kwelokudla
+
+# Find panel button title and messages
+find_label=Thola
+find_previous.title=Thola indawo eyandulelayo okuvela kuyo lomshwana
+find_previous_label=Okudlulile
+find_next.title=Thola enye indawo okuvela kuyo lomshwana
+find_next_label=Okulandelayo
+find_highlight=Gqamisa konke
+find_match_case_label=Fanisa ikheyisi
+find_reached_top=Finyelele phezulu kwidokhumenti, qhubeka kusukaphansi
+find_reached_bottom=Ifinyelele ekupheleni kwedokhumenti, qhubeka kusukaphezulu
+find_not_found=Umshwana awutholakali
+
+# Error panel labels
+error_more_info=Ukwaziswa Okwengeziwe
+error_less_info=Ukwazi okuncane
+error_close=Vala
+# LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be
+# replaced by the PDF.JS version and build ID.
+error_version_info=PDF.js v{{version}} (build: {{build}})
+# LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an
+# english string describing the error.
+error_message=Umlayezo: {{message}}
+# LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack
+# trace.
+error_stack=Isitaki: {{stack}}
+# LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename
+error_file=Ifayela: {{file}}
+# LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number
+error_line=Umugqa: {{line}}
+rendering_error=Iphutha lenzekile uma kunikwa ikhasi.
+
+# Predefined zoom values
+page_scale_width=Ububanzi bekhasi
+page_scale_fit=Ukulingana kwekhasi
+page_scale_auto=Ukulwiza okuzenzekalelayo
+page_scale_actual=Usayizi Wangempela
+
+# Loading indicator messages
+loading_error_indicator=Iphutha
+loading_error=Kwenzeke iphutha uma kulayishwa i-PDF.
+invalid_file_error=Ifayela le-PDF elingavumelekile noma elonakele.
+missing_file_error=Ifayela le-PDF elilahlekile.
+
+# LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip.
+# "{{type}}" will be replaced with an annotation type from a list defined in
+# the PDF spec (32000-1:2008 Table 169 – Annotation types).
+# Some common types are e.g.: "Check", "Text", "Comment", "Note"
+text_annotation_type.alt=[Amazwibela e-{{type}}]
+request_password=I-PDF ivikeleke ngephasiwedi
+invalid_password=Iphasiwedi Engavumelekile.
+
+printing_not_supported=Isixwayiso: Ukuphrinta akuxhasiwe yilesisiphequluli ngokugcwele.
+printing_not_ready=Isixwayiso: I-PDF ayikalayishwa ngokuphelele yiPhrinta.
+web_fonts_disabled=Amafonti e-webhu akutshaziwe: ayikwazi ukusebenzisa amafonti abekiwe e-PDF.
+document_colors_disabled=Amadokhumenti we-PDF awavumelekile ukusebenzisa imibalo yayo: 'Vumela amakhasi ukukhetha imibala yayo' ayisebenzi kusiphequluli.
diff --git a/static/pdf.js/pdf.js b/static/pdf.js/pdf.js
index b23e8a334..e6d7aa46b 100644
--- a/static/pdf.js/pdf.js
+++ b/static/pdf.js/pdf.js
@@ -14,14 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/*jshint globalstrict: false */
+/* globals PDFJS */
// Initializing PDFJS global object (if still undefined)
if (typeof PDFJS === 'undefined') {
(typeof window !== 'undefined' ? window : this).PDFJS = {};
}
-PDFJS.version = '0.8.846';
-PDFJS.build = '05f937e';
+PDFJS.version = '1.0.908';
+PDFJS.build = '291671c';
(function pdfjsWrapper() {
// Use strict in our context only - users might not want it
@@ -50,7 +52,7 @@ PDFJS.build = '05f937e';
var globalScope = (typeof window === 'undefined') ? this : window;
-var isWorker = (typeof window == 'undefined');
+var isWorker = (typeof window === 'undefined');
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
@@ -67,6 +69,45 @@ var TextRenderingMode = {
ADD_TO_PATH_FLAG: 4
};
+var ImageKind = {
+ GRAYSCALE_1BPP: 1,
+ RGB_24BPP: 2,
+ RGBA_32BPP: 3
+};
+
+var AnnotationType = {
+ WIDGET: 1,
+ TEXT: 2,
+ LINK: 3
+};
+
+var StreamType = {
+ UNKNOWN: 0,
+ FLATE: 1,
+ LZW: 2,
+ DCT: 3,
+ JPX: 4,
+ JBIG: 5,
+ A85: 6,
+ AHX: 7,
+ CCF: 8,
+ RL: 9
+};
+
+var FontType = {
+ UNKNOWN: 0,
+ TYPE1: 1,
+ TYPE1C: 2,
+ CIDFONTTYPE0: 3,
+ CIDFONTTYPE0C: 4,
+ TRUETYPE: 5,
+ CIDFONTTYPE2: 6,
+ TYPE3: 7,
+ OPENTYPE: 8,
+ TYPE0: 9,
+ MMTYPE1: 10
+};
+
// The global PDFJS object exposes the API
// In production, it will be declared outside a global wrapper
// In development, it will be declared here
@@ -172,33 +213,26 @@ var OPS = PDFJS.OPS = {
paintImageMaskXObjectGroup: 84,
paintImageXObject: 85,
paintInlineImageXObject: 86,
- paintInlineImageXObjectGroup: 87
+ paintInlineImageXObjectGroup: 87,
+ paintImageXObjectRepeat: 88,
+ paintImageMaskXObjectRepeat: 89,
+ paintSolidColorImageMask: 90,
+ constructPath: 91
};
-// Use only for debugging purposes. This should not be used in any code that is
-// in mozilla master.
-var log = (function() {
- if ('console' in globalScope && 'log' in globalScope['console']) {
- return globalScope['console']['log'].bind(globalScope['console']);
- } else {
- return function nop() {
- };
- }
-})();
-
// A notice for devs. These are good for things that are helpful to devs, such
// as warning that Workers were disabled, which is important to devs but not
// end users.
function info(msg) {
if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
- log('Info: ' + msg);
+ console.log('Info: ' + msg);
}
}
// Non-fatal warnings.
function warn(msg) {
if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
- log('Warning: ' + msg);
+ console.log('Warning: ' + msg);
}
}
@@ -209,13 +243,13 @@ function error(msg) {
if (arguments.length > 1) {
var logArguments = ['Error:'];
logArguments.push.apply(logArguments, arguments);
- log.apply(null, logArguments);
+ console.log.apply(console, logArguments);
// Join the arguments into a single string for the lines below.
msg = [].join.call(arguments, ' ');
} else {
- log('Error: ' + msg);
+ console.log('Error: ' + msg);
}
- log(backtrace());
+ console.log(backtrace());
UnsupportedManager.notify(UNSUPPORTED_FEATURES.unknown);
throw new Error(msg);
}
@@ -229,8 +263,9 @@ function backtrace() {
}
function assert(cond, msg) {
- if (!cond)
+ if (!cond) {
error(msg);
+ }
}
var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
@@ -261,18 +296,25 @@ var UnsupportedManager = PDFJS.UnsupportedManager =
// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
// absolute URL, it will be returned as is.
function combineUrl(baseUrl, url) {
- if (!url)
+ if (!url) {
return baseUrl;
- if (url.indexOf(':') >= 0)
+ }
+ if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
return url;
- if (url.charAt(0) == '/') {
+ }
+ var i;
+ if (url.charAt(0) === '/') {
// absolute path
- var i = baseUrl.indexOf('://');
- i = baseUrl.indexOf('/', i + 3);
+ i = baseUrl.indexOf('://');
+ if (url.charAt(1) === '/') {
+ ++i;
+ } else {
+ i = baseUrl.indexOf('/', i + 3);
+ }
return baseUrl.substring(0, i) + url;
} else {
// relative path
- var pathLength = baseUrl.length, i;
+ var pathLength = baseUrl.length;
i = baseUrl.lastIndexOf('#');
pathLength = i >= 0 ? i : pathLength;
i = baseUrl.lastIndexOf('?', pathLength);
@@ -287,11 +329,13 @@ function isValidUrl(url, allowRelative) {
if (!url) {
return false;
}
- var colon = url.indexOf(':');
- if (colon < 0) {
+ // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
+ // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+ var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
+ if (!protocol) {
return allowRelative;
}
- var protocol = url.substr(0, colon);
+ protocol = protocol[0].toLowerCase();
switch (protocol) {
case 'http':
case 'https':
@@ -304,13 +348,6 @@ function isValidUrl(url, allowRelative) {
}
PDFJS.isValidUrl = isValidUrl;
-// In a well-formed PDF, |cond| holds. If it doesn't, subsequent
-// behavior is undefined.
-function assertWellFormed(cond, msg) {
- if (!cond)
- error(msg);
-}
-
function shadow(obj, prop, value) {
Object.defineProperty(obj, prop, { value: value,
enumerable: true,
@@ -336,6 +373,7 @@ var PasswordException = (function PasswordExceptionClosure() {
return PasswordException;
})();
+PDFJS.PasswordException = PasswordException;
var UnknownErrorException = (function UnknownErrorExceptionClosure() {
function UnknownErrorException(msg, details) {
@@ -349,6 +387,7 @@ var UnknownErrorException = (function UnknownErrorExceptionClosure() {
return UnknownErrorException;
})();
+PDFJS.UnknownErrorException = UnknownErrorException;
var InvalidPDFException = (function InvalidPDFExceptionClosure() {
function InvalidPDFException(msg) {
@@ -361,6 +400,7 @@ var InvalidPDFException = (function InvalidPDFExceptionClosure() {
return InvalidPDFException;
})();
+PDFJS.InvalidPDFException = InvalidPDFException;
var MissingPDFException = (function MissingPDFExceptionClosure() {
function MissingPDFException(msg) {
@@ -373,6 +413,22 @@ var MissingPDFException = (function MissingPDFExceptionClosure() {
return MissingPDFException;
})();
+PDFJS.MissingPDFException = MissingPDFException;
+
+var UnexpectedResponseException =
+ (function UnexpectedResponseExceptionClosure() {
+ function UnexpectedResponseException(msg, status) {
+ this.name = 'UnexpectedResponseException';
+ this.message = msg;
+ this.status = status;
+ }
+
+ UnexpectedResponseException.prototype = new Error();
+ UnexpectedResponseException.constructor = UnexpectedResponseException;
+
+ return UnexpectedResponseException;
+})();
+PDFJS.UnexpectedResponseException = UnexpectedResponseException;
var NotImplementedException = (function NotImplementedExceptionClosure() {
function NotImplementedException(msg) {
@@ -414,33 +470,142 @@ var XRefParseException = (function XRefParseExceptionClosure() {
function bytesToString(bytes) {
- var str = '';
var length = bytes.length;
- for (var n = 0; n < length; ++n)
- str += String.fromCharCode(bytes[n]);
- return str;
+ var MAX_ARGUMENT_COUNT = 8192;
+ if (length < MAX_ARGUMENT_COUNT) {
+ return String.fromCharCode.apply(null, bytes);
+ }
+ var strBuf = [];
+ for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
+ var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
+ var chunk = bytes.subarray(i, chunkEnd);
+ strBuf.push(String.fromCharCode.apply(null, chunk));
+ }
+ return strBuf.join('');
}
function stringToBytes(str) {
var length = str.length;
var bytes = new Uint8Array(length);
- for (var n = 0; n < length; ++n)
- bytes[n] = str.charCodeAt(n) & 0xFF;
+ for (var i = 0; i < length; ++i) {
+ bytes[i] = str.charCodeAt(i) & 0xFF;
+ }
return bytes;
}
+function string32(value) {
+ return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
+ (value >> 8) & 0xff, value & 0xff);
+}
+
+function log2(x) {
+ var n = 1, i = 0;
+ while (x > n) {
+ n <<= 1;
+ i++;
+ }
+ return i;
+}
+
+function readInt8(data, start) {
+ return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+ return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+ return ((data[offset] << 24) | (data[offset + 1] << 16) |
+ (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
+// Lazy test the endianness of the platform
+// NOTE: This will be 'true' for simulated TypedArrays
+function isLittleEndian() {
+ var buffer8 = new Uint8Array(2);
+ buffer8[0] = 1;
+ var buffer16 = new Uint16Array(buffer8.buffer);
+ return (buffer16[0] === 1);
+}
+
+Object.defineProperty(PDFJS, 'isLittleEndian', {
+ configurable: true,
+ get: function PDFJS_isLittleEndian() {
+ return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
+ }
+});
+
+ // Lazy test if the userAgant support CanvasTypedArrays
+function hasCanvasTypedArrays() {
+ var canvas = document.createElement('canvas');
+ canvas.width = canvas.height = 1;
+ var ctx = canvas.getContext('2d');
+ var imageData = ctx.createImageData(1, 1);
+ return (typeof imageData.data.buffer !== 'undefined');
+}
+
+Object.defineProperty(PDFJS, 'hasCanvasTypedArrays', {
+ configurable: true,
+ get: function PDFJS_hasCanvasTypedArrays() {
+ return shadow(PDFJS, 'hasCanvasTypedArrays', hasCanvasTypedArrays());
+ }
+});
+
+var Uint32ArrayView = (function Uint32ArrayViewClosure() {
+
+ function Uint32ArrayView(buffer, length) {
+ this.buffer = buffer;
+ this.byteLength = buffer.length;
+ this.length = length === undefined ? (this.byteLength >> 2) : length;
+ ensureUint32ArrayViewProps(this.length);
+ }
+ Uint32ArrayView.prototype = Object.create(null);
+
+ var uint32ArrayViewSetters = 0;
+ function createUint32ArrayProp(index) {
+ return {
+ get: function () {
+ var buffer = this.buffer, offset = index << 2;
+ return (buffer[offset] | (buffer[offset + 1] << 8) |
+ (buffer[offset + 2] << 16) | (buffer[offset + 3] << 24)) >>> 0;
+ },
+ set: function (value) {
+ var buffer = this.buffer, offset = index << 2;
+ buffer[offset] = value & 255;
+ buffer[offset + 1] = (value >> 8) & 255;
+ buffer[offset + 2] = (value >> 16) & 255;
+ buffer[offset + 3] = (value >>> 24) & 255;
+ }
+ };
+ }
+
+ function ensureUint32ArrayViewProps(length) {
+ while (uint32ArrayViewSetters < length) {
+ Object.defineProperty(Uint32ArrayView.prototype,
+ uint32ArrayViewSetters,
+ createUint32ArrayProp(uint32ArrayViewSetters));
+ uint32ArrayViewSetters++;
+ }
+ }
+
+ return Uint32ArrayView;
+})();
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
var Util = PDFJS.Util = (function UtilClosure() {
function Util() {}
- Util.makeCssRgb = function Util_makeCssRgb(rgb) {
- return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
- };
+ var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
- Util.makeCssCmyk = function Util_makeCssCmyk(cmyk) {
- var rgb = ColorSpace.singletons.cmyk.getRgb(cmyk, 0);
- return Util.makeCssRgb(rgb);
+ // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
+ // creating many intermediate strings.
+ Util.makeCssRgb = function Util_makeCssRgb(rgb) {
+ rgbBuf[1] = rgb[0];
+ rgbBuf[3] = rgb[1];
+ rgbBuf[5] = rgb[2];
+ return rgbBuf.join('');
};
// Concatenates two transformation matrices together and returns the result.
@@ -590,12 +755,11 @@ var Util = PDFJS.Util = (function UtilClosure() {
return num < 0 ? -1 : 1;
};
- // TODO(mack): Rename appendToArray
- Util.concatenateToArray = function concatenateToArray(arr1, arr2) {
+ Util.appendToArray = function Util_appendToArray(arr1, arr2) {
Array.prototype.push.apply(arr1, arr2);
};
- Util.prependToArray = function concatenateToArray(arr1, arr2) {
+ Util.prependToArray = function Util_prependToArray(arr1, arr2) {
Array.prototype.unshift.apply(arr1, arr2);
};
@@ -642,7 +806,22 @@ var Util = PDFJS.Util = (function UtilClosure() {
return Util;
})();
+/**
+ * PDF page viewport created based on scale, rotation and offset.
+ * @class
+ * @alias PDFJS.PageViewport
+ */
var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
+ /**
+ * @constructor
+ * @private
+ * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
+ * @param scale {number} scale of the viewport.
+ * @param rotation {number} rotations of the viewport in degrees.
+ * @param offsetX {number} offset X
+ * @param offsetY {number} offset Y
+ * @param dontFlip {boolean} if true, axis Y will not be flipped.
+ */
function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
this.viewBox = viewBox;
this.scale = scale;
@@ -706,7 +885,14 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
this.height = height;
this.fontScale = scale;
}
- PageViewport.prototype = {
+ PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+ /**
+ * Clones viewport with additional properties.
+ * @param args {Object} (optional) If specified, may contain the 'scale' or
+ * 'rotation' properties to override the corresponding properties in
+ * the cloned viewport.
+ * @returns {PDFJS.PageViewport} Cloned viewport.
+ */
clone: function PageViewPort_clone(args) {
args = args || {};
var scale = 'scale' in args ? args.scale : this.scale;
@@ -714,15 +900,41 @@ var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
return new PageViewport(this.viewBox.slice(), scale, rotation,
this.offsetX, this.offsetY, args.dontFlip);
},
+ /**
+ * Converts PDF point to the viewport coordinates. For examples, useful for
+ * converting PDF location into canvas pixel coordinates.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the viewport coordinate space.
+ * @see {@link convertToPdfPoint}
+ * @see {@link convertToViewportRectangle}
+ */
convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
return Util.applyTransform([x, y], this.transform);
},
+ /**
+ * Converts PDF rectangle to the viewport coordinates.
+ * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
+ * @returns {Array} Contains corresponding coordinates of the rectangle
+ * in the viewport coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToViewportRectangle:
function PageViewport_convertToViewportRectangle(rect) {
var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
var br = Util.applyTransform([rect[2], rect[3]], this.transform);
return [tl[0], tl[1], br[0], br[1]];
},
+ /**
+ * Converts viewport coordinates to the PDF location. For examples, useful
+ * for converting canvas pixel location into PDF one.
+ * @param x {number} X coordinate.
+ * @param y {number} Y coordinate.
+ * @returns {Object} Object that contains 'x' and 'y' properties of the
+ * point in the PDF coordinate space.
+ * @see {@link convertToViewportPoint}
+ */
convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
return Util.applyInverseTransform([x, y], this.transform);
}
@@ -743,19 +955,20 @@ var PDFStringTranslateTable = [
];
function stringToPDFString(str) {
- var i, n = str.length, str2 = '';
+ var i, n = str.length, strBuf = [];
if (str[0] === '\xFE' && str[1] === '\xFF') {
// UTF16BE BOM
- for (i = 2; i < n; i += 2)
- str2 += String.fromCharCode(
- (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1));
+ for (i = 2; i < n; i += 2) {
+ strBuf.push(String.fromCharCode(
+ (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
+ }
} else {
for (i = 0; i < n; ++i) {
var code = PDFStringTranslateTable[str.charCodeAt(i)];
- str2 += code ? String.fromCharCode(code) : str.charAt(i);
+ strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
}
}
- return str2;
+ return strBuf.join('');
}
function stringToUTF8String(str) {
@@ -770,19 +983,19 @@ function isEmptyObj(obj) {
}
function isBool(v) {
- return typeof v == 'boolean';
+ return typeof v === 'boolean';
}
function isInt(v) {
- return typeof v == 'number' && ((v | 0) == v);
+ return typeof v === 'number' && ((v | 0) === v);
}
function isNum(v) {
- return typeof v == 'number';
+ return typeof v === 'number';
}
function isString(v) {
- return typeof v == 'string';
+ return typeof v === 'string';
}
function isNull(v) {
@@ -794,7 +1007,7 @@ function isName(v) {
}
function isCmd(v, cmd) {
- return v instanceof Cmd && (!cmd || v.cmd == cmd);
+ return v instanceof Cmd && (cmd === undefined || v.cmd === cmd);
}
function isDict(v, type) {
@@ -805,7 +1018,7 @@ function isDict(v, type) {
return true;
}
var dictType = v.get('Type');
- return isName(dictType) && dictType.name == type;
+ return isName(dictType) && dictType.name === type;
}
function isArray(v) {
@@ -813,52 +1026,47 @@ function isArray(v) {
}
function isStream(v) {
- return typeof v == 'object' && v !== null && v !== undefined &&
- ('getBytes' in v);
+ return typeof v === 'object' && v !== null && v.getBytes !== undefined;
}
function isArrayBuffer(v) {
- return typeof v == 'object' && v !== null && v !== undefined &&
- ('byteLength' in v);
+ return typeof v === 'object' && v !== null && v.byteLength !== undefined;
}
function isRef(v) {
return v instanceof Ref;
}
-function isPDFFunction(v) {
- var fnDict;
- if (typeof v != 'object')
- return false;
- else if (isDict(v))
- fnDict = v;
- else if (isStream(v))
- fnDict = v.dict;
- else
- return false;
- return fnDict.has('FunctionType');
-}
+/**
+ * Promise Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
/**
- * Legacy support for PDFJS Promise implementation.
- * TODO remove eventually
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
*/
-var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
- return function LegacyPromise() {
- var resolve, reject;
- var promise = new Promise(function (resolve_, reject_) {
- resolve = resolve_;
- reject = reject_;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
- };
-})();
+function createPromiseCapability() {
+ var capability = {};
+ capability.promise = new Promise(function (resolve, reject) {
+ capability.resolve = resolve;
+ capability.reject = reject;
+ });
+ return capability;
+}
+
+PDFJS.createPromiseCapability = createPromiseCapability;
/**
* Polyfill for Promises:
- * The following promise implementation tries to generally implment the
+ * The following promise implementation tries to generally implement the
* Promise/A+ spec. Some notable differences from other promise libaries are:
* - There currently isn't a seperate deferred and promise object.
* - Unhandled rejections eventually show an error if they aren't handled.
@@ -893,8 +1101,20 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
};
}
if (typeof globalScope.Promise.resolve !== 'function') {
- globalScope.Promise.resolve = function (x) {
- return new globalScope.Promise(function (resolve) { resolve(x); });
+ globalScope.Promise.resolve = function (value) {
+ return new globalScope.Promise(function (resolve) { resolve(value); });
+ };
+ }
+ if (typeof globalScope.Promise.reject !== 'function') {
+ globalScope.Promise.reject = function (reason) {
+ return new globalScope.Promise(function (resolve, reject) {
+ reject(reason);
+ });
+ };
+ }
+ if (typeof globalScope.Promise.prototype.catch !== 'function') {
+ globalScope.Promise.prototype.catch = function (onReject) {
+ return globalScope.Promise.prototype.then(undefined, onReject);
};
}
return;
@@ -915,7 +1135,7 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
pendingRejectionCheck: false,
scheduleHandlers: function scheduleHandlers(promise) {
- if (promise._status == STATUS_PENDING) {
+ if (promise._status === STATUS_PENDING) {
return;
}
@@ -941,10 +1161,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
try {
if (nextStatus === STATUS_RESOLVED) {
- if (typeof(handler.onResolve) == 'function') {
+ if (typeof handler.onResolve === 'function') {
nextValue = handler.onResolve(nextValue);
}
- } else if (typeof(handler.onReject) === 'function') {
+ } else if (typeof handler.onReject === 'function') {
nextValue = handler.onReject(nextValue);
nextStatus = STATUS_RESOLVED;
@@ -1019,7 +1239,11 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
function Promise(resolver) {
this._status = STATUS_PENDING;
this._handlers = [];
- resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ try {
+ resolver.call(this, this._resolve.bind(this), this._reject.bind(this));
+ } catch (e) {
+ this._reject(e);
+ }
}
/**
* Builds a promise that is resolved when all the passed in promises are
@@ -1055,8 +1279,9 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
}
results[i] = value;
unresolved--;
- if (unresolved === 0)
+ if (unresolved === 0) {
resolveAll(results);
+ }
};
})(i);
if (Promise.isPromise(promise)) {
@@ -1070,18 +1295,28 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
/**
* Checks if the value is likely a promise (has a 'then' function).
- * @return {boolean} true if x is thenable
+ * @return {boolean} true if value is thenable
*/
Promise.isPromise = function Promise_isPromise(value) {
return value && typeof value.then === 'function';
};
+
/**
* Creates resolved promise
- * @param x resolve value
+ * @param value resolve value
* @returns {Promise}
*/
- Promise.resolve = function Promise_resolve(x) {
- return new Promise(function (resolve) { resolve(x); });
+ Promise.resolve = function Promise_resolve(value) {
+ return new Promise(function (resolve) { resolve(value); });
+ };
+
+ /**
+ * Creates rejected promise
+ * @param reason rejection value
+ * @returns {Promise}
+ */
+ Promise.reject = function Promise_reject(reason) {
+ return new Promise(function (resolve, reject) { reject(reason); });
};
Promise.prototype = {
@@ -1096,7 +1331,7 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
return;
}
- if (status == STATUS_RESOLVED &&
+ if (status === STATUS_RESOLVED &&
Promise.isPromise(value)) {
value.then(this._updateStatus.bind(this, STATUS_RESOLVED),
this._updateStatus.bind(this, STATUS_REJECTED));
@@ -1124,7 +1359,7 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
then: function Promise_then(onResolve, onReject) {
var nextPromise = new Promise(function (resolve, reject) {
- this.resolve = reject;
+ this.resolve = resolve;
this.reject = reject;
});
this._handlers.push({
@@ -1135,6 +1370,10 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
});
HandlerManager.scheduleHandlers(this);
return nextPromise;
+ },
+
+ catch: function Promise_catch(onReject) {
+ return this.then(undefined, onReject);
}
};
@@ -1143,8 +1382,9 @@ var LegacyPromise = PDFJS.LegacyPromise = (function LegacyPromiseClosure() {
var StatTimer = (function StatTimerClosure() {
function rpad(str, pad, length) {
- while (str.length < length)
+ while (str.length < length) {
str += pad;
+ }
return str;
}
function StatTimer() {
@@ -1154,17 +1394,21 @@ var StatTimer = (function StatTimerClosure() {
}
StatTimer.prototype = {
time: function StatTimer_time(name) {
- if (!this.enabled)
+ if (!this.enabled) {
return;
- if (name in this.started)
+ }
+ if (name in this.started) {
warn('Timer is already running for ' + name);
+ }
this.started[name] = Date.now();
},
timeEnd: function StatTimer_timeEnd(name) {
- if (!this.enabled)
+ if (!this.enabled) {
return;
- if (!(name in this.started))
+ }
+ if (!(name in this.started)) {
warn('Timer has not been started for ' + name);
+ }
this.times.push({
'name': name,
'start': this.started[name],
@@ -1174,16 +1418,18 @@ var StatTimer = (function StatTimerClosure() {
delete this.started[name];
},
toString: function StatTimer_toString() {
+ var i, ii;
var times = this.times;
var out = '';
// Find the longest name for padding purposes.
var longest = 0;
- for (var i = 0, ii = times.length; i < ii; ++i) {
+ for (i = 0, ii = times.length; i < ii; ++i) {
var name = times[i]['name'];
- if (name.length > longest)
+ if (name.length > longest) {
longest = name.length;
+ }
}
- for (var i = 0, ii = times.length; i < ii; ++i) {
+ for (i = 0, ii = times.length; i < ii; ++i) {
var span = times[i];
var duration = span.end - span.start;
out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
@@ -1195,8 +1441,9 @@ var StatTimer = (function StatTimerClosure() {
})();
PDFJS.createBlob = function createBlob(data, contentType) {
- if (typeof Blob !== 'undefined')
+ if (typeof Blob !== 'undefined') {
return new Blob([data], { type: contentType });
+ }
// Blob builder is deprecated in FF14 and removed in FF18.
var bb = new MozBlobBuilder();
bb.append(data);
@@ -1204,18 +1451,17 @@ PDFJS.createBlob = function createBlob(data, contentType) {
};
PDFJS.createObjectURL = (function createObjectURLClosure() {
- if (typeof URL !== 'undefined' && URL.createObjectURL) {
- return function createObjectURL(data, contentType) {
- var blob = PDFJS.createBlob(data, contentType);
- return URL.createObjectURL(blob);
- };
- }
-
// Blob/createObjectURL is not available, falling back to data schema.
var digits =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
return function createObjectURL(data, contentType) {
+ if (!PDFJS.disableCreateObjectURL &&
+ typeof URL !== 'undefined' && URL.createObjectURL) {
+ var blob = PDFJS.createBlob(data, contentType);
+ return URL.createObjectURL(blob);
+ }
+
var buffer = 'data:' + contentType + ';base64,';
for (var i = 0, ii = data.length; i < ii; i += 3) {
var b1 = data[i] & 0xFF;
@@ -1235,23 +1481,15 @@ function MessageHandler(name, comObj) {
this.comObj = comObj;
this.callbackIndex = 1;
this.postMessageTransfers = true;
- var callbacks = this.callbacks = {};
+ var callbacksCapabilities = this.callbacksCapabilities = {};
var ah = this.actionHandler = {};
ah['console_log'] = [function ahConsoleLog(data) {
- log.apply(null, data);
+ console.log.apply(console, data);
+ }];
+ ah['console_error'] = [function ahConsoleError(data) {
+ console.error.apply(console, data);
}];
- // If there's no console available, console_error in the
- // action handler will do nothing.
- if ('console' in globalScope) {
- ah['console_error'] = [function ahConsoleError(data) {
- globalScope['console'].error.apply(null, data);
- }];
- } else {
- ah['console_error'] = [function ahConsoleError(data) {
- log.apply(null, data);
- }];
- }
ah['_unsupported_feature'] = [function ah_unsupportedFeature(data) {
UnsupportedManager.notify(data);
}];
@@ -1260,35 +1498,40 @@ function MessageHandler(name, comObj) {
var data = event.data;
if (data.isReply) {
var callbackId = data.callbackId;
- if (data.callbackId in callbacks) {
- var callback = callbacks[callbackId];
- delete callbacks[callbackId];
- callback(data.data);
+ if (data.callbackId in callbacksCapabilities) {
+ var callback = callbacksCapabilities[callbackId];
+ delete callbacksCapabilities[callbackId];
+ if ('error' in data) {
+ callback.reject(data.error);
+ } else {
+ callback.resolve(data.data);
+ }
} else {
error('Cannot resolve callback ' + callbackId);
}
} else if (data.action in ah) {
var action = ah[data.action];
if (data.callbackId) {
- var deferred = {};
- var promise = new Promise(function (resolve, reject) {
- deferred.resolve = resolve;
- deferred.reject = reject;
- });
- deferred.promise = promise;
- promise.then(function(resolvedData) {
+ Promise.resolve().then(function () {
+ return action[0].call(action[1], data.data);
+ }).then(function (result) {
comObj.postMessage({
isReply: true,
callbackId: data.callbackId,
- data: resolvedData
+ data: result
+ });
+ }, function (reason) {
+ comObj.postMessage({
+ isReply: true,
+ callbackId: data.callbackId,
+ error: reason
});
});
- action[0].call(action[1], data.data, deferred);
} else {
action[0].call(action[1], data.data);
}
} else {
- error('Unkown action from worker: ' + data.action);
+ error('Unknown action from worker: ' + data.action);
}
};
}
@@ -1305,19 +1548,47 @@ MessageHandler.prototype = {
* Sends a message to the comObj to invoke the action with the supplied data.
* @param {String} actionName Action to call.
* @param {JSON} data JSON data to send.
- * @param {function} [callback] Optional callback that will handle a reply.
* @param {Array} [transfers] Optional list of transfers/ArrayBuffers
*/
- send: function messageHandlerSend(actionName, data, callback, transfers) {
+ send: function messageHandlerSend(actionName, data, transfers) {
var message = {
action: actionName,
data: data
};
- if (callback) {
- var callbackId = this.callbackIndex++;
- this.callbacks[callbackId] = callback;
- message.callbackId = callbackId;
+ this.postMessage(message, transfers);
+ },
+ /**
+ * Sends a message to the comObj to invoke the action with the supplied data.
+ * Expects that other side will callback with the response.
+ * @param {String} actionName Action to call.
+ * @param {JSON} data JSON data to send.
+ * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
+ * @returns {Promise} Promise to be resolved with response data.
+ */
+ sendWithPromise:
+ function messageHandlerSendWithPromise(actionName, data, transfers) {
+ var callbackId = this.callbackIndex++;
+ var message = {
+ action: actionName,
+ data: data,
+ callbackId: callbackId
+ };
+ var capability = createPromiseCapability();
+ this.callbacksCapabilities[callbackId] = capability;
+ try {
+ this.postMessage(message, transfers);
+ } catch (e) {
+ capability.reject(e);
}
+ return capability.promise;
+ },
+ /**
+ * Sends raw message to the comObj.
+ * @private
+ * @param message {Object} Raw message.
+ * @param transfers List of transfers/ArrayBuffers, or undefined.
+ */
+ postMessage: function (message, transfers) {
if (transfers && this.postMessageTransfers) {
this.comObj.postMessage(message, transfers);
} else {
@@ -1331,2904 +1602,128 @@ function loadJpegStream(id, imageUrl, objs) {
img.onload = (function loadJpegStream_onloadClosure() {
objs.resolve(id, img);
});
+ img.onerror = (function loadJpegStream_onerrorClosure() {
+ objs.resolve(id, null);
+ warn('Error during JPEG image loading');
+ });
img.src = imageUrl;
}
-var ColorSpace = (function ColorSpaceClosure() {
- // Constructor should define this.numComps, this.defaultColor, this.name
- function ColorSpace() {
- error('should not call ColorSpace constructor');
- }
-
- ColorSpace.prototype = {
- /**
- * Converts the color value to the RGB color. The color components are
- * located in the src array starting from the srcOffset. Returns the array
- * of the rgb components, each value ranging from [0,255].
- */
- getRgb: function ColorSpace_getRgb(src, srcOffset) {
- error('Should not call ColorSpace.getRgb');
- },
- /**
- * Converts the color value to the RGB color, similar to the getRgb method.
- * The result placed into the dest array starting from the destOffset.
- */
- getRgbItem: function ColorSpace_getRgb(src, srcOffset, dest, destOffset) {
- error('Should not call ColorSpace.getRgbItem');
- },
- /**
- * Converts the specified number of the color values to the RGB colors.
- * The colors are located in the src array starting from the srcOffset.
- * The result is placed into the dest array starting from the destOffset.
- * The src array items shall be in [0,2^bits) range, the dest array items
- * will be in [0,255] range.
- */
- getRgbBuffer: function ColorSpace_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- error('Should not call ColorSpace.getRgbBuffer');
- },
- /**
- * Determines amount of the bytes is required to store the reslut of the
- * conversion that done by the getRgbBuffer method.
- */
- getOutputLength: function ColorSpace_getOutputLength(inputLength) {
- error('Should not call ColorSpace.getOutputLength');
- },
- /**
- * Returns true if source data will be equal the result/output data.
- */
- isPassthrough: function ColorSpace_isPassthrough(bits) {
- return false;
- },
- /**
- * Creates the output buffer and converts the specified number of the color
- * values to the RGB colors, similar to the getRgbBuffer.
- */
- createRgbBuffer: function ColorSpace_createRgbBuffer(src, srcOffset,
- count, bits) {
- if (this.isPassthrough(bits)) {
- return src.subarray(srcOffset);
- }
- var dest = new Uint8Array(count * 3);
- var numComponentColors = 1 << bits;
- // Optimization: create a color map when there is just one component and
- // we are converting more colors than the size of the color map. We
- // don't build the map if the colorspace is gray or rgb since those
- // methods are faster than building a map. This mainly offers big speed
- // ups for indexed and alternate colorspaces.
- if (this.numComps === 1 && count > numComponentColors &&
- this.name !== 'DeviceGray' && this.name !== 'DeviceRGB') {
- // TODO it may be worth while to cache the color map. While running
- // testing I never hit a cache so I will leave that out for now (perhaps
- // we are reparsing colorspaces too much?).
- var allColors = bits <= 8 ? new Uint8Array(numComponentColors) :
- new Uint16Array(numComponentColors);
- for (var i = 0; i < numComponentColors; i++) {
- allColors[i] = i;
- }
- var colorMap = new Uint8Array(numComponentColors * 3);
- this.getRgbBuffer(allColors, 0, numComponentColors, colorMap, 0, bits);
-
- var destOffset = 0;
- for (var i = 0; i < count; ++i) {
- var key = src[srcOffset++] * 3;
- dest[destOffset++] = colorMap[key];
- dest[destOffset++] = colorMap[key + 1];
- dest[destOffset++] = colorMap[key + 2];
- }
- return dest;
- }
- this.getRgbBuffer(src, srcOffset, count, dest, 0, bits);
- return dest;
- },
- /**
- * True if the colorspace has components in the default range of [0, 1].
- * This should be true for all colorspaces except for lab color spaces
- * which are [0,100], [-128, 127], [-128, 127].
- */
- usesZeroToOneRange: true
- };
-
- ColorSpace.parse = function ColorSpace_parse(cs, xref, res) {
- var IR = ColorSpace.parseToIR(cs, xref, res);
- if (IR instanceof AlternateCS)
- return IR;
-
- return ColorSpace.fromIR(IR);
- };
-
- ColorSpace.fromIR = function ColorSpace_fromIR(IR) {
- var name = isArray(IR) ? IR[0] : IR;
-
- switch (name) {
- case 'DeviceGrayCS':
- return this.singletons.gray;
- case 'DeviceRgbCS':
- return this.singletons.rgb;
- case 'DeviceCmykCS':
- return this.singletons.cmyk;
- case 'CalGrayCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var gamma = IR[1].Gamma;
- return new CalGrayCS(whitePoint, blackPoint, gamma);
- case 'PatternCS':
- var basePatternCS = IR[1];
- if (basePatternCS)
- basePatternCS = ColorSpace.fromIR(basePatternCS);
- return new PatternCS(basePatternCS);
- case 'IndexedCS':
- var baseIndexedCS = IR[1];
- var hiVal = IR[2];
- var lookup = IR[3];
- return new IndexedCS(ColorSpace.fromIR(baseIndexedCS), hiVal, lookup);
- case 'AlternateCS':
- var numComps = IR[1];
- var alt = IR[2];
- var tintFnIR = IR[3];
-
- return new AlternateCS(numComps, ColorSpace.fromIR(alt),
- PDFFunction.fromIR(tintFnIR));
- case 'LabCS':
- var whitePoint = IR[1].WhitePoint;
- var blackPoint = IR[1].BlackPoint;
- var range = IR[1].Range;
- return new LabCS(whitePoint, blackPoint, range);
- default:
- error('Unkown name ' + name);
- }
- return null;
- };
-
- ColorSpace.parseToIR = function ColorSpace_parseToIR(cs, xref, res) {
- if (isName(cs)) {
- var colorSpaces = res.get('ColorSpace');
- if (isDict(colorSpaces)) {
- var refcs = colorSpaces.get(cs.name);
- if (refcs)
- cs = refcs;
- }
- }
-
- cs = xref.fetchIfRef(cs);
- var mode;
-
- if (isName(cs)) {
- mode = cs.name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'Pattern':
- return ['PatternCS', null];
- default:
- error('unrecognized colorspace ' + mode);
- }
- } else if (isArray(cs)) {
- mode = cs[0].name;
- this.mode = mode;
-
- switch (mode) {
- case 'DeviceGray':
- case 'G':
- return 'DeviceGrayCS';
- case 'DeviceRGB':
- case 'RGB':
- return 'DeviceRgbCS';
- case 'DeviceCMYK':
- case 'CMYK':
- return 'DeviceCmykCS';
- case 'CalGray':
- var params = cs[1].getAll();
- return ['CalGrayCS', params];
- case 'CalRGB':
- return 'DeviceRgbCS';
- case 'ICCBased':
- var stream = xref.fetchIfRef(cs[1]);
- var dict = stream.dict;
- var numComps = dict.get('N');
- if (numComps == 1)
- return 'DeviceGrayCS';
- if (numComps == 3)
- return 'DeviceRgbCS';
- if (numComps == 4)
- return 'DeviceCmykCS';
- break;
- case 'Pattern':
- var basePatternCS = cs[1];
- if (basePatternCS)
- basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
- return ['PatternCS', basePatternCS];
- case 'Indexed':
- case 'I':
- var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
- var hiVal = cs[2] + 1;
- var lookup = xref.fetchIfRef(cs[3]);
- if (isStream(lookup)) {
- lookup = lookup.getBytes();
- }
- return ['IndexedCS', baseIndexedCS, hiVal, lookup];
- case 'Separation':
- case 'DeviceN':
- var name = cs[1];
- var numComps = 1;
- if (isName(name))
- numComps = 1;
- else if (isArray(name))
- numComps = name.length;
- var alt = ColorSpace.parseToIR(cs[2], xref, res);
- var tintFnIR = PDFFunction.getIR(xref, xref.fetchIfRef(cs[3]));
- return ['AlternateCS', numComps, alt, tintFnIR];
- case 'Lab':
- var params = cs[1].getAll();
- return ['LabCS', params];
- default:
- error('unimplemented color space object "' + mode + '"');
- }
- } else {
- error('unrecognized color space object: "' + cs + '"');
- }
- return null;
- };
- /**
- * Checks if a decode map matches the default decode map for a color space.
- * This handles the general decode maps where there are two values per
- * component. e.g. [0, 1, 0, 1, 0, 1] for a RGB color.
- * This does not handle Lab, Indexed, or Pattern decode maps since they are
- * slightly different.
- * @param {Array} decode Decode map (usually from an image).
- * @param {Number} n Number of components the color space has.
- */
- ColorSpace.isDefaultDecode = function ColorSpace_isDefaultDecode(decode, n) {
- if (!decode)
- return true;
-
- if (n * 2 !== decode.length) {
- warn('The decode map is not the correct length');
- return true;
- }
- for (var i = 0, ii = decode.length; i < ii; i += 2) {
- if (decode[i] !== 0 || decode[i + 1] != 1)
- return false;
- }
- return true;
- };
-
- ColorSpace.singletons = {
- get gray() {
- return shadow(this, 'gray', new DeviceGrayCS());
- },
- get rgb() {
- return shadow(this, 'rgb', new DeviceRgbCS());
- },
- get cmyk() {
- return shadow(this, 'cmyk', new DeviceCmykCS());
- }
- };
-
- return ColorSpace;
-})();
-
-/**
- * Alternate color space handles both Separation and DeviceN color spaces. A
- * Separation color space is actually just a DeviceN with one color component.
- * Both color spaces use a tinting function to convert colors to a base color
- * space.
- */
-var AlternateCS = (function AlternateCSClosure() {
- function AlternateCS(numComps, base, tintFn) {
- this.name = 'Alternate';
- this.numComps = numComps;
- this.defaultColor = new Float32Array(numComps);
- for (var i = 0; i < numComps; ++i) {
- this.defaultColor[i] = 1;
- }
- this.base = base;
- this.tintFn = tintFn;
- }
-
- AlternateCS.prototype = {
- getRgb: function AlternateCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function AlternateCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var baseNumComps = this.base.numComps;
- var input = 'subarray' in src ?
- src.subarray(srcOffset, srcOffset + this.numComps) :
- Array.prototype.slice.call(src, srcOffset, srcOffset + this.numComps);
- var tinted = this.tintFn(input);
- this.base.getRgbItem(tinted, 0, dest, destOffset);
- },
- getRgbBuffer: function AlternateCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var tintFn = this.tintFn;
- var base = this.base;
- var scale = 1 / ((1 << bits) - 1);
- var baseNumComps = base.numComps;
- var usesZeroToOneRange = base.usesZeroToOneRange;
- var isPassthrough = base.isPassthrough(8) || !usesZeroToOneRange;
- var pos = isPassthrough ? destOffset : 0;
- var baseBuf = isPassthrough ? dest : new Uint8Array(baseNumComps * count);
- var numComps = this.numComps;
-
- var scaled = new Float32Array(numComps);
- for (var i = 0; i < count; i++) {
- for (var j = 0; j < numComps; j++) {
- scaled[j] = src[srcOffset++] * scale;
- }
- var tinted = tintFn(scaled);
- if (usesZeroToOneRange) {
- for (var j = 0; j < baseNumComps; j++) {
- baseBuf[pos++] = tinted[j] * 255;
- }
- } else {
- base.getRgbItem(tinted, 0, baseBuf, pos);
- pos += baseNumComps;
- }
- }
- if (!isPassthrough) {
- base.getRgbBuffer(baseBuf, 0, count, dest, destOffset, 8);
- }
- },
- getOutputLength: function AlternateCS_getOutputLength(inputLength) {
- return this.base.getOutputLength(inputLength *
- this.base.numComps / this.numComps);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function AlternateCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return AlternateCS;
-})();
-
-var PatternCS = (function PatternCSClosure() {
- function PatternCS(baseCS) {
- this.name = 'Pattern';
- this.base = baseCS;
- }
- PatternCS.prototype = {};
-
- return PatternCS;
-})();
-
-var IndexedCS = (function IndexedCSClosure() {
- function IndexedCS(base, highVal, lookup) {
- this.name = 'Indexed';
- this.numComps = 1;
- this.defaultColor = new Uint8Array([0]);
- this.base = base;
- this.highVal = highVal;
-
- var baseNumComps = base.numComps;
- var length = baseNumComps * highVal;
- var lookupArray;
-
- if (isStream(lookup)) {
- lookupArray = new Uint8Array(length);
- var bytes = lookup.getBytes(length);
- lookupArray.set(bytes);
- } else if (isString(lookup)) {
- lookupArray = new Uint8Array(length);
- for (var i = 0; i < length; ++i)
- lookupArray[i] = lookup.charCodeAt(i);
- } else if (lookup instanceof Uint8Array || lookup instanceof Array) {
- lookupArray = lookup;
- } else {
- error('Unrecognized lookup table: ' + lookup);
- }
- this.lookup = lookupArray;
- }
-
- IndexedCS.prototype = {
- getRgb: function IndexedCS_getRgb(src, srcOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- return this.base.getRgb(this.lookup, start);
- },
- getRgbItem: function IndexedCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var numComps = this.base.numComps;
- var start = src[srcOffset] * numComps;
- this.base.getRgbItem(this.lookup, start, dest, destOffset);
- },
- getRgbBuffer: function IndexedCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset) {
- var base = this.base;
- var numComps = base.numComps;
- var outputDelta = base.getOutputLength(numComps);
- var lookup = this.lookup;
-
- for (var i = 0; i < count; ++i) {
- var lookupPos = src[srcOffset++] * numComps;
- base.getRgbBuffer(lookup, lookupPos, 1, dest, destOffset, 8);
- destOffset += outputDelta;
- }
- },
- getOutputLength: function IndexedCS_getOutputLength(inputLength) {
- return this.base.getOutputLength(inputLength * this.base.numComps);
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function IndexedCS_isDefaultDecode(decodeMap) {
- // indexed color maps shouldn't be changed
- return true;
- },
- usesZeroToOneRange: true
- };
- return IndexedCS;
-})();
-
-var DeviceGrayCS = (function DeviceGrayCSClosure() {
- function DeviceGrayCS() {
- this.name = 'DeviceGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
- }
-
- DeviceGrayCS.prototype = {
- getRgb: function DeviceGrayCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function DeviceGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var c = (src[srcOffset] * 255) | 0;
- c = c < 0 ? 0 : c > 255 ? 255 : c;
- dest[destOffset] = dest[destOffset + 1] = dest[destOffset + 2] = c;
- },
- getRgbBuffer: function DeviceGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < count; ++i) {
- var c = (scale * src[j++]) | 0;
- dest[q++] = c;
- dest[q++] = c;
- dest[q++] = c;
- }
- },
- getOutputLength: function DeviceGrayCS_getOutputLength(inputLength) {
- return inputLength * 3;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function DeviceGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceGrayCS;
-})();
-
-var DeviceRgbCS = (function DeviceRgbCSClosure() {
- function DeviceRgbCS() {
- this.name = 'DeviceRGB';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
- }
- DeviceRgbCS.prototype = {
- getRgb: function DeviceRgbCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function DeviceRgbCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- var r = (src[srcOffset] * 255) | 0;
- var g = (src[srcOffset + 1] * 255) | 0;
- var b = (src[srcOffset + 2] * 255) | 0;
- dest[destOffset] = r < 0 ? 0 : r > 255 ? 255 : r;
- dest[destOffset + 1] = g < 0 ? 0 : g > 255 ? 255 : g;
- dest[destOffset + 2] = b < 0 ? 0 : b > 255 ? 255 : b;
- },
- getRgbBuffer: function DeviceRgbCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var length = count * 3;
- if (bits == 8) {
- dest.set(src.subarray(srcOffset, srcOffset + length), destOffset);
- return;
- }
- var scale = 255 / ((1 << bits) - 1);
- var j = srcOffset, q = destOffset;
- for (var i = 0; i < length; ++i) {
- dest[q++] = (scale * src[j++]) | 0;
- }
- },
- getOutputLength: function DeviceRgbCS_getOutputLength(inputLength) {
- return inputLength;
- },
- isPassthrough: function DeviceRgbCS_isPassthrough(bits) {
- return bits == 8;
- },
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function DeviceRgbCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return DeviceRgbCS;
-})();
-
-var DeviceCmykCS = (function DeviceCmykCSClosure() {
- // The coefficients below was found using numerical analysis: the method of
- // steepest descent for the sum((f_i - color_value_i)^2) for r/g/b colors,
- // where color_value is the tabular value from the table of sampled RGB colors
- // from CMYK US Web Coated (SWOP) colorspace, and f_i is the corresponding
- // CMYK color conversion using the estimation below:
- // f(A, B,.. N) = Acc+Bcm+Ccy+Dck+c+Fmm+Gmy+Hmk+Im+Jyy+Kyk+Ly+Mkk+Nk+255
- function convertToRgb(src, srcOffset, srcScale, dest, destOffset) {
- var c = src[srcOffset + 0] * srcScale;
- var m = src[srcOffset + 1] * srcScale;
- var y = src[srcOffset + 2] * srcScale;
- var k = src[srcOffset + 3] * srcScale;
-
- var r =
- c * (-4.387332384609988 * c + 54.48615194189176 * m +
- 18.82290502165302 * y + 212.25662451639585 * k +
- -285.2331026137004) +
- m * (1.7149763477362134 * m - 5.6096736904047315 * y +
- -17.873870861415444 * k - 5.497006427196366) +
- y * (-2.5217340131683033 * y - 21.248923337353073 * k +
- 17.5119270841813) +
- k * (-21.86122147463605 * k - 189.48180835922747) + 255;
- var g =
- c * (8.841041422036149 * c + 60.118027045597366 * m +
- 6.871425592049007 * y + 31.159100130055922 * k +
- -79.2970844816548) +
- m * (-15.310361306967817 * m + 17.575251261109482 * y +
- 131.35250912493976 * k - 190.9453302588951) +
- y * (4.444339102852739 * y + 9.8632861493405 * k - 24.86741582555878) +
- k * (-20.737325471181034 * k - 187.80453709719578) + 255;
- var b =
- c * (0.8842522430003296 * c + 8.078677503112928 * m +
- 30.89978309703729 * y - 0.23883238689178934 * k +
- -14.183576799673286) +
- m * (10.49593273432072 * m + 63.02378494754052 * y +
- 50.606957656360734 * k - 112.23884253719248) +
- y * (0.03296041114873217 * y + 115.60384449646641 * k +
- -193.58209356861505) +
- k * (-22.33816807309886 * k - 180.12613974708367) + 255;
-
- dest[destOffset] = r > 255 ? 255 : r < 0 ? 0 : r;
- dest[destOffset + 1] = g > 255 ? 255 : g < 0 ? 0 : g;
- dest[destOffset + 2] = b > 255 ? 255 : b < 0 ? 0 : b;
- }
-
- function DeviceCmykCS() {
- this.name = 'DeviceCMYK';
- this.numComps = 4;
- this.defaultColor = new Float32Array([0, 0, 0, 1]);
- }
- DeviceCmykCS.prototype = {
- getRgb: function DeviceCmykCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- convertToRgb(src, srcOffset, 1, rgb, 0);
- return rgb;
- },
- getRgbItem: function DeviceCmykCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(src, srcOffset, 1, dest, destOffset);
- },
- getRgbBuffer: function DeviceCmykCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var scale = 1 / ((1 << bits) - 1);
- for (var i = 0; i < count; i++) {
- convertToRgb(src, srcOffset, scale, dest, destOffset);
- srcOffset += 4;
- destOffset += 3;
- }
- },
- getOutputLength: function DeviceCmykCS_getOutputLength(inputLength) {
- return (inputLength >> 2) * 3;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function DeviceCmykCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
-
- return DeviceCmykCS;
-})();
-
-//
-// CalGrayCS: Based on "PDF Reference, Sixth Ed", p.245
-//
-var CalGrayCS = (function CalGrayCSClosure() {
- function CalGrayCS(whitePoint, blackPoint, gamma) {
- this.name = 'CalGray';
- this.numComps = 1;
- this.defaultColor = new Float32Array([0]);
-
- if (!whitePoint) {
- error('WhitePoint missing - required for color space CalGray');
- }
- blackPoint = blackPoint || [0, 0, 0];
- gamma = gamma || 1;
-
- // Translate arguments to spec variables.
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
-
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- this.G = gamma;
-
- // Validate variables as per spec.
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1) {
- error('Invalid WhitePoint components for ' + this.name +
- ', no fallback available');
- }
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint for ' + this.name + ', falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.XB !== 0 || this.YB !== 0 || this.ZB !== 0) {
- warn(this.name + ', BlackPoint: XB: ' + this.XB + ', YB: ' + this.YB +
- ', ZB: ' + this.ZB + ', only default values are supported.');
- }
-
- if (this.G < 1) {
- info('Invalid Gamma: ' + this.G + ' for ' + this.name +
- ', falling back to default');
- this.G = 1;
- }
- }
-
- function convertToRgb(cs, src, srcOffset, dest, destOffset, scale) {
- // A represents a gray component of a calibrated gray space.
- // A <---> AG in the spec
- var A = src[srcOffset] * scale;
- var AG = Math.pow(A, cs.G);
-
- // Computes intermediate variables M, L, N as per spec.
- // Except if other than default BlackPoint values are used.
- var M = cs.XW * AG;
- var L = cs.YW * AG;
- var N = cs.ZW * AG;
-
- // Decode XYZ, as per spec.
- var X = M;
- var Y = L;
- var Z = N;
-
- // http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html, Ch 4.
- // This yields values in range [0, 100].
- var Lstar = Math.max(116 * Math.pow(Y, 1 / 3) - 16, 0);
-
- // Convert values to rgb range [0, 255].
- dest[destOffset] = Lstar * 255 / 100;
- dest[destOffset + 1] = Lstar * 255 / 100;
- dest[destOffset + 2] = Lstar * 255 / 100;
- }
-
- CalGrayCS.prototype = {
- getRgb: function CalGrayCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- this.getRgbItem(src, srcOffset, rgb, 0);
- return rgb;
- },
- getRgbItem: function CalGrayCS_getRgbItem(src, srcOffset,
- dest, destOffset) {
- convertToRgb(this, src, srcOffset, dest, destOffset, 1);
- },
- getRgbBuffer: function CalGrayCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var scale = 1 / ((1 << bits) - 1);
-
- for (var i = 0; i < count; ++i) {
- convertToRgb(this, src, srcOffset, dest, destOffset, scale);
- srcOffset += 1;
- destOffset += 3;
- }
- },
- getOutputLength: function CalGrayCS_getOutputLength(inputLength) {
- return inputLength * 3;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- createRgbBuffer: ColorSpace.prototype.createRgbBuffer,
- isDefaultDecode: function CalGrayCS_isDefaultDecode(decodeMap) {
- return ColorSpace.isDefaultDecode(decodeMap, this.numComps);
- },
- usesZeroToOneRange: true
- };
- return CalGrayCS;
-})();
-
-//
-// LabCS: Based on "PDF Reference, Sixth Ed", p.250
-//
-var LabCS = (function LabCSClosure() {
- function LabCS(whitePoint, blackPoint, range) {
- this.name = 'Lab';
- this.numComps = 3;
- this.defaultColor = new Float32Array([0, 0, 0]);
-
- if (!whitePoint)
- error('WhitePoint missing - required for color space Lab');
- blackPoint = blackPoint || [0, 0, 0];
- range = range || [-100, 100, -100, 100];
-
- // Translate args to spec variables
- this.XW = whitePoint[0];
- this.YW = whitePoint[1];
- this.ZW = whitePoint[2];
- this.amin = range[0];
- this.amax = range[1];
- this.bmin = range[2];
- this.bmax = range[3];
-
- // These are here just for completeness - the spec doesn't offer any
- // formulas that use BlackPoint in Lab
- this.XB = blackPoint[0];
- this.YB = blackPoint[1];
- this.ZB = blackPoint[2];
-
- // Validate vars as per spec
- if (this.XW < 0 || this.ZW < 0 || this.YW !== 1)
- error('Invalid WhitePoint components, no fallback available');
-
- if (this.XB < 0 || this.YB < 0 || this.ZB < 0) {
- info('Invalid BlackPoint, falling back to default');
- this.XB = this.YB = this.ZB = 0;
- }
-
- if (this.amin > this.amax || this.bmin > this.bmax) {
- info('Invalid Range, falling back to defaults');
- this.amin = -100;
- this.amax = 100;
- this.bmin = -100;
- this.bmax = 100;
- }
- }
-
- // Function g(x) from spec
- function fn_g(x) {
- if (x >= 6 / 29)
- return x * x * x;
- else
- return (108 / 841) * (x - 4 / 29);
- }
-
- function decode(value, high1, low2, high2) {
- return low2 + (value) * (high2 - low2) / (high1);
- }
-
- // If decoding is needed maxVal should be 2^bits per component - 1.
- function convertToRgb(cs, src, srcOffset, maxVal, dest, destOffset) {
- // XXX: Lab input is in the range of [0, 100], [amin, amax], [bmin, bmax]
- // not the usual [0, 1]. If a command like setFillColor is used the src
- // values will already be within the correct range. However, if we are
- // converting an image we have to map the values to the correct range given
- // above.
- // Ls,as,bs <---> L*,a*,b* in the spec
- var Ls = src[srcOffset];
- var as = src[srcOffset + 1];
- var bs = src[srcOffset + 2];
- if (maxVal !== false) {
- Ls = decode(Ls, maxVal, 0, 100);
- as = decode(as, maxVal, cs.amin, cs.amax);
- bs = decode(bs, maxVal, cs.bmin, cs.bmax);
- }
-
- // Adjust limits of 'as' and 'bs'
- as = as > cs.amax ? cs.amax : as < cs.amin ? cs.amin : as;
- bs = bs > cs.bmax ? cs.bmax : bs < cs.bmin ? cs.bmin : bs;
-
- // Computes intermediate variables X,Y,Z as per spec
- var M = (Ls + 16) / 116;
- var L = M + (as / 500);
- var N = M - (bs / 200);
-
- var X = cs.XW * fn_g(L);
- var Y = cs.YW * fn_g(M);
- var Z = cs.ZW * fn_g(N);
-
- var r, g, b;
- // Using different conversions for D50 and D65 white points,
- // per http://www.color.org/srgb.pdf
- if (cs.ZW < 1) {
- // Assuming D50 (X=0.9642, Y=1.00, Z=0.8249)
- r = X * 3.1339 + Y * -1.6170 + Z * -0.4906;
- g = X * -0.9785 + Y * 1.9160 + Z * 0.0333;
- b = X * 0.0720 + Y * -0.2290 + Z * 1.4057;
- } else {
- // Assuming D65 (X=0.9505, Y=1.00, Z=1.0888)
- r = X * 3.2406 + Y * -1.5372 + Z * -0.4986;
- g = X * -0.9689 + Y * 1.8758 + Z * 0.0415;
- b = X * 0.0557 + Y * -0.2040 + Z * 1.0570;
- }
- // clamp color values to [0,1] range then convert to [0,255] range.
- dest[destOffset] = Math.sqrt(r < 0 ? 0 : r > 1 ? 1 : r) * 255;
- dest[destOffset + 1] = Math.sqrt(g < 0 ? 0 : g > 1 ? 1 : g) * 255;
- dest[destOffset + 2] = Math.sqrt(b < 0 ? 0 : b > 1 ? 1 : b) * 255;
- }
-
- LabCS.prototype = {
- getRgb: function LabCS_getRgb(src, srcOffset) {
- var rgb = new Uint8Array(3);
- convertToRgb(this, src, srcOffset, false, rgb, 0);
- return rgb;
- },
- getRgbItem: function LabCS_getRgbItem(src, srcOffset, dest, destOffset) {
- convertToRgb(this, src, srcOffset, false, dest, destOffset);
- },
- getRgbBuffer: function LabCS_getRgbBuffer(src, srcOffset, count,
- dest, destOffset, bits) {
- var maxVal = (1 << bits) - 1;
- for (var i = 0; i < count; i++) {
- convertToRgb(this, src, srcOffset, maxVal, dest, destOffset);
- srcOffset += 3;
- destOffset += 3;
- }
- },
- getOutputLength: function LabCS_getOutputLength(inputLength) {
- return inputLength;
- },
- isPassthrough: ColorSpace.prototype.isPassthrough,
- isDefaultDecode: function LabCS_isDefaultDecode(decodeMap) {
- // XXX: Decoding is handled with the lab conversion because of the strange
- // ranges that are used.
- return true;
- },
- usesZeroToOneRange: false
- };
- return LabCS;
-})();
-
-
-
-var PatternType = {
- AXIAL: 2,
- RADIAL: 3
-};
-
-var Pattern = (function PatternClosure() {
- // Constructor should define this.getPattern
- function Pattern() {
- error('should not call Pattern constructor');
- }
-
- Pattern.prototype = {
- // Input: current Canvas context
- // Output: the appropriate fillStyle or strokeStyle
- getPattern: function Pattern_getPattern(ctx) {
- error('Should not call Pattern.getStyle: ' + ctx);
- }
- };
-
- Pattern.shadingFromIR = function Pattern_shadingFromIR(raw) {
- return Shadings[raw[0]].fromIR(raw);
- };
-
- Pattern.parseShading = function Pattern_parseShading(shading, matrix, xref,
- res) {
-
- var dict = isStream(shading) ? shading.dict : shading;
- var type = dict.get('ShadingType');
-
- switch (type) {
- case PatternType.AXIAL:
- case PatternType.RADIAL:
- // Both radial and axial shadings are handled by RadialAxial shading.
- return new Shadings.RadialAxial(dict, matrix, xref, res);
- default:
- UnsupportedManager.notify(UNSUPPORTED_FEATURES.shadingPattern);
- return new Shadings.Dummy();
- }
- };
- return Pattern;
-})();
-
-var Shadings = {};
-
-// A small number to offset the first/last color stops so we can insert ones to
-// support extend. Number.MIN_VALUE appears to be too small and breaks the
-// extend. 1e-7 works in FF but chrome seems to use an even smaller sized number
-// internally so we have to go bigger.
-Shadings.SMALL_NUMBER = 1e-2;
-
-// Radial and axial shading have very similar implementations
-// If needed, the implementations can be broken into two classes
-Shadings.RadialAxial = (function RadialAxialClosure() {
- function RadialAxial(dict, matrix, xref, res, ctx) {
- this.matrix = matrix;
- this.coordsArr = dict.get('Coords');
- this.shadingType = dict.get('ShadingType');
- this.type = 'Pattern';
- this.ctx = ctx;
- var cs = dict.get('ColorSpace', 'CS');
- cs = ColorSpace.parse(cs, xref, res);
- this.cs = cs;
-
- var t0 = 0.0, t1 = 1.0;
- if (dict.has('Domain')) {
- var domainArr = dict.get('Domain');
- t0 = domainArr[0];
- t1 = domainArr[1];
- }
-
- var extendStart = false, extendEnd = false;
- if (dict.has('Extend')) {
- var extendArr = dict.get('Extend');
- extendStart = extendArr[0];
- extendEnd = extendArr[1];
- }
-
- if (this.shadingType === PatternType.RADIAL &&
- (!extendStart || !extendEnd)) {
- // Radial gradient only currently works if either circle is fully within
- // the other circle.
- var x1 = this.coordsArr[0];
- var y1 = this.coordsArr[1];
- var r1 = this.coordsArr[2];
- var x2 = this.coordsArr[3];
- var y2 = this.coordsArr[4];
- var r2 = this.coordsArr[5];
- var distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
- if (r1 <= r2 + distance &&
- r2 <= r1 + distance) {
- warn('Unsupported radial gradient.');
- }
- }
-
- this.extendStart = extendStart;
- this.extendEnd = extendEnd;
-
- var fnObj = dict.get('Function');
- var fn;
- if (isArray(fnObj)) {
- var fnArray = [];
- for (var j = 0, jj = fnObj.length; j < jj; j++) {
- var obj = xref.fetchIfRef(fnObj[j]);
- if (!isPDFFunction(obj)) {
- error('Invalid function');
- }
- fnArray.push(PDFFunction.parse(xref, obj));
- }
- fn = function radialAxialColorFunction(arg) {
- var out = [];
- for (var i = 0, ii = fnArray.length; i < ii; i++) {
- out.push(fnArray[i](arg)[0]);
- }
- return out;
- };
- } else {
- if (!isPDFFunction(fnObj)) {
- error('Invalid function');
- }
- fn = PDFFunction.parse(xref, fnObj);
- }
-
- // 10 samples seems good enough for now, but probably won't work
- // if there are sharp color changes. Ideally, we would implement
- // the spec faithfully and add lossless optimizations.
- var diff = t1 - t0;
- var step = diff / 10;
-
- var colorStops = this.colorStops = [];
-
- // Protect against bad domains so we don't end up in an infinte loop below.
- if (t0 >= t1 || step <= 0) {
- // Acrobat doesn't seem to handle these cases so we'll ignore for
- // now.
- info('Bad shading domain.');
- return;
- }
-
- for (var i = t0; i <= t1; i += step) {
- var rgbColor = cs.getRgb(fn([i]), 0);
- var cssColor = Util.makeCssRgb(rgbColor);
- colorStops.push([(i - t0) / diff, cssColor]);
- }
-
- var background = 'transparent';
- if (dict.has('Background')) {
- var rgbColor = cs.getRgb(dict.get('Background'), 0);
- background = Util.makeCssRgb(rgbColor);
- }
-
- if (!extendStart) {
- // Insert a color stop at the front and offset the first real color stop
- // so it doesn't conflict with the one we insert.
- colorStops.unshift([0, background]);
- colorStops[1][0] += Shadings.SMALL_NUMBER;
- }
- if (!extendEnd) {
- // Same idea as above in extendStart but for the end.
- colorStops[colorStops.length - 1][0] -= Shadings.SMALL_NUMBER;
- colorStops.push([1, background]);
- }
-
- this.colorStops = colorStops;
- }
-
- RadialAxial.fromIR = function RadialAxial_fromIR(raw) {
- var type = raw[1];
- var colorStops = raw[2];
- var p0 = raw[3];
- var p1 = raw[4];
- var r0 = raw[5];
- var r1 = raw[6];
- return {
- type: 'Pattern',
- getPattern: function RadialAxial_getPattern(ctx) {
- var grad;
- if (type == PatternType.AXIAL)
- grad = ctx.createLinearGradient(p0[0], p0[1], p1[0], p1[1]);
- else if (type == PatternType.RADIAL)
- grad = ctx.createRadialGradient(p0[0], p0[1], r0, p1[0], p1[1], r1);
-
- for (var i = 0, ii = colorStops.length; i < ii; ++i) {
- var c = colorStops[i];
- grad.addColorStop(c[0], c[1]);
- }
- return grad;
- }
- };
- };
-
- RadialAxial.prototype = {
- getIR: function RadialAxial_getIR() {
- var coordsArr = this.coordsArr;
- var type = this.shadingType;
- if (type == PatternType.AXIAL) {
- var p0 = [coordsArr[0], coordsArr[1]];
- var p1 = [coordsArr[2], coordsArr[3]];
- var r0 = null;
- var r1 = null;
- } else if (type == PatternType.RADIAL) {
- var p0 = [coordsArr[0], coordsArr[1]];
- var p1 = [coordsArr[3], coordsArr[4]];
- var r0 = coordsArr[2];
- var r1 = coordsArr[5];
- } else {
- error('getPattern type unknown: ' + type);
- }
-
- var matrix = this.matrix;
- if (matrix) {
- p0 = Util.applyTransform(p0, matrix);
- p1 = Util.applyTransform(p1, matrix);
- }
-
- return ['RadialAxial', type, this.colorStops, p0, p1, r0, r1];
- }
- };
-
- return RadialAxial;
-})();
-
-Shadings.Dummy = (function DummyClosure() {
- function Dummy() {
- this.type = 'Pattern';
- }
-
- Dummy.fromIR = function Dummy_fromIR() {
- return {
- type: 'Pattern',
- getPattern: function Dummy_fromIR_getPattern() {
- return 'hotpink';
- }
- };
- };
-
- Dummy.prototype = {
- getIR: function Dummy_getIR() {
- return ['Dummy'];
- }
- };
- return Dummy;
-})();
-
-var TilingPattern = (function TilingPatternClosure() {
- var PaintType = {
- COLORED: 1,
- UNCOLORED: 2
- };
-
- var MAX_PATTERN_SIZE = 3000; // 10in @ 300dpi shall be enough
-
- function TilingPattern(IR, color, ctx, objs, commonObjs, baseTransform) {
- this.name = IR[1][0].name;
- this.operatorList = IR[2];
- this.matrix = IR[3] || [1, 0, 0, 1, 0, 0];
- this.bbox = IR[4];
- this.xstep = IR[5];
- this.ystep = IR[6];
- this.paintType = IR[7];
- this.tilingType = IR[8];
- this.color = color;
- this.objs = objs;
- this.commonObjs = commonObjs;
- this.baseTransform = baseTransform;
- this.type = 'Pattern';
- this.ctx = ctx;
- }
-
- TilingPattern.getIR = function TilingPattern_getIR(operatorList, dict, args) {
- var matrix = dict.get('Matrix');
- var bbox = dict.get('BBox');
- var xstep = dict.get('XStep');
- var ystep = dict.get('YStep');
- var paintType = dict.get('PaintType');
- var tilingType = dict.get('TilingType');
-
- return [
- 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep,
- paintType, tilingType
- ];
- };
-
- TilingPattern.prototype = {
- createPatternCanvas: function TilinPattern_createPatternCanvas(owner) {
- var operatorList = this.operatorList;
- var bbox = this.bbox;
- var xstep = this.xstep;
- var ystep = this.ystep;
- var paintType = this.paintType;
- var tilingType = this.tilingType;
- var color = this.color;
- var objs = this.objs;
- var commonObjs = this.commonObjs;
- var ctx = this.ctx;
-
- info('TilingType: ' + tilingType);
-
- var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
-
- var topLeft = [x0, y0];
- // we want the canvas to be as large as the step size
- var botRight = [x0 + xstep, y0 + ystep];
-
- var width = botRight[0] - topLeft[0];
- var height = botRight[1] - topLeft[1];
-
- // Obtain scale from matrix and current transformation matrix.
- var matrixScale = Util.singularValueDecompose2dScale(this.matrix);
- var curMatrixScale = Util.singularValueDecompose2dScale(
- this.baseTransform);
- var combinedScale = [matrixScale[0] * curMatrixScale[0],
- matrixScale[1] * curMatrixScale[1]];
-
- // MAX_PATTERN_SIZE is used to avoid OOM situation.
- // Use width and height values that are as close as possible to the end
- // result when the pattern is used. Too low value makes the pattern look
- // blurry. Too large value makes it look too crispy.
- width = Math.min(Math.ceil(Math.abs(width * combinedScale[0])),
- MAX_PATTERN_SIZE);
-
- height = Math.min(Math.ceil(Math.abs(height * combinedScale[1])),
- MAX_PATTERN_SIZE);
-
- var tmpCanvas = CachedCanvases.getCanvas('pattern', width, height, true);
- var tmpCtx = tmpCanvas.context;
- var graphics = new CanvasGraphics(tmpCtx, commonObjs, objs);
- graphics.groupLevel = owner.groupLevel;
-
- this.setFillAndStrokeStyleToContext(tmpCtx, paintType, color);
-
- this.setScale(width, height, xstep, ystep);
- this.transformToScale(graphics);
-
- // transform coordinates to pattern space
- var tmpTranslate = [1, 0, 0, 1, -topLeft[0], -topLeft[1]];
- graphics.transform.apply(graphics, tmpTranslate);
-
- this.clipBbox(graphics, bbox, x0, y0, x1, y1);
-
- graphics.executeOperatorList(operatorList);
- return tmpCanvas.canvas;
- },
-
- setScale: function TilingPattern_setScale(width, height, xstep, ystep) {
- this.scale = [width / xstep, height / ystep];
- },
-
- transformToScale: function TilingPattern_transformToScale(graphics) {
- var scale = this.scale;
- var tmpScale = [scale[0], 0, 0, scale[1], 0, 0];
- graphics.transform.apply(graphics, tmpScale);
- },
-
- scaleToContext: function TilingPattern_scaleToContext() {
- var scale = this.scale;
- this.ctx.scale(1 / scale[0], 1 / scale[1]);
- },
-
- clipBbox: function clipBbox(graphics, bbox, x0, y0, x1, y1) {
- if (bbox && isArray(bbox) && 4 == bbox.length) {
- var bboxWidth = x1 - x0;
- var bboxHeight = y1 - y0;
- graphics.rectangle(x0, y0, bboxWidth, bboxHeight);
- graphics.clip();
- graphics.endPath();
- }
- },
-
- setFillAndStrokeStyleToContext:
- function setFillAndStrokeStyleToContext(context, paintType, color) {
- switch (paintType) {
- case PaintType.COLORED:
- var ctx = this.ctx;
- context.fillStyle = ctx.fillStyle;
- context.strokeStyle = ctx.strokeStyle;
- break;
- case PaintType.UNCOLORED:
- var rgbColor = ColorSpace.singletons.rgb.getRgb(color, 0);
- var cssColor = Util.makeCssRgb(rgbColor);
- context.fillStyle = cssColor;
- context.strokeStyle = cssColor;
- break;
- default:
- error('Unsupported paint type: ' + paintType);
- }
- },
-
- getPattern: function TilingPattern_getPattern(ctx, owner) {
- var temporaryPatternCanvas = this.createPatternCanvas(owner);
-
- var ctx = this.ctx;
- ctx.setTransform.apply(ctx, this.baseTransform);
- ctx.transform.apply(ctx, this.matrix);
- this.scaleToContext();
-
- return ctx.createPattern(temporaryPatternCanvas, 'repeat');
- }
- };
-
- return TilingPattern;
-})();
-
-
-
-var PDFFunction = (function PDFFunctionClosure() {
- var CONSTRUCT_SAMPLED = 0;
- var CONSTRUCT_INTERPOLATED = 2;
- var CONSTRUCT_STICHED = 3;
- var CONSTRUCT_POSTSCRIPT = 4;
-
- return {
- getSampleArray: function PDFFunction_getSampleArray(size, outputSize, bps,
- str) {
- var length = 1;
- for (var i = 0, ii = size.length; i < ii; i++)
- length *= size[i];
- length *= outputSize;
-
- var array = [];
- var codeSize = 0;
- var codeBuf = 0;
- // 32 is a valid bps so shifting won't work
- var sampleMul = 1.0 / (Math.pow(2.0, bps) - 1);
-
- var strBytes = str.getBytes((length * bps + 7) / 8);
- var strIdx = 0;
- for (var i = 0; i < length; i++) {
- while (codeSize < bps) {
- codeBuf <<= 8;
- codeBuf |= strBytes[strIdx++];
- codeSize += 8;
- }
- codeSize -= bps;
- array.push((codeBuf >> codeSize) * sampleMul);
- codeBuf &= (1 << codeSize) - 1;
- }
- return array;
- },
-
- getIR: function PDFFunction_getIR(xref, fn) {
- var dict = fn.dict;
- if (!dict)
- dict = fn;
-
- var types = [this.constructSampled,
- null,
- this.constructInterpolated,
- this.constructStiched,
- this.constructPostScript];
-
- var typeNum = dict.get('FunctionType');
- var typeFn = types[typeNum];
- if (!typeFn)
- error('Unknown type of function');
-
- return typeFn.call(this, fn, dict, xref);
- },
-
- fromIR: function PDFFunction_fromIR(IR) {
- var type = IR[0];
- switch (type) {
- case CONSTRUCT_SAMPLED:
- return this.constructSampledFromIR(IR);
- case CONSTRUCT_INTERPOLATED:
- return this.constructInterpolatedFromIR(IR);
- case CONSTRUCT_STICHED:
- return this.constructStichedFromIR(IR);
- //case CONSTRUCT_POSTSCRIPT:
- default:
- return this.constructPostScriptFromIR(IR);
- }
- },
-
- parse: function PDFFunction_parse(xref, fn) {
- var IR = this.getIR(xref, fn);
- return this.fromIR(IR);
- },
-
- constructSampled: function PDFFunction_constructSampled(str, dict) {
- function toMultiArray(arr) {
- var inputLength = arr.length;
- var outputLength = arr.length / 2;
- var out = [];
- var index = 0;
- for (var i = 0; i < inputLength; i += 2) {
- out[index] = [arr[i], arr[i + 1]];
- ++index;
- }
- return out;
- }
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain || !range)
- error('No domain or range');
-
- var inputSize = domain.length / 2;
- var outputSize = range.length / 2;
-
- domain = toMultiArray(domain);
- range = toMultiArray(range);
-
- var size = dict.get('Size');
- var bps = dict.get('BitsPerSample');
- var order = dict.get('Order') || 1;
- if (order !== 1) {
- // No description how cubic spline interpolation works in PDF32000:2008
- // As in poppler, ignoring order, linear interpolation may work as good
- info('No support for cubic spline interpolation: ' + order);
- }
-
- var encode = dict.get('Encode');
- if (!encode) {
- encode = [];
- for (var i = 0; i < inputSize; ++i) {
- encode.push(0);
- encode.push(size[i] - 1);
- }
- }
- encode = toMultiArray(encode);
-
- var decode = dict.get('Decode');
- if (!decode)
- decode = range;
- else
- decode = toMultiArray(decode);
-
- var samples = this.getSampleArray(size, outputSize, bps, str);
-
- return [
- CONSTRUCT_SAMPLED, inputSize, domain, encode, decode, samples, size,
- outputSize, Math.pow(2, bps) - 1, range
- ];
- },
-
- constructSampledFromIR: function PDFFunction_constructSampledFromIR(IR) {
- // See chapter 3, page 109 of the PDF reference
- function interpolate(x, xmin, xmax, ymin, ymax) {
- return ymin + ((x - xmin) * ((ymax - ymin) / (xmax - xmin)));
- }
-
- return function constructSampledFromIRResult(args) {
- // See chapter 3, page 110 of the PDF reference.
- var m = IR[1];
- var domain = IR[2];
- var encode = IR[3];
- var decode = IR[4];
- var samples = IR[5];
- var size = IR[6];
- var n = IR[7];
- var mask = IR[8];
- var range = IR[9];
-
- if (m != args.length)
- error('Incorrect number of arguments: ' + m + ' != ' +
- args.length);
-
- var x = args;
-
- // Building the cube vertices: its part and sample index
- // http://rjwagner49.com/Mathematics/Interpolation.pdf
- var cubeVertices = 1 << m;
- var cubeN = new Float64Array(cubeVertices);
- var cubeVertex = new Uint32Array(cubeVertices);
- for (var j = 0; j < cubeVertices; j++)
- cubeN[j] = 1;
-
- var k = n, pos = 1;
- // Map x_i to y_j for 0 <= i < m using the sampled function.
- for (var i = 0; i < m; ++i) {
- // x_i' = min(max(x_i, Domain_2i), Domain_2i+1)
- var domain_2i = domain[i][0];
- var domain_2i_1 = domain[i][1];
- var xi = Math.min(Math.max(x[i], domain_2i), domain_2i_1);
-
- // e_i = Interpolate(x_i', Domain_2i, Domain_2i+1,
- // Encode_2i, Encode_2i+1)
- var e = interpolate(xi, domain_2i, domain_2i_1,
- encode[i][0], encode[i][1]);
-
- // e_i' = min(max(e_i, 0), Size_i - 1)
- var size_i = size[i];
- e = Math.min(Math.max(e, 0), size_i - 1);
-
- // Adjusting the cube: N and vertex sample index
- var e0 = e < size_i - 1 ? Math.floor(e) : e - 1; // e1 = e0 + 1;
- var n0 = e0 + 1 - e; // (e1 - e) / (e1 - e0);
- var n1 = e - e0; // (e - e0) / (e1 - e0);
- var offset0 = e0 * k;
- var offset1 = offset0 + k; // e1 * k
- for (var j = 0; j < cubeVertices; j++) {
- if (j & pos) {
- cubeN[j] *= n1;
- cubeVertex[j] += offset1;
- } else {
- cubeN[j] *= n0;
- cubeVertex[j] += offset0;
- }
- }
-
- k *= size_i;
- pos <<= 1;
- }
-
- var y = new Float64Array(n);
- for (var j = 0; j < n; ++j) {
- // Sum all cube vertices' samples portions
- var rj = 0;
- for (var i = 0; i < cubeVertices; i++)
- rj += samples[cubeVertex[i] + j] * cubeN[i];
-
- // r_j' = Interpolate(r_j, 0, 2^BitsPerSample - 1,
- // Decode_2j, Decode_2j+1)
- rj = interpolate(rj, 0, 1, decode[j][0], decode[j][1]);
-
- // y_j = min(max(r_j, range_2j), range_2j+1)
- y[j] = Math.min(Math.max(rj, range[j][0]), range[j][1]);
- }
-
- return y;
- };
- },
-
- constructInterpolated: function PDFFunction_constructInterpolated(str,
- dict) {
- var c0 = dict.get('C0') || [0];
- var c1 = dict.get('C1') || [1];
- var n = dict.get('N');
-
- if (!isArray(c0) || !isArray(c1))
- error('Illegal dictionary for interpolated function');
-
- var length = c0.length;
- var diff = [];
- for (var i = 0; i < length; ++i)
- diff.push(c1[i] - c0[i]);
-
- return [CONSTRUCT_INTERPOLATED, c0, diff, n];
- },
-
- constructInterpolatedFromIR:
- function PDFFunction_constructInterpolatedFromIR(IR) {
- var c0 = IR[1];
- var diff = IR[2];
- var n = IR[3];
-
- var length = diff.length;
-
- return function constructInterpolatedFromIRResult(args) {
- var x = n == 1 ? args[0] : Math.pow(args[0], n);
-
- var out = [];
- for (var j = 0; j < length; ++j)
- out.push(c0[j] + (x * diff[j]));
-
- return out;
-
- };
- },
-
- constructStiched: function PDFFunction_constructStiched(fn, dict, xref) {
- var domain = dict.get('Domain');
-
- if (!domain)
- error('No domain');
-
- var inputSize = domain.length / 2;
- if (inputSize != 1)
- error('Bad domain for stiched function');
-
- var fnRefs = dict.get('Functions');
- var fns = [];
- for (var i = 0, ii = fnRefs.length; i < ii; ++i)
- fns.push(PDFFunction.getIR(xref, xref.fetchIfRef(fnRefs[i])));
-
- var bounds = dict.get('Bounds');
- var encode = dict.get('Encode');
-
- return [CONSTRUCT_STICHED, domain, bounds, encode, fns];
- },
-
- constructStichedFromIR: function PDFFunction_constructStichedFromIR(IR) {
- var domain = IR[1];
- var bounds = IR[2];
- var encode = IR[3];
- var fnsIR = IR[4];
- var fns = [];
-
- for (var i = 0, ii = fnsIR.length; i < ii; i++) {
- fns.push(PDFFunction.fromIR(fnsIR[i]));
- }
-
- return function constructStichedFromIRResult(args) {
- var clip = function constructStichedFromIRClip(v, min, max) {
- if (v > max)
- v = max;
- else if (v < min)
- v = min;
- return v;
- };
-
- // clip to domain
- var v = clip(args[0], domain[0], domain[1]);
- // calulate which bound the value is in
- for (var i = 0, ii = bounds.length; i < ii; ++i) {
- if (v < bounds[i])
- break;
- }
-
- // encode value into domain of function
- var dmin = domain[0];
- if (i > 0)
- dmin = bounds[i - 1];
- var dmax = domain[1];
- if (i < bounds.length)
- dmax = bounds[i];
-
- var rmin = encode[2 * i];
- var rmax = encode[2 * i + 1];
-
- var v2 = rmin + (v - dmin) * (rmax - rmin) / (dmax - dmin);
-
- // call the appropropriate function
- return fns[i]([v2]);
- };
- },
-
- constructPostScript: function PDFFunction_constructPostScript(fn, dict,
- xref) {
- var domain = dict.get('Domain');
- var range = dict.get('Range');
-
- if (!domain)
- error('No domain.');
-
- if (!range)
- error('No range.');
-
- var lexer = new PostScriptLexer(fn);
- var parser = new PostScriptParser(lexer);
- var code = parser.parse();
-
- return [CONSTRUCT_POSTSCRIPT, domain, range, code];
- },
-
- constructPostScriptFromIR: function PDFFunction_constructPostScriptFromIR(
- IR) {
- var domain = IR[1];
- var range = IR[2];
- var code = IR[3];
- var numOutputs = range.length / 2;
- var evaluator = new PostScriptEvaluator(code);
- // Cache the values for a big speed up, the cache size is limited though
- // since the number of possible values can be huge from a PS function.
- var cache = new FunctionCache();
- return function constructPostScriptFromIRResult(args) {
- var initialStack = [];
- for (var i = 0, ii = (domain.length / 2); i < ii; ++i) {
- initialStack.push(args[i]);
- }
-
- var key = initialStack.join('_');
- if (cache.has(key))
- return cache.get(key);
-
- var stack = evaluator.execute(initialStack);
- var transformed = [];
- for (i = numOutputs - 1; i >= 0; --i) {
- var out = stack.pop();
- var rangeIndex = 2 * i;
- if (out < range[rangeIndex])
- out = range[rangeIndex];
- else if (out > range[rangeIndex + 1])
- out = range[rangeIndex + 1];
- transformed[i] = out;
- }
- cache.set(key, transformed);
- return transformed;
- };
- }
- };
-})();
-
-var FunctionCache = (function FunctionCacheClosure() {
- // Of 10 PDF's with type4 functions the maxium number of distinct values seen
- // was 256. This still may need some tweaking in the future though.
- var MAX_CACHE_SIZE = 1024;
- function FunctionCache() {
- this.cache = {};
- this.total = 0;
- }
- FunctionCache.prototype = {
- has: function FunctionCache_has(key) {
- return key in this.cache;
- },
- get: function FunctionCache_get(key) {
- return this.cache[key];
- },
- set: function FunctionCache_set(key, value) {
- if (this.total < MAX_CACHE_SIZE) {
- this.cache[key] = value;
- this.total++;
- }
- }
- };
- return FunctionCache;
-})();
-
-var PostScriptStack = (function PostScriptStackClosure() {
- var MAX_STACK_SIZE = 100;
- function PostScriptStack(initialStack) {
- this.stack = initialStack || [];
- }
-
- PostScriptStack.prototype = {
- push: function PostScriptStack_push(value) {
- if (this.stack.length >= MAX_STACK_SIZE)
- error('PostScript function stack overflow.');
- this.stack.push(value);
- },
- pop: function PostScriptStack_pop() {
- if (this.stack.length <= 0)
- error('PostScript function stack underflow.');
- return this.stack.pop();
- },
- copy: function PostScriptStack_copy(n) {
- if (this.stack.length + n >= MAX_STACK_SIZE)
- error('PostScript function stack overflow.');
- var stack = this.stack;
- for (var i = stack.length - n, j = n - 1; j >= 0; j--, i++)
- stack.push(stack[i]);
- },
- index: function PostScriptStack_index(n) {
- this.push(this.stack[this.stack.length - n - 1]);
- },
- // rotate the last n stack elements p times
- roll: function PostScriptStack_roll(n, p) {
- var stack = this.stack;
- var l = stack.length - n;
- var r = stack.length - 1, c = l + (p - Math.floor(p / n) * n), i, j, t;
- for (i = l, j = r; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- for (i = l, j = c - 1; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- for (i = c, j = r; i < j; i++, j--) {
- t = stack[i]; stack[i] = stack[j]; stack[j] = t;
- }
- }
- };
- return PostScriptStack;
-})();
-var PostScriptEvaluator = (function PostScriptEvaluatorClosure() {
- function PostScriptEvaluator(operators, operands) {
- this.operators = operators;
- this.operands = operands;
- }
- PostScriptEvaluator.prototype = {
- execute: function PostScriptEvaluator_execute(initialStack) {
- var stack = new PostScriptStack(initialStack);
- var counter = 0;
- var operators = this.operators;
- var length = operators.length;
- var operator, a, b;
- while (counter < length) {
- operator = operators[counter++];
- if (typeof operator == 'number') {
- // Operator is really an operand and should be pushed to the stack.
- stack.push(operator);
- continue;
- }
- switch (operator) {
- // non standard ps operators
- case 'jz': // jump if false
- b = stack.pop();
- a = stack.pop();
- if (!a)
- counter = b;
- break;
- case 'j': // jump
- a = stack.pop();
- counter = a;
- break;
-
- // all ps operators in alphabetical order (excluding if/ifelse)
- case 'abs':
- a = stack.pop();
- stack.push(Math.abs(a));
- break;
- case 'add':
- b = stack.pop();
- a = stack.pop();
- stack.push(a + b);
- break;
- case 'and':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a && b);
- else
- stack.push(a & b);
- break;
- case 'atan':
- a = stack.pop();
- stack.push(Math.atan(a));
- break;
- case 'bitshift':
- b = stack.pop();
- a = stack.pop();
- if (a > 0)
- stack.push(a << b);
- else
- stack.push(a >> b);
- break;
- case 'ceiling':
- a = stack.pop();
- stack.push(Math.ceil(a));
- break;
- case 'copy':
- a = stack.pop();
- stack.copy(a);
- break;
- case 'cos':
- a = stack.pop();
- stack.push(Math.cos(a));
- break;
- case 'cvi':
- a = stack.pop() | 0;
- stack.push(a);
- break;
- case 'cvr':
- // noop
- break;
- case 'div':
- b = stack.pop();
- a = stack.pop();
- stack.push(a / b);
- break;
- case 'dup':
- stack.copy(1);
- break;
- case 'eq':
- b = stack.pop();
- a = stack.pop();
- stack.push(a == b);
- break;
- case 'exch':
- stack.roll(2, 1);
- break;
- case 'exp':
- b = stack.pop();
- a = stack.pop();
- stack.push(Math.pow(a, b));
- break;
- case 'false':
- stack.push(false);
- break;
- case 'floor':
- a = stack.pop();
- stack.push(Math.floor(a));
- break;
- case 'ge':
- b = stack.pop();
- a = stack.pop();
- stack.push(a >= b);
- break;
- case 'gt':
- b = stack.pop();
- a = stack.pop();
- stack.push(a > b);
- break;
- case 'idiv':
- b = stack.pop();
- a = stack.pop();
- stack.push((a / b) | 0);
- break;
- case 'index':
- a = stack.pop();
- stack.index(a);
- break;
- case 'le':
- b = stack.pop();
- a = stack.pop();
- stack.push(a <= b);
- break;
- case 'ln':
- a = stack.pop();
- stack.push(Math.log(a));
- break;
- case 'log':
- a = stack.pop();
- stack.push(Math.log(a) / Math.LN10);
- break;
- case 'lt':
- b = stack.pop();
- a = stack.pop();
- stack.push(a < b);
- break;
- case 'mod':
- b = stack.pop();
- a = stack.pop();
- stack.push(a % b);
- break;
- case 'mul':
- b = stack.pop();
- a = stack.pop();
- stack.push(a * b);
- break;
- case 'ne':
- b = stack.pop();
- a = stack.pop();
- stack.push(a != b);
- break;
- case 'neg':
- a = stack.pop();
- stack.push(-b);
- break;
- case 'not':
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a && b);
- else
- stack.push(a & b);
- break;
- case 'or':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a || b);
- else
- stack.push(a | b);
- break;
- case 'pop':
- stack.pop();
- break;
- case 'roll':
- b = stack.pop();
- a = stack.pop();
- stack.roll(a, b);
- break;
- case 'round':
- a = stack.pop();
- stack.push(Math.round(a));
- break;
- case 'sin':
- a = stack.pop();
- stack.push(Math.sin(a));
- break;
- case 'sqrt':
- a = stack.pop();
- stack.push(Math.sqrt(a));
- break;
- case 'sub':
- b = stack.pop();
- a = stack.pop();
- stack.push(a - b);
- break;
- case 'true':
- stack.push(true);
- break;
- case 'truncate':
- a = stack.pop();
- a = a < 0 ? Math.ceil(a) : Math.floor(a);
- stack.push(a);
- break;
- case 'xor':
- b = stack.pop();
- a = stack.pop();
- if (isBool(a) && isBool(b))
- stack.push(a != b);
- else
- stack.push(a ^ b);
- break;
- default:
- error('Unknown operator ' + operator);
- break;
- }
- }
- return stack.stack;
- }
- };
- return PostScriptEvaluator;
-})();
-
-var PostScriptParser = (function PostScriptParserClosure() {
- function PostScriptParser(lexer) {
- this.lexer = lexer;
- this.operators = [];
- this.token = null;
- this.prev = null;
- }
- PostScriptParser.prototype = {
- nextToken: function PostScriptParser_nextToken() {
- this.prev = this.token;
- this.token = this.lexer.getToken();
- },
- accept: function PostScriptParser_accept(type) {
- if (this.token.type == type) {
- this.nextToken();
- return true;
- }
- return false;
- },
- expect: function PostScriptParser_expect(type) {
- if (this.accept(type))
- return true;
- error('Unexpected symbol: found ' + this.token.type + ' expected ' +
- type + '.');
- },
- parse: function PostScriptParser_parse() {
- this.nextToken();
- this.expect(PostScriptTokenTypes.LBRACE);
- this.parseBlock();
- this.expect(PostScriptTokenTypes.RBRACE);
- return this.operators;
- },
- parseBlock: function PostScriptParser_parseBlock() {
- while (true) {
- if (this.accept(PostScriptTokenTypes.NUMBER)) {
- this.operators.push(this.prev.value);
- } else if (this.accept(PostScriptTokenTypes.OPERATOR)) {
- this.operators.push(this.prev.value);
- } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
- this.parseCondition();
- } else {
- return;
- }
- }
- },
- parseCondition: function PostScriptParser_parseCondition() {
- // Add two place holders that will be updated later
- var conditionLocation = this.operators.length;
- this.operators.push(null, null);
-
- this.parseBlock();
- this.expect(PostScriptTokenTypes.RBRACE);
- if (this.accept(PostScriptTokenTypes.IF)) {
- // The true block is right after the 'if' so it just falls through on
- // true else it jumps and skips the true block.
- this.operators[conditionLocation] = this.operators.length;
- this.operators[conditionLocation + 1] = 'jz';
- } else if (this.accept(PostScriptTokenTypes.LBRACE)) {
- var jumpLocation = this.operators.length;
- this.operators.push(null, null);
- var endOfTrue = this.operators.length;
- this.parseBlock();
- this.expect(PostScriptTokenTypes.RBRACE);
- this.expect(PostScriptTokenTypes.IFELSE);
- // The jump is added at the end of the true block to skip the false
- // block.
- this.operators[jumpLocation] = this.operators.length;
- this.operators[jumpLocation + 1] = 'j';
-
- this.operators[conditionLocation] = endOfTrue;
- this.operators[conditionLocation + 1] = 'jz';
- } else {
- error('PS Function: error parsing conditional.');
- }
- }
- };
- return PostScriptParser;
-})();
-
-var PostScriptTokenTypes = {
- LBRACE: 0,
- RBRACE: 1,
- NUMBER: 2,
- OPERATOR: 3,
- IF: 4,
- IFELSE: 5
-};
-
-var PostScriptToken = (function PostScriptTokenClosure() {
- function PostScriptToken(type, value) {
- this.type = type;
- this.value = value;
- }
-
- var opCache = {};
-
- PostScriptToken.getOperator = function PostScriptToken_getOperator(op) {
- var opValue = opCache[op];
- if (opValue)
- return opValue;
-
- return opCache[op] = new PostScriptToken(PostScriptTokenTypes.OPERATOR, op);
- };
-
- PostScriptToken.LBRACE = new PostScriptToken(PostScriptTokenTypes.LBRACE,
- '{');
- PostScriptToken.RBRACE = new PostScriptToken(PostScriptTokenTypes.RBRACE,
- '}');
- PostScriptToken.IF = new PostScriptToken(PostScriptTokenTypes.IF, 'IF');
- PostScriptToken.IFELSE = new PostScriptToken(PostScriptTokenTypes.IFELSE,
- 'IFELSE');
- return PostScriptToken;
-})();
-
-var PostScriptLexer = (function PostScriptLexerClosure() {
- function PostScriptLexer(stream) {
- this.stream = stream;
- this.nextChar();
- }
- PostScriptLexer.prototype = {
- nextChar: function PostScriptLexer_nextChar() {
- return (this.currentChar = this.stream.getByte());
- },
- getToken: function PostScriptLexer_getToken() {
- var s = '';
- var comment = false;
- var ch = this.currentChar;
-
- // skip comments
- while (true) {
- if (ch < 0) {
- return EOF;
- }
-
- if (comment) {
- if (ch === 0x0A || ch === 0x0D) {
- comment = false;
- }
- } else if (ch == 0x25) { // '%'
- comment = true;
- } else if (!Lexer.isSpace(ch)) {
- break;
- }
- ch = this.nextChar();
- }
- switch (ch | 0) {
- case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4'
- case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9'
- case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.'
- return new PostScriptToken(PostScriptTokenTypes.NUMBER,
- this.getNumber());
- case 0x7B: // '{'
- this.nextChar();
- return PostScriptToken.LBRACE;
- case 0x7D: // '}'
- this.nextChar();
- return PostScriptToken.RBRACE;
- }
- // operator
- var str = String.fromCharCode(ch);
- while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z'
- ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) {
- str += String.fromCharCode(ch);
- }
- switch (str.toLowerCase()) {
- case 'if':
- return PostScriptToken.IF;
- case 'ifelse':
- return PostScriptToken.IFELSE;
- default:
- return PostScriptToken.getOperator(str);
- }
- },
- getNumber: function PostScriptLexer_getNumber() {
- var ch = this.currentChar;
- var str = String.fromCharCode(ch);
- while ((ch = this.nextChar()) >= 0) {
- if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9'
- ch === 0x2D || ch === 0x2E) { // '-', '.'
- str += String.fromCharCode(ch);
- } else {
- break;
- }
- }
- var value = parseFloat(str);
- if (isNaN(value))
- error('Invalid floating point number: ' + value);
- return value;
- }
- };
- return PostScriptLexer;
-})();
-
-
-
-var Annotation = (function AnnotationClosure() {
- // 12.5.5: Algorithm: Appearance streams
- function getTransformMatrix(rect, bbox, matrix) {
- var bounds = Util.getAxialAlignedBoundingBox(bbox, matrix);
- var minX = bounds[0];
- var minY = bounds[1];
- var maxX = bounds[2];
- var maxY = bounds[3];
-
- if (minX === maxX || minY === maxY) {
- // From real-life file, bbox was [0, 0, 0, 0]. In this case,
- // just apply the transform for rect
- return [1, 0, 0, 1, rect[0], rect[1]];
- }
-
- var xRatio = (rect[2] - rect[0]) / (maxX - minX);
- var yRatio = (rect[3] - rect[1]) / (maxY - minY);
- return [
- xRatio,
- 0,
- 0,
- yRatio,
- rect[0] - minX * xRatio,
- rect[1] - minY * yRatio
- ];
- }
-
- function getDefaultAppearance(dict) {
- var appearanceState = dict.get('AP');
- if (!isDict(appearanceState)) {
- return;
- }
-
- var appearance;
- var appearances = appearanceState.get('N');
- if (isDict(appearances)) {
- var as = dict.get('AS');
- if (as && appearances.has(as.name)) {
- appearance = appearances.get(as.name);
- }
- } else {
- appearance = appearances;
- }
- return appearance;
- }
-
- function Annotation(params) {
- if (params.data) {
- this.data = params.data;
- return;
- }
-
- var dict = params.dict;
- var data = this.data = {};
-
- data.subtype = dict.get('Subtype').name;
- var rect = dict.get('Rect');
- data.rect = Util.normalizeRect(rect);
- data.annotationFlags = dict.get('F');
-
- var color = dict.get('C');
- if (isArray(color) && color.length === 3) {
- // TODO(mack): currently only supporting rgb; need support different
- // colorspaces
- data.color = color;
- } else {
- data.color = [0, 0, 0];
- }
-
- // Some types of annotations have border style dict which has more
- // info than the border array
- if (dict.has('BS')) {
- var borderStyle = dict.get('BS');
- data.borderWidth = borderStyle.has('W') ? borderStyle.get('W') : 1;
- } else {
- var borderArray = dict.get('Border') || [0, 0, 1];
- data.borderWidth = borderArray[2] || 0;
- }
-
- this.appearance = getDefaultAppearance(dict);
- data.hasAppearance = !!this.appearance;
- }
-
- Annotation.prototype = {
-
- getData: function Annotation_getData() {
- return this.data;
- },
-
- hasHtml: function Annotation_hasHtml() {
- return false;
- },
-
- getHtmlElement: function Annotation_getHtmlElement(commonObjs) {
- throw new NotImplementedException(
- 'getHtmlElement() should be implemented in subclass');
- },
-
- // TODO(mack): Remove this, it's not really that helpful.
- getEmptyContainer: function Annotation_getEmptyContainer(tagName, rect) {
- assert(!isWorker,
- 'getEmptyContainer() should be called from main thread');
-
- rect = rect || this.data.rect;
- var element = document.createElement(tagName);
- element.style.width = Math.ceil(rect[2] - rect[0]) + 'px';
- element.style.height = Math.ceil(rect[3] - rect[1]) + 'px';
- return element;
- },
-
- isViewable: function Annotation_isViewable() {
- var data = this.data;
- return !!(
- data &&
- (!data.annotationFlags ||
- !(data.annotationFlags & 0x22)) && // Hidden or NoView
- data.rect // rectangle is nessessary
- );
- },
-
- loadResources: function(keys) {
- var promise = new LegacyPromise();
- this.appearance.dict.getAsync('Resources').then(function(resources) {
- if (!resources) {
- promise.resolve();
- return;
- }
- var objectLoader = new ObjectLoader(resources.map,
- keys,
- resources.xref);
- objectLoader.load().then(function() {
- promise.resolve(resources);
- });
- }.bind(this));
-
- return promise;
- },
-
- getOperatorList: function Annotation_getToOperatorList(evaluator) {
-
- var promise = new LegacyPromise();
-
- if (!this.appearance) {
- promise.resolve(new OperatorList());
- return promise;
- }
-
- var data = this.data;
-
- var appearanceDict = this.appearance.dict;
- var resourcesPromise = this.loadResources([
- 'ExtGState',
- 'ColorSpace',
- 'Pattern',
- 'Shading',
- 'XObject',
- 'Font'
- // ProcSet
- // Properties
- ]);
- var bbox = appearanceDict.get('BBox') || [0, 0, 1, 1];
- var matrix = appearanceDict.get('Matrix') || [1, 0, 0, 1, 0 ,0];
- var transform = getTransformMatrix(data.rect, bbox, matrix);
-
- var border = data.border;
-
- resourcesPromise.then(function(resources) {
- var opList = new OperatorList();
- opList.addOp(OPS.beginAnnotation, [data.rect, transform, matrix]);
- evaluator.getOperatorList(this.appearance, resources, opList);
- opList.addOp(OPS.endAnnotation, []);
- promise.resolve(opList);
- }.bind(this));
-
- return promise;
- }
- };
-
- Annotation.getConstructor =
- function Annotation_getConstructor(subtype, fieldType) {
-
- if (!subtype) {
- return;
- }
-
- // TODO(mack): Implement FreeText annotations
- if (subtype === 'Link') {
- return LinkAnnotation;
- } else if (subtype === 'Text') {
- return TextAnnotation;
- } else if (subtype === 'Widget') {
- if (!fieldType) {
- return;
- }
-
- if (fieldType === 'Tx') {
- return TextWidgetAnnotation;
- } else {
- return WidgetAnnotation;
- }
- } else {
- return Annotation;
- }
- };
-
- // TODO(mack): Support loading annotation from data
- Annotation.fromData = function Annotation_fromData(data) {
- var subtype = data.subtype;
- var fieldType = data.fieldType;
- var Constructor = Annotation.getConstructor(subtype, fieldType);
- if (Constructor) {
- return new Constructor({ data: data });
- }
- };
-
- Annotation.fromRef = function Annotation_fromRef(xref, ref) {
-
- var dict = xref.fetchIfRef(ref);
- if (!isDict(dict)) {
- return;
- }
-
- var subtype = dict.get('Subtype');
- subtype = isName(subtype) ? subtype.name : '';
- if (!subtype) {
- return;
- }
-
- var fieldType = Util.getInheritableProperty(dict, 'FT');
- fieldType = isName(fieldType) ? fieldType.name : '';
-
- var Constructor = Annotation.getConstructor(subtype, fieldType);
- if (!Constructor) {
- return;
- }
-
- var params = {
- dict: dict,
- ref: ref,
- };
-
- var annotation = new Constructor(params);
-
- if (annotation.isViewable()) {
- return annotation;
- } else {
- warn('unimplemented annotation type: ' + subtype);
- }
- };
-
- Annotation.appendToOperatorList = function Annotation_appendToOperatorList(
- annotations, opList, pdfManager, partialEvaluator) {
-
- function reject(e) {
- annotationsReadyPromise.reject(e);
- }
-
- var annotationsReadyPromise = new LegacyPromise();
-
- var annotationPromises = [];
- for (var i = 0, n = annotations.length; i < n; ++i) {
- annotationPromises.push(annotations[i].getOperatorList(partialEvaluator));
- }
- Promise.all(annotationPromises).then(function(datas) {
- opList.addOp(OPS.beginAnnotations, []);
- for (var i = 0, n = datas.length; i < n; ++i) {
- var annotOpList = datas[i];
- opList.addOpList(annotOpList);
- }
- opList.addOp(OPS.endAnnotations, []);
- annotationsReadyPromise.resolve();
- }, reject);
-
- return annotationsReadyPromise;
- };
-
- return Annotation;
-})();
-PDFJS.Annotation = Annotation;
-
-
-var WidgetAnnotation = (function WidgetAnnotationClosure() {
-
- function WidgetAnnotation(params) {
- Annotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- var dict = params.dict;
- var data = this.data;
-
- data.fieldValue = stringToPDFString(
- Util.getInheritableProperty(dict, 'V') || '');
- data.alternativeText = stringToPDFString(dict.get('TU') || '');
- data.defaultAppearance = Util.getInheritableProperty(dict, 'DA') || '';
- var fieldType = Util.getInheritableProperty(dict, 'FT');
- data.fieldType = isName(fieldType) ? fieldType.name : '';
- data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
- this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
-
- // Building the full field name by collecting the field and
- // its ancestors 'T' data and joining them using '.'.
- var fieldName = [];
- var namedItem = dict;
- var ref = params.ref;
- while (namedItem) {
- var parent = namedItem.get('Parent');
- var parentRef = namedItem.getRaw('Parent');
- var name = namedItem.get('T');
- if (name) {
- fieldName.unshift(stringToPDFString(name));
- } else {
- // The field name is absent, that means more than one field
- // with the same name may exist. Replacing the empty name
- // with the '`' plus index in the parent's 'Kids' array.
- // This is not in the PDF spec but necessary to id the
- // the input controls.
- var kids = parent.get('Kids');
- var j, jj;
- for (j = 0, jj = kids.length; j < jj; j++) {
- var kidRef = kids[j];
- if (kidRef.num == ref.num && kidRef.gen == ref.gen)
- break;
- }
- fieldName.unshift('`' + j);
- }
- namedItem = parent;
- ref = parentRef;
- }
- data.fullName = fieldName.join('.');
- }
-
- var parent = Annotation.prototype;
- Util.inherit(WidgetAnnotation, Annotation, {
- isViewable: function WidgetAnnotation_isViewable() {
- if (this.data.fieldType === 'Sig') {
- warn('unimplemented annotation type: Widget signature');
- return false;
- }
-
- return parent.isViewable.call(this);
- }
- });
-
- return WidgetAnnotation;
-})();
-
-var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
- function TextWidgetAnnotation(params) {
- WidgetAnnotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- this.data.textAlignment = Util.getInheritableProperty(params.dict, 'Q');
- }
-
- // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
- function setTextStyles(element, item, fontObj) {
-
- var style = element.style;
- style.fontSize = item.fontSize + 'px';
- style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
-
- if (!fontObj) {
- return;
- }
-
- style.fontWeight = fontObj.black ?
- (fontObj.bold ? 'bolder' : 'bold') :
- (fontObj.bold ? 'bold' : 'normal');
- style.fontStyle = fontObj.italic ? 'italic' : 'normal';
-
- var fontName = fontObj.loadedName;
- var fontFamily = fontName ? '"' + fontName + '", ' : '';
- // Use a reasonable default font if the font doesn't specify a fallback
- var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
- style.fontFamily = fontFamily + fallbackName;
- }
-
-
- var parent = WidgetAnnotation.prototype;
- Util.inherit(TextWidgetAnnotation, WidgetAnnotation, {
- hasHtml: function TextWidgetAnnotation_hasHtml() {
- return !this.data.hasAppearance && !!this.data.fieldValue;
- },
-
- getHtmlElement: function TextWidgetAnnotation_getHtmlElement(commonObjs) {
- assert(!isWorker, 'getHtmlElement() shall be called from main thread');
-
- var item = this.data;
-
- var element = this.getEmptyContainer('div');
- element.style.display = 'table';
-
- var content = document.createElement('div');
- content.textContent = item.fieldValue;
- var textAlignment = item.textAlignment;
- content.style.textAlign = ['left', 'center', 'right'][textAlignment];
- content.style.verticalAlign = 'middle';
- content.style.display = 'table-cell';
-
- var fontObj = item.fontRefName ?
- commonObjs.getData(item.fontRefName) : null;
- var cssRules = setTextStyles(content, item, fontObj);
-
- element.appendChild(content);
-
- return element;
- },
-
- getOperatorList: function TextWidgetAnnotation_getOperatorList(evaluator) {
- if (this.appearance) {
- return Annotation.prototype.getOperatorList.call(this, evaluator);
- }
-
- var promise = new LegacyPromise();
- var opList = new OperatorList();
- var data = this.data;
-
- // Even if there is an appearance stream, ignore it. This is the
- // behaviour used by Adobe Reader.
-
- var defaultAppearance = data.defaultAppearance;
- if (!defaultAppearance) {
- promise.resolve(opList);
- return promise;
- }
-
- // Include any font resources found in the default appearance
-
- var stream = new Stream(stringToBytes(defaultAppearance));
- evaluator.getOperatorList(stream, this.fieldResources, opList);
- var appearanceFnArray = opList.fnArray;
- var appearanceArgsArray = opList.argsArray;
- var fnArray = [];
- var argsArray = [];
-
- // TODO(mack): Add support for stroke color
- data.rgb = [0, 0, 0];
- // TODO THIS DOESN'T MAKE ANY SENSE SINCE THE fnArray IS EMPTY!
- for (var i = 0, n = fnArray.length; i < n; ++i) {
- var fnId = appearanceFnArray[i];
- var args = appearanceArgsArray[i];
-
- if (fnId === OPS.setFont) {
- data.fontRefName = args[0];
- var size = args[1];
- if (size < 0) {
- data.fontDirection = -1;
- data.fontSize = -size;
- } else {
- data.fontDirection = 1;
- data.fontSize = size;
- }
- } else if (fnId === OPS.setFillRGBColor) {
- data.rgb = args;
- } else if (fnId === OPS.setFillGray) {
- var rgbValue = args[0] * 255;
- data.rgb = [rgbValue, rgbValue, rgbValue];
- }
- }
- promise.resolve(opList);
- return promise;
- }
- });
-
- return TextWidgetAnnotation;
-})();
-
-var TextAnnotation = (function TextAnnotationClosure() {
- function TextAnnotation(params) {
- Annotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- var dict = params.dict;
- var data = this.data;
-
- var content = dict.get('Contents');
- var title = dict.get('T');
- data.content = stringToPDFString(content || '');
- data.title = stringToPDFString(title || '');
- data.name = !dict.has('Name') ? 'Note' : dict.get('Name').name;
- }
-
- var ANNOT_MIN_SIZE = 10;
-
- Util.inherit(TextAnnotation, Annotation, {
-
- getOperatorList: function TextAnnotation_getOperatorList(evaluator) {
- var promise = new LegacyPromise();
- promise.resolve(new OperatorList());
- return promise;
- },
-
- hasHtml: function TextAnnotation_hasHtml() {
- return true;
- },
-
- getHtmlElement: function TextAnnotation_getHtmlElement(commonObjs) {
- assert(!isWorker, 'getHtmlElement() shall be called from main thread');
-
- var item = this.data;
- var rect = item.rect;
-
- // sanity check because of OOo-generated PDFs
- if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
- rect[3] = rect[1] + ANNOT_MIN_SIZE;
- }
- if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
- rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
- }
-
- var container = this.getEmptyContainer('section', rect);
- container.className = 'annotText';
-
- var image = document.createElement('img');
- image.style.height = container.style.height;
- var iconName = item.name;
- image.src = PDFJS.imageResourcesPath + 'annotation-' +
- iconName.toLowerCase() + '.svg';
- image.alt = '[{{type}} Annotation]';
- image.dataset.l10nId = 'text_annotation_type';
- image.dataset.l10nArgs = JSON.stringify({type: iconName});
- var content = document.createElement('div');
- content.setAttribute('hidden', true);
- var title = document.createElement('h1');
- var text = document.createElement('p');
- content.style.left = Math.floor(rect[2] - rect[0]) + 'px';
- content.style.top = '0px';
- title.textContent = item.title;
-
- if (!item.content && !item.title) {
- content.setAttribute('hidden', true);
- } else {
- var e = document.createElement('span');
- var lines = item.content.split(/(?:\r\n?|\n)/);
- for (var i = 0, ii = lines.length; i < ii; ++i) {
- var line = lines[i];
- e.appendChild(document.createTextNode(line));
- if (i < (ii - 1))
- e.appendChild(document.createElement('br'));
- }
- text.appendChild(e);
-
- var showAnnotation = function showAnnotation() {
- container.style.zIndex += 1;
- content.removeAttribute('hidden');
- };
-
- var hideAnnotation = function hideAnnotation(e) {
- if (e.toElement || e.relatedTarget) { // No context menu is used
- container.style.zIndex -= 1;
- content.setAttribute('hidden', true);
- }
- };
-
- content.addEventListener('mouseover', showAnnotation, false);
- content.addEventListener('mouseout', hideAnnotation, false);
- image.addEventListener('mouseover', showAnnotation, false);
- image.addEventListener('mouseout', hideAnnotation, false);
- }
-
- content.appendChild(title);
- content.appendChild(text);
- container.appendChild(image);
- container.appendChild(content);
-
- return container;
- }
- });
-
- return TextAnnotation;
-})();
-
-var LinkAnnotation = (function LinkAnnotationClosure() {
- function LinkAnnotation(params) {
- Annotation.call(this, params);
-
- if (params.data) {
- return;
- }
-
- var dict = params.dict;
- var data = this.data;
-
- var action = dict.get('A');
- if (action) {
- var linkType = action.get('S').name;
- if (linkType === 'URI') {
- var url = addDefaultProtocolToUrl(action.get('URI'));
- // TODO: pdf spec mentions urls can be relative to a Base
- // entry in the dictionary.
- if (!isValidUrl(url, false)) {
- url = '';
- }
- data.url = url;
- } else if (linkType === 'GoTo') {
- data.dest = action.get('D');
- } else if (linkType === 'GoToR') {
- var urlDict = action.get('F');
- if (isDict(urlDict)) {
- // We assume that the 'url' is a Filspec dictionary
- // and fetch the url without checking any further
- url = urlDict.get('F') || '';
- }
-
- // TODO: pdf reference says that GoToR
- // can also have 'NewWindow' attribute
- if (!isValidUrl(url, false)) {
- url = '';
- }
- data.url = url;
- data.dest = action.get('D');
- } else if (linkType === 'Named') {
- data.action = action.get('N').name;
- } else {
- warn('unrecognized link type: ' + linkType);
- }
- } else if (dict.has('Dest')) {
- // simple destination link
- var dest = dict.get('Dest');
- data.dest = isName(dest) ? dest.name : dest;
- }
- }
-
- // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
- function addDefaultProtocolToUrl(url) {
- if (url.indexOf('www.') === 0) {
- return ('http://' + url);
- }
- return url;
- }
-
- Util.inherit(LinkAnnotation, Annotation, {
- hasOperatorList: function LinkAnnotation_hasOperatorList() {
- return false;
- },
-
- hasHtml: function LinkAnnotation_hasHtml() {
- return true;
- },
-
- getHtmlElement: function LinkAnnotation_getHtmlElement(commonObjs) {
- var rect = this.data.rect;
- var element = document.createElement('a');
- var borderWidth = this.data.borderWidth;
-
- element.style.borderWidth = borderWidth + 'px';
- var color = this.data.color;
- var rgb = [];
- for (var i = 0; i < 3; ++i) {
- rgb[i] = Math.round(color[i] * 255);
- }
- element.style.borderColor = Util.makeCssRgb(rgb);
- element.style.borderStyle = 'solid';
-
- var width = rect[2] - rect[0] - 2 * borderWidth;
- var height = rect[3] - rect[1] - 2 * borderWidth;
- element.style.width = width + 'px';
- element.style.height = height + 'px';
-
- element.href = this.data.url || '';
- return element;
- }
- });
-
- return LinkAnnotation;
-})();
-
-
/**
* The maximum allowed image size in total pixels e.g. width * height. Images
* above this value will not be drawn. Use -1 for no limit.
- * @var {Number}
+ * @var {number}
*/
-PDFJS.maxImageSize = PDFJS.maxImageSize === undefined ? -1 : PDFJS.maxImageSize;
+PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?
+ -1 : PDFJS.maxImageSize);
/**
+ * The url of where the predefined Adobe CMaps are located. Include trailing
+ * slash.
+ * @var {string}
+ */
+PDFJS.cMapUrl = (PDFJS.cMapUrl === undefined ? null : PDFJS.cMapUrl);
+
+/**
+ * Specifies if CMaps are binary packed.
+ * @var {boolean}
+ */
+PDFJS.cMapPacked = PDFJS.cMapPacked === undefined ? false : PDFJS.cMapPacked;
+
+/*
* By default fonts are converted to OpenType fonts and loaded via font face
* rules. If disabled, the font will be rendered using a built in font renderer
* that constructs the glyphs with primitive path commands.
- * @var {Boolean}
+ * @var {boolean}
*/
-PDFJS.disableFontFace = PDFJS.disableFontFace === undefined ?
- false : PDFJS.disableFontFace;
+PDFJS.disableFontFace = (PDFJS.disableFontFace === undefined ?
+ false : PDFJS.disableFontFace);
/**
* Path for image resources, mainly for annotation icons. Include trailing
* slash.
- * @var {String}
+ * @var {string}
*/
-PDFJS.imageResourcesPath = PDFJS.imageResourcesPath === undefined ?
- '' : PDFJS.imageResourcesPath;
+PDFJS.imageResourcesPath = (PDFJS.imageResourcesPath === undefined ?
+ '' : PDFJS.imageResourcesPath);
/**
* Disable the web worker and run all code on the main thread. This will happen
* automatically if the browser doesn't support workers or sending typed arrays
* to workers.
- * @var {Boolean}
+ * @var {boolean}
*/
-PDFJS.disableWorker = PDFJS.disableWorker === undefined ?
- false : PDFJS.disableWorker;
+PDFJS.disableWorker = (PDFJS.disableWorker === undefined ?
+ false : PDFJS.disableWorker);
/**
* Path and filename of the worker file. Required when the worker is enabled in
* development mode. If unspecified in the production build, the worker will be
* loaded based on the location of the pdf.js file.
- * @var {String}
+ * @var {string}
*/
-PDFJS.workerSrc = PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc;
+PDFJS.workerSrc = (PDFJS.workerSrc === undefined ? null : PDFJS.workerSrc);
/**
* Disable range request loading of PDF files. When enabled and if the server
* supports partial content requests then the PDF will be fetched in chunks.
* Enabled (false) by default.
- * @var {Boolean}
+ * @var {boolean}
*/
-PDFJS.disableRange = PDFJS.disableRange === undefined ?
- false : PDFJS.disableRange;
+PDFJS.disableRange = (PDFJS.disableRange === undefined ?
+ false : PDFJS.disableRange);
+
+/**
+ * Disable streaming of PDF file data. By default PDF.js attempts to load PDF
+ * in chunks. This default behavior can be disabled.
+ * @var {boolean}
+ */
+PDFJS.disableStream = (PDFJS.disableStream === undefined ?
+ false : PDFJS.disableStream);
/**
* Disable pre-fetching of PDF file data. When range requests are enabled PDF.js
* will automatically keep fetching more data even if it isn't needed to display
* the current page. This default behavior can be disabled.
- * @var {Boolean}
+ * @var {boolean}
*/
-PDFJS.disableAutoFetch = PDFJS.disableAutoFetch === undefined ?
- false : PDFJS.disableAutoFetch;
+PDFJS.disableAutoFetch = (PDFJS.disableAutoFetch === undefined ?
+ false : PDFJS.disableAutoFetch);
/**
* Enables special hooks for debugging PDF.js.
- * @var {Boolean}
+ * @var {boolean}
*/
-PDFJS.pdfBug = PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug;
+PDFJS.pdfBug = (PDFJS.pdfBug === undefined ? false : PDFJS.pdfBug);
/**
* Enables transfer usage in postMessage for ArrayBuffers.
* @var {boolean}
*/
-PDFJS.postMessageTransfers = PDFJS.postMessageTransfers === undefined ?
- true : PDFJS.postMessageTransfers;
+PDFJS.postMessageTransfers = (PDFJS.postMessageTransfers === undefined ?
+ true : PDFJS.postMessageTransfers);
+
+/**
+ * Disables URL.createObjectURL usage.
+ * @var {boolean}
+ */
+PDFJS.disableCreateObjectURL = (PDFJS.disableCreateObjectURL === undefined ?
+ false : PDFJS.disableCreateObjectURL);
+
+/**
+ * Disables WebGL usage.
+ * @var {boolean}
+ */
+PDFJS.disableWebGL = (PDFJS.disableWebGL === undefined ?
+ true : PDFJS.disableWebGL);
+
+/**
+ * Enables CSS only zooming.
+ * @var {boolean}
+ */
+PDFJS.useOnlyCssZoom = (PDFJS.useOnlyCssZoom === undefined ?
+ false : PDFJS.useOnlyCssZoom);
/**
* Controls the logging level.
@@ -4236,10 +1731,42 @@ PDFJS.postMessageTransfers = PDFJS.postMessageTransfers === undefined ?
* - errors
* - warnings [default]
* - infos
- * @var {Number}
+ * @var {number}
+ */
+PDFJS.verbosity = (PDFJS.verbosity === undefined ?
+ PDFJS.VERBOSITY_LEVELS.warnings : PDFJS.verbosity);
+
+/**
+ * The maximum supported canvas size in total pixels e.g. width * height.
+ * The default value is 4096 * 4096. Use -1 for no limit.
+ * @var {number}
+ */
+PDFJS.maxCanvasPixels = (PDFJS.maxCanvasPixels === undefined ?
+ 16777216 : PDFJS.maxCanvasPixels);
+
+/**
+ * Document initialization / loading parameters object.
+ *
+ * @typedef {Object} DocumentInitParameters
+ * @property {string} url - The URL of the PDF.
+ * @property {TypedArray} data - A typed array with PDF data.
+ * @property {Object} httpHeaders - Basic authentication headers.
+ * @property {boolean} withCredentials - Indicates whether or not cross-site
+ * Access-Control requests should be made using credentials such as cookies
+ * or authorization headers. The default is false.
+ * @property {string} password - For decrypting password-protected PDFs.
+ * @property {TypedArray} initialData - A typed array with the first portion or
+ * all of the pdf data. Used by the extension since some data is already
+ * loaded before the switch to range requests.
+ */
+
+/**
+ * @typedef {Object} PDFDocumentStats
+ * @property {Array} streamTypes - Used stream types in the document (an item
+ * is set to true if specific stream ID was used in the document).
+ * @property {Array} fontTypes - Used font type in the document (an item is set
+ * to true if specific font ID was used in the document).
*/
-PDFJS.verbosity = PDFJS.verbosity === undefined ?
- PDFJS.VERBOSITY_LEVELS.warnings : PDFJS.verbosity;
/**
* This is the main entry point for loading a PDF and interacting with it.
@@ -4247,18 +1774,11 @@ PDFJS.verbosity = PDFJS.verbosity === undefined ?
* is used, which means it must follow the same origin rules that any XHR does
* e.g. No cross domain requests without CORS.
*
- * @param {string|TypedAray|object} source Can be an url to where a PDF is
- * located, a typed array (Uint8Array) already populated with data or
- * and parameter object with the following possible fields:
- * - url - The URL of the PDF.
- * - data - A typed array with PDF data.
- * - httpHeaders - Basic authentication headers.
- * - password - For decrypting password-protected PDFs.
- * - initialData - A typed array with the first portion or all of the pdf data.
- * Used by the extension since some data is already loaded
- * before the switch to range requests.
+ * @param {string|TypedArray|DocumentInitParameters} source Can be a url to
+ * where a PDF is located, a typed array (Uint8Array) already populated with
+ * data or parameter object.
*
- * @param {object} pdfDataRangeTransport is optional. It is used if you want
+ * @param {Object} pdfDataRangeTransport is optional. It is used if you want
* to manually serve range requests for data in the PDF. See viewer.js for
* an example of pdfDataRangeTransport's interface.
*
@@ -4267,13 +1787,19 @@ PDFJS.verbosity = PDFJS.verbosity === undefined ?
* parameters: function that needs to be called with new password and reason
* (see {PasswordResponses}).
*
- * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object.
+ * @param {function} progressCallback is optional. It is used to be able to
+ * monitor the loading progress of the PDF file (necessary to implement e.g.
+ * a loading bar). The callback receives an {Object} with the properties:
+ * {number} loaded and {number} total.
+ *
+ * @return {Promise} A promise that is resolved with {@link PDFDocumentProxy}
+ * object.
*/
PDFJS.getDocument = function getDocument(source,
pdfDataRangeTransport,
passwordCallback,
progressCallback) {
- var workerInitializedPromise, workerReadyPromise, transport;
+ var workerInitializedCapability, workerReadyCapability, transport;
if (typeof source === 'string') {
source = { url: source };
@@ -4284,8 +1810,9 @@ PDFJS.getDocument = function getDocument(source,
'string or a parameter object');
}
- if (!source.url && !source.data)
+ if (!source.url && !source.data) {
error('Invalid parameter array, need either .data or .url');
+ }
// copy/use all keys as is except 'url' -- full path is required
var params = {};
@@ -4297,27 +1824,29 @@ PDFJS.getDocument = function getDocument(source,
params[key] = source[key];
}
- workerInitializedPromise = new PDFJS.LegacyPromise();
- workerReadyPromise = new PDFJS.LegacyPromise();
- transport = new WorkerTransport(workerInitializedPromise,
- workerReadyPromise, pdfDataRangeTransport, progressCallback);
- workerInitializedPromise.then(function transportInitialized() {
+ workerInitializedCapability = createPromiseCapability();
+ workerReadyCapability = createPromiseCapability();
+ transport = new WorkerTransport(workerInitializedCapability,
+ workerReadyCapability, pdfDataRangeTransport,
+ progressCallback);
+ workerInitializedCapability.promise.then(function transportInitialized() {
transport.passwordCallback = passwordCallback;
transport.fetchDocument(params);
});
- return workerReadyPromise;
+ return workerReadyCapability.promise;
};
/**
* Proxy to a PDFDocument in the worker thread. Also, contains commonly used
* properties that can be read synchronously.
+ * @class
*/
var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
function PDFDocumentProxy(pdfInfo, transport) {
this.pdfInfo = pdfInfo;
this.transport = transport;
}
- PDFDocumentProxy.prototype = {
+ PDFDocumentProxy.prototype = /** @lends PDFDocumentProxy.prototype */ {
/**
* @return {number} Total number of pages the PDF contains.
*/
@@ -4332,22 +1861,16 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
return this.pdfInfo.fingerprint;
},
/**
- * @return {boolean} true if embedded document fonts are in use. Will be
- * set during rendering of the pages.
- */
- get embeddedFontsUsed() {
- return this.transport.embeddedFontsUsed;
- },
- /**
- * @param {number} The page number to get. The first page is 1.
- * @return {Promise} A promise that is resolved with a {PDFPageProxy}
+ * @param {number} pageNumber The page number to get. The first page is 1.
+ * @return {Promise} A promise that is resolved with a {@link PDFPageProxy}
* object.
*/
- getPage: function PDFDocumentProxy_getPage(number) {
- return this.transport.getPage(number);
+ getPage: function PDFDocumentProxy_getPage(pageNumber) {
+ return this.transport.getPage(pageNumber);
},
/**
- * @param {object} Must have 'num' and 'gen' properties.
+ * @param {{num: number, gen: number}} ref The page reference. Must have
+ * the 'num' and 'gen' properties.
* @return {Promise} A promise that is resolved with the page index that is
* associated with the reference.
*/
@@ -4357,22 +1880,36 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
/**
* @return {Promise} A promise that is resolved with a lookup table for
* mapping named destinations to reference numbers.
+ *
+ * This can be slow for large documents: use getDestination instead
*/
getDestinations: function PDFDocumentProxy_getDestinations() {
return this.transport.getDestinations();
},
+ /**
+ * @param {string} id The named destination to get.
+ * @return {Promise} A promise that is resolved with all information
+ * of the given named destination.
+ */
+ getDestination: function PDFDocumentProxy_getDestination(id) {
+ return this.transport.getDestination(id);
+ },
+ /**
+ * @return {Promise} A promise that is resolved with a lookup table for
+ * mapping named attachments to their content.
+ */
+ getAttachments: function PDFDocumentProxy_getAttachments() {
+ return this.transport.getAttachments();
+ },
/**
* @return {Promise} A promise that is resolved with an array of all the
* JavaScript strings in the name tree.
*/
getJavaScript: function PDFDocumentProxy_getJavaScript() {
- var promise = new PDFJS.LegacyPromise();
- var js = this.pdfInfo.javaScript;
- promise.resolve(js);
- return promise;
+ return this.transport.getJavaScript();
},
/**
- * @return {Promise} A promise that is resolved with an {array} that is a
+ * @return {Promise} A promise that is resolved with an {Array} that is a
* tree outline (if it has one) of the PDF. The tree is in the format of:
* [
* {
@@ -4387,51 +1924,48 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
* ].
*/
getOutline: function PDFDocumentProxy_getOutline() {
- var promise = new PDFJS.LegacyPromise();
- var outline = this.pdfInfo.outline;
- promise.resolve(outline);
- return promise;
+ return this.transport.getOutline();
},
/**
- * @return {Promise} A promise that is resolved with an {object} that has
- * info and metadata properties. Info is an {object} filled with anything
+ * @return {Promise} A promise that is resolved with an {Object} that has
+ * info and metadata properties. Info is an {Object} filled with anything
* available in the information dictionary and similarly metadata is a
* {Metadata} object with information from the metadata section of the PDF.
*/
getMetadata: function PDFDocumentProxy_getMetadata() {
- var promise = new PDFJS.LegacyPromise();
- var info = this.pdfInfo.info;
- var metadata = this.pdfInfo.metadata;
- promise.resolve({
- info: info,
- metadata: metadata ? new PDFJS.Metadata(metadata) : null
- });
- return promise;
- },
- isEncrypted: function PDFDocumentProxy_isEncrypted() {
- var promise = new PDFJS.LegacyPromise();
- promise.resolve(this.pdfInfo.encrypted);
- return promise;
+ return this.transport.getMetadata();
},
/**
* @return {Promise} A promise that is resolved with a TypedArray that has
* the raw data from the PDF.
*/
getData: function PDFDocumentProxy_getData() {
- var promise = new PDFJS.LegacyPromise();
- this.transport.getData(promise);
- return promise;
+ return this.transport.getData();
},
/**
* @return {Promise} A promise that is resolved when the document's data
- * is loaded
+ * is loaded. It is resolved with an {Object} that contains the length
+ * property that indicates size of the PDF data in bytes.
*/
- dataLoaded: function PDFDocumentProxy_dataLoaded() {
- return this.transport.dataLoaded();
+ getDownloadInfo: function PDFDocumentProxy_getDownloadInfo() {
+ return this.transport.downloadInfoCapability.promise;
},
+ /**
+ * @returns {Promise} A promise this is resolved with current stats about
+ * document structures (see {@link PDFDocumentStats}).
+ */
+ getStats: function PDFDocumentProxy_getStats() {
+ return this.transport.getStats();
+ },
+ /**
+ * Cleans up resources allocated by the document, e.g. created @font-face.
+ */
cleanup: function PDFDocumentProxy_cleanup() {
this.transport.startCleanup();
},
+ /**
+ * Destroys current document instance and terminates worker.
+ */
destroy: function PDFDocumentProxy_destroy() {
this.transport.destroy();
}
@@ -4439,25 +1973,86 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
return PDFDocumentProxy;
})();
+/**
+ * Page text content.
+ *
+ * @typedef {Object} TextContent
+ * @property {array} items - array of {@link TextItem}
+ * @property {Object} styles - {@link TextStyles} objects, indexed by font
+ * name.
+ */
+
+/**
+ * Page text content part.
+ *
+ * @typedef {Object} TextItem
+ * @property {string} str - text content.
+ * @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
+ * @property {array} transform - transformation matrix.
+ * @property {number} width - width in device space.
+ * @property {number} height - height in device space.
+ * @property {string} fontName - font name used by pdf.js for converted font.
+ */
+
+/**
+ * Text style.
+ *
+ * @typedef {Object} TextStyle
+ * @property {number} ascent - font ascent.
+ * @property {number} descent - font descent.
+ * @property {boolean} vertical - text is in vertical mode.
+ * @property {string} fontFamily - possible font family
+ */
+
+/**
+ * Page render parameters.
+ *
+ * @typedef {Object} RenderParameters
+ * @property {Object} canvasContext - A 2D context of a DOM Canvas object.
+ * @property {PDFJS.PageViewport} viewport - Rendering viewport obtained by
+ * calling of PDFPage.getViewport method.
+ * @property {string} intent - Rendering intent, can be 'display' or 'print'
+ * (default value is 'display').
+ * @property {Object} imageLayer - (optional) An object that has beginLayout,
+ * endLayout and appendImage functions.
+ * @property {function} continueCallback - (optional) A function that will be
+ * called each time the rendering is paused. To continue
+ * rendering call the function that is the first argument
+ * to the callback.
+ */
+
+/**
+ * PDF page operator list.
+ *
+ * @typedef {Object} PDFOperatorList
+ * @property {Array} fnArray - Array containing the operator functions.
+ * @property {Array} argsArray - Array containing the arguments of the
+ * functions.
+ */
+
+/**
+ * Proxy to a PDFPage in the worker thread.
+ * @class
+ */
var PDFPageProxy = (function PDFPageProxyClosure() {
- function PDFPageProxy(pageInfo, transport) {
+ function PDFPageProxy(pageIndex, pageInfo, transport) {
+ this.pageIndex = pageIndex;
this.pageInfo = pageInfo;
this.transport = transport;
this.stats = new StatTimer();
this.stats.enabled = !!globalScope.PDFJS.enableStats;
this.commonObjs = transport.commonObjs;
this.objs = new PDFObjects();
- this.receivingOperatorList = false;
this.cleanupAfterRender = false;
this.pendingDestroy = false;
- this.renderTasks = [];
+ this.intentStates = {};
}
- PDFPageProxy.prototype = {
+ PDFPageProxy.prototype = /** @lends PDFPageProxy.prototype */ {
/**
* @return {number} Page number of the page. First page is 1.
*/
get pageNumber() {
- return this.pageInfo.pageIndex + 1;
+ return this.pageIndex + 1;
},
/**
* @return {number} The number of degrees the page is rotated clockwise.
@@ -4466,14 +2061,14 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return this.pageInfo.rotate;
},
/**
- * @return {object} The reference that points to this page. It has 'num' and
+ * @return {Object} The reference that points to this page. It has 'num' and
* 'gen' properties.
*/
get ref() {
return this.pageInfo.ref;
},
/**
- * @return {array} An array of the visible portion of the PDF page in the
+ * @return {Array} An array of the visible portion of the PDF page in the
* user space units - [x1, y1, x2, y2].
*/
get view() {
@@ -4483,43 +2078,33 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
* @param {number} scale The desired scale of the viewport.
* @param {number} rotate Degrees to rotate the viewport. If omitted this
* defaults to the page rotation.
- * @return {PageViewport} Contains 'width' and 'height' properties along
- * with transforms required for rendering.
+ * @return {PDFJS.PageViewport} Contains 'width' and 'height' properties
+ * along with transforms required for rendering.
*/
getViewport: function PDFPageProxy_getViewport(scale, rotate) {
- if (arguments.length < 2)
+ if (arguments.length < 2) {
rotate = this.rotate;
+ }
return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
},
/**
- * @return {Promise} A promise that is resolved with an {array} of the
+ * @return {Promise} A promise that is resolved with an {Array} of the
* annotation objects.
*/
getAnnotations: function PDFPageProxy_getAnnotations() {
- if (this.annotationsPromise)
+ if (this.annotationsPromise) {
return this.annotationsPromise;
+ }
- var promise = new PDFJS.LegacyPromise();
+ var promise = this.transport.getAnnotations(this.pageIndex);
this.annotationsPromise = promise;
- this.transport.getAnnotations(this.pageInfo.pageIndex);
return promise;
},
/**
* Begins the process of rendering a page to the desired context.
- * @param {object} params A parameter object that supports:
- * {
- * canvasContext(required): A 2D context of a DOM Canvas object.,
- * textLayer(optional): An object that has beginLayout, endLayout, and
- * appendText functions.,
- * imageLayer(optional): An object that has beginLayout, endLayout and
- * appendImage functions.,
- * continueCallback(optional): A function that will be called each time
- * the rendering is paused. To continue
- * rendering call the function that is the
- * first argument to the callback.
- * }.
- * @return {RenderTask} An extended promise that is resolved when the page
- * finishes rendering (see RenderTask).
+ * @param {RenderParameters} params Page render parameters.
+ * @return {RenderTask} An object that contains the promise, which
+ * is resolved when the page finishes rendering.
*/
render: function PDFPageProxy_render(params) {
var stats = this.stats;
@@ -4529,12 +2114,19 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
// this call to render.
this.pendingDestroy = false;
- // If there is no displayReadyPromise yet, then the operatorList was never
- // requested before. Make the request and create the promise.
- if (!this.displayReadyPromise) {
- this.receivingOperatorList = true;
- this.displayReadyPromise = new LegacyPromise();
- this.operatorList = {
+ var renderingIntent = (params.intent === 'print' ? 'print' : 'display');
+
+ if (!this.intentStates[renderingIntent]) {
+ this.intentStates[renderingIntent] = {};
+ }
+ var intentState = this.intentStates[renderingIntent];
+
+ // If there's no displayReadyCapability yet, then the operatorList
+ // was never requested before. Make the request and create the promise.
+ if (!intentState.displayReadyCapability) {
+ intentState.receivingOperatorList = true;
+ intentState.displayReadyCapability = createPromiseCapability();
+ intentState.operatorList = {
fnArray: [],
argsArray: [],
lastChunk: false
@@ -4542,18 +2134,24 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
this.stats.time('Page Request');
this.transport.messageHandler.send('RenderPageRequest', {
- pageIndex: this.pageNumber - 1
+ pageIndex: this.pageNumber - 1,
+ intent: renderingIntent
});
}
var internalRenderTask = new InternalRenderTask(complete, params,
- this.objs, this.commonObjs,
- this.operatorList, this.pageNumber);
- this.renderTasks.push(internalRenderTask);
+ this.objs,
+ this.commonObjs,
+ intentState.operatorList,
+ this.pageNumber);
+ if (!intentState.renderTasks) {
+ intentState.renderTasks = [];
+ }
+ intentState.renderTasks.push(internalRenderTask);
var renderTask = new RenderTask(internalRenderTask);
var self = this;
- this.displayReadyPromise.then(
+ intentState.displayReadyCapability.promise.then(
function pageDisplayReadyPromise(transparency) {
if (self.pendingDestroy) {
complete();
@@ -4569,9 +2167,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
);
function complete(error) {
- var i = self.renderTasks.indexOf(internalRenderTask);
+ var i = intentState.renderTasks.indexOf(internalRenderTask);
if (i >= 0) {
- self.renderTasks.splice(i, 1);
+ intentState.renderTasks.splice(i, 1);
}
if (self.cleanupAfterRender) {
@@ -4580,9 +2178,9 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
self._tryDestroy();
if (error) {
- renderTask.promise.reject(error);
+ internalRenderTask.capability.reject(error);
} else {
- renderTask.promise.resolve();
+ internalRenderTask.capability.resolve();
}
stats.timeEnd('Rendering');
stats.timeEnd('Overall');
@@ -4590,32 +2188,53 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return renderTask;
},
+
/**
- * @return {Promise} That is resolved with the a {string} that is the text
- * content from the page.
+ * @return {Promise} A promise resolved with an {@link PDFOperatorList}
+ * object that represents page's operator list.
+ */
+ getOperatorList: function PDFPageProxy_getOperatorList() {
+ function operatorListChanged() {
+ if (intentState.operatorList.lastChunk) {
+ intentState.opListReadCapability.resolve(intentState.operatorList);
+ }
+ }
+
+ var renderingIntent = 'oplist';
+ if (!this.intentStates[renderingIntent]) {
+ this.intentStates[renderingIntent] = {};
+ }
+ var intentState = this.intentStates[renderingIntent];
+
+ if (!intentState.opListReadCapability) {
+ var opListTask = {};
+ opListTask.operatorListChanged = operatorListChanged;
+ intentState.receivingOperatorList = true;
+ intentState.opListReadCapability = createPromiseCapability();
+ intentState.renderTasks = [];
+ intentState.renderTasks.push(opListTask);
+ intentState.operatorList = {
+ fnArray: [],
+ argsArray: [],
+ lastChunk: false
+ };
+
+ this.transport.messageHandler.send('RenderPageRequest', {
+ pageIndex: this.pageIndex,
+ intent: renderingIntent
+ });
+ }
+ return intentState.opListReadCapability.promise;
+ },
+
+ /**
+ * @return {Promise} That is resolved a {@link TextContent}
+ * object that represent the page text content.
*/
getTextContent: function PDFPageProxy_getTextContent() {
- var promise = new PDFJS.LegacyPromise();
- this.transport.messageHandler.send('GetTextContent', {
- pageIndex: this.pageNumber - 1
- },
- function textContentCallback(textContent) {
- promise.resolve(textContent);
- }
- );
- return promise;
- },
- /**
- * Stub for future feature.
- */
- getOperationList: function PDFPageProxy_getOperationList() {
- var promise = new PDFJS.LegacyPromise();
- var operationList = { // not implemented
- dependencyFontsID: null,
- operatorList: null
- };
- promise.resolve(operationList);
- return promise;
+ return this.transport.messageHandler.sendWithPromise('GetTextContent', {
+ pageIndex: this.pageNumber - 1
+ });
},
/**
* Destroys resources allocated by the page.
@@ -4627,65 +2246,85 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
/**
* For internal use only. Attempts to clean up if rendering is in a state
* where that's possible.
+ * @ignore
*/
_tryDestroy: function PDFPageProxy__destroy() {
if (!this.pendingDestroy ||
- this.renderTasks.length !== 0 ||
- this.receivingOperatorList) {
+ Object.keys(this.intentStates).some(function(intent) {
+ var intentState = this.intentStates[intent];
+ return (intentState.renderTasks.length !== 0 ||
+ intentState.receivingOperatorList);
+ }, this)) {
return;
}
- delete this.operatorList;
- delete this.displayReadyPromise;
+ Object.keys(this.intentStates).forEach(function(intent) {
+ delete this.intentStates[intent];
+ }, this);
this.objs.clear();
+ this.annotationsPromise = null;
this.pendingDestroy = false;
},
/**
* For internal use only.
+ * @ignore
*/
- _startRenderPage: function PDFPageProxy_startRenderPage(transparency) {
- this.displayReadyPromise.resolve(transparency);
+ _startRenderPage: function PDFPageProxy_startRenderPage(transparency,
+ intent) {
+ var intentState = this.intentStates[intent];
+ // TODO Refactor RenderPageRequest to separate rendering
+ // and operator list logic
+ if (intentState.displayReadyCapability) {
+ intentState.displayReadyCapability.resolve(transparency);
+ }
},
/**
* For internal use only.
+ * @ignore
*/
- _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk) {
+ _renderPageChunk: function PDFPageProxy_renderPageChunk(operatorListChunk,
+ intent) {
+ var intentState = this.intentStates[intent];
+ var i, ii;
// Add the new chunk to the current operator list.
- for (var i = 0, ii = operatorListChunk.length; i < ii; i++) {
- this.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
- this.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
+ for (i = 0, ii = operatorListChunk.length; i < ii; i++) {
+ intentState.operatorList.fnArray.push(operatorListChunk.fnArray[i]);
+ intentState.operatorList.argsArray.push(
+ operatorListChunk.argsArray[i]);
}
- this.operatorList.lastChunk = operatorListChunk.lastChunk;
+ intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
// Notify all the rendering tasks there are more operators to be consumed.
- for (var i = 0; i < this.renderTasks.length; i++) {
- this.renderTasks[i].operatorListChanged();
+ for (i = 0; i < intentState.renderTasks.length; i++) {
+ intentState.renderTasks[i].operatorListChanged();
}
if (operatorListChunk.lastChunk) {
- this.receivingOperatorList = false;
+ intentState.receivingOperatorList = false;
this._tryDestroy();
}
}
};
return PDFPageProxy;
})();
+
/**
* For internal use only.
+ * @ignore
*/
var WorkerTransport = (function WorkerTransportClosure() {
- function WorkerTransport(workerInitializedPromise, workerReadyPromise,
- pdfDataRangeTransport, progressCallback) {
+ function WorkerTransport(workerInitializedCapability, workerReadyCapability,
+ pdfDataRangeTransport, progressCallback) {
this.pdfDataRangeTransport = pdfDataRangeTransport;
- this.workerReadyPromise = workerReadyPromise;
+ this.workerInitializedCapability = workerInitializedCapability;
+ this.workerReadyCapability = workerReadyCapability;
this.progressCallback = progressCallback;
this.commonObjs = new PDFObjects();
this.pageCache = [];
this.pagePromises = [];
- this.embeddedFontsUsed = false;
-
+ this.downloadInfoCapability = createPromiseCapability();
this.passwordCallback = null;
// If worker support isn't disabled explicit and the browser has worker
@@ -4714,13 +2353,9 @@ var WorkerTransport = (function WorkerTransportClosure() {
PDFJS.postMessageTransfers = false;
}
this.setupMessageHandler(messageHandler);
- workerInitializedPromise.resolve();
+ workerInitializedCapability.resolve();
} else {
- globalScope.PDFJS.disableWorker = true;
- this.loadFakeWorkerFiles().then(function() {
- this.setupFakeWorker();
- workerInitializedPromise.resolve();
- }.bind(this));
+ this.setupFakeWorker();
}
}.bind(this));
@@ -4728,7 +2363,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
// Some versions of Opera throw a DATA_CLONE_ERR on serializing the
// typed array. Also, checking if we can use transfers.
try {
- messageHandler.send('test', testObj, null, [testObj.buffer]);
+ messageHandler.send('test', testObj, [testObj.buffer]);
} catch (ex) {
info('Cannot use postMessage transfers');
testObj[0] = 0;
@@ -4741,53 +2376,52 @@ var WorkerTransport = (function WorkerTransportClosure() {
}
// Either workers are disabled, not supported or have thrown an exception.
// Thus, we fallback to a faked worker.
- globalScope.PDFJS.disableWorker = true;
- this.loadFakeWorkerFiles().then(function() {
- this.setupFakeWorker();
- workerInitializedPromise.resolve();
- }.bind(this));
+ this.setupFakeWorker();
}
WorkerTransport.prototype = {
destroy: function WorkerTransport_destroy() {
this.pageCache = [];
this.pagePromises = [];
var self = this;
- this.messageHandler.send('Terminate', null, function () {
+ this.messageHandler.sendWithPromise('Terminate', null).then(function () {
+ FontLoader.clear();
if (self.worker) {
self.worker.terminate();
}
});
},
- loadFakeWorkerFiles: function WorkerTransport_loadFakeWorkerFiles() {
- if (!PDFJS.fakeWorkerFilesLoadedPromise) {
- PDFJS.fakeWorkerFilesLoadedPromise = new LegacyPromise();
+ setupFakeWorker: function WorkerTransport_setupFakeWorker() {
+ globalScope.PDFJS.disableWorker = true;
+
+ if (!PDFJS.fakeWorkerFilesLoadedCapability) {
+ PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
// In the developer build load worker_loader which in turn loads all the
// other files and resolves the promise. In production only the
// pdf.worker.js file is needed.
Util.loadScript(PDFJS.workerSrc, function() {
- PDFJS.fakeWorkerFilesLoadedPromise.resolve();
+ PDFJS.fakeWorkerFilesLoadedCapability.resolve();
});
}
- return PDFJS.fakeWorkerFilesLoadedPromise;
- },
+ PDFJS.fakeWorkerFilesLoadedCapability.promise.then(function () {
+ warn('Setting up fake worker.');
+ // If we don't use a worker, just post/sendMessage to the main thread.
+ var fakeWorker = {
+ postMessage: function WorkerTransport_postMessage(obj) {
+ fakeWorker.onmessage({data: obj});
+ },
+ terminate: function WorkerTransport_terminate() {}
+ };
- setupFakeWorker: function WorkerTransport_setupFakeWorker() {
- warn('Setting up fake worker.');
- // If we don't use a worker, just post/sendMessage to the main thread.
- var fakeWorker = {
- postMessage: function WorkerTransport_postMessage(obj) {
- fakeWorker.onmessage({data: obj});
- },
- terminate: function WorkerTransport_terminate() {}
- };
+ var messageHandler = new MessageHandler('main', fakeWorker);
+ this.setupMessageHandler(messageHandler);
- var messageHandler = new MessageHandler('main', fakeWorker);
- this.setupMessageHandler(messageHandler);
+ // If the main thread is our worker, setup the handling for the messages
+ // the main thread sends to it self.
+ PDFJS.WorkerMessageHandler.setup(messageHandler);
- // If the main thread is our worker, setup the handling for the messages
- // the main thread sends to it self.
- PDFJS.WorkerMessageHandler.setup(messageHandler);
+ this.workerInitializedCapability.resolve();
+ }.bind(this));
},
setupMessageHandler:
@@ -4813,6 +2447,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
});
});
+ pdfDataRangeTransport.addProgressiveReadListener(function(chunk) {
+ messageHandler.send('OnDataRange', {
+ chunk: chunk
+ });
+ });
+
messageHandler.on('RequestDataRange',
function transportDataRange(data) {
pdfDataRangeTransport.requestDataRange(data.begin, data.end);
@@ -4821,71 +2461,83 @@ var WorkerTransport = (function WorkerTransportClosure() {
messageHandler.on('GetDoc', function transportDoc(data) {
var pdfInfo = data.pdfInfo;
+ this.numPages = data.pdfInfo.numPages;
var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
this.pdfDocument = pdfDocument;
- this.workerReadyPromise.resolve(pdfDocument);
+ this.workerReadyCapability.resolve(pdfDocument);
}, this);
- messageHandler.on('NeedPassword', function transportPassword(data) {
+ messageHandler.on('NeedPassword',
+ function transportNeedPassword(exception) {
if (this.passwordCallback) {
return this.passwordCallback(updatePassword,
PasswordResponses.NEED_PASSWORD);
}
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(
+ new PasswordException(exception.message, exception.code));
}, this);
- messageHandler.on('IncorrectPassword', function transportBadPass(data) {
+ messageHandler.on('IncorrectPassword',
+ function transportIncorrectPassword(exception) {
if (this.passwordCallback) {
return this.passwordCallback(updatePassword,
PasswordResponses.INCORRECT_PASSWORD);
}
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ this.workerReadyCapability.reject(
+ new PasswordException(exception.message, exception.code));
}, this);
- messageHandler.on('InvalidPDF', function transportInvalidPDF(data) {
- this.workerReadyPromise.reject(data.exception.name, data.exception);
+ messageHandler.on('InvalidPDF', function transportInvalidPDF(exception) {
+ this.workerReadyCapability.reject(
+ new InvalidPDFException(exception.message));
}, this);
- messageHandler.on('MissingPDF', function transportMissingPDF(data) {
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ messageHandler.on('MissingPDF', function transportMissingPDF(exception) {
+ this.workerReadyCapability.reject(
+ new MissingPDFException(exception.message));
}, this);
- messageHandler.on('UnknownError', function transportUnknownError(data) {
- this.workerReadyPromise.reject(data.exception.message, data.exception);
+ messageHandler.on('UnexpectedResponse',
+ function transportUnexpectedResponse(exception) {
+ this.workerReadyCapability.reject(
+ new UnexpectedResponseException(exception.message, exception.status));
}, this);
- messageHandler.on('GetPage', function transportPage(data) {
- var pageInfo = data.pageInfo;
- var page = new PDFPageProxy(pageInfo, this);
- this.pageCache[pageInfo.pageIndex] = page;
- var promise = this.pagePromises[pageInfo.pageIndex];
- promise.resolve(page);
+ messageHandler.on('UnknownError',
+ function transportUnknownError(exception) {
+ this.workerReadyCapability.reject(
+ new UnknownErrorException(exception.message, exception.details));
}, this);
- messageHandler.on('GetAnnotations', function transportAnnotations(data) {
- var annotations = data.annotations;
- var promise = this.pageCache[data.pageIndex].annotationsPromise;
- promise.resolve(annotations);
+ messageHandler.on('DataLoaded', function transportPage(data) {
+ this.downloadInfoCapability.resolve(data);
+ }, this);
+
+ messageHandler.on('PDFManagerReady', function transportPage(data) {
+ if (this.pdfDataRangeTransport) {
+ this.pdfDataRangeTransport.transportReady();
+ }
}, this);
messageHandler.on('StartRenderPage', function transportRender(data) {
var page = this.pageCache[data.pageIndex];
page.stats.timeEnd('Page Request');
- page._startRenderPage(data.transparency);
+ page._startRenderPage(data.transparency, data.intent);
}, this);
messageHandler.on('RenderPageChunk', function transportRender(data) {
var page = this.pageCache[data.pageIndex];
- page._renderPageChunk(data.operatorList);
+ page._renderPageChunk(data.operatorList, data.intent);
}, this);
messageHandler.on('commonobj', function transportObj(data) {
var id = data[0];
var type = data[1];
- if (this.commonObjs.hasData(id))
+ if (this.commonObjs.hasData(id)) {
return;
+ }
switch (type) {
case 'Font':
@@ -4898,7 +2550,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
this.commonObjs.resolve(id, error);
break;
} else {
- font = new FontFace(exportedData);
+ font = new FontFaceObject(exportedData);
}
FontLoader.bind(
@@ -4921,21 +2573,23 @@ var WorkerTransport = (function WorkerTransportClosure() {
var pageIndex = data[1];
var type = data[2];
var pageProxy = this.pageCache[pageIndex];
- if (pageProxy.objs.hasData(id))
+ var imageData;
+ if (pageProxy.objs.hasData(id)) {
return;
+ }
switch (type) {
case 'JpegStream':
- var imageData = data[3];
+ imageData = data[3];
loadJpegStream(id, imageData, pageProxy.objs);
break;
case 'Image':
- var imageData = data[3];
+ imageData = data[3];
pageProxy.objs.resolve(id, imageData);
// heuristics that will allow not to store large data
var MAX_IMAGE_SIZE_TO_STORE = 8000000;
- if ('data' in imageData &&
+ if (imageData && 'data' in imageData &&
imageData.data.length > MAX_IMAGE_SIZE_TO_STORE) {
pageProxy.cleanupAfterRender = true;
}
@@ -4954,127 +2608,155 @@ var WorkerTransport = (function WorkerTransportClosure() {
}
}, this);
- messageHandler.on('DocError', function transportDocError(data) {
- this.workerReadyPromise.reject(data);
- }, this);
-
messageHandler.on('PageError', function transportError(data) {
var page = this.pageCache[data.pageNum - 1];
- if (page.displayReadyPromise)
- page.displayReadyPromise.reject(data.error);
- else
+ var intentState = page.intentStates[data.intent];
+ if (intentState.displayReadyCapability) {
+ intentState.displayReadyCapability.reject(data.error);
+ } else {
error(data.error);
+ }
}, this);
- messageHandler.on('JpegDecode', function(data, deferred) {
+ messageHandler.on('JpegDecode', function(data) {
var imageUrl = data[0];
var components = data[1];
- if (components != 3 && components != 1)
- error('Only 3 component or 1 component can be returned');
+ if (components !== 3 && components !== 1) {
+ return Promise.reject(
+ new Error('Only 3 components or 1 component can be returned'));
+ }
- var img = new Image();
- img.onload = (function messageHandler_onloadClosure() {
- var width = img.width;
- var height = img.height;
- var size = width * height;
- var rgbaLength = size * 4;
- var buf = new Uint8Array(size * components);
- var tmpCanvas = createScratchCanvas(width, height);
- var tmpCtx = tmpCanvas.getContext('2d');
- tmpCtx.drawImage(img, 0, 0);
- var data = tmpCtx.getImageData(0, 0, width, height).data;
+ return new Promise(function (resolve, reject) {
+ var img = new Image();
+ img.onload = function () {
+ var width = img.width;
+ var height = img.height;
+ var size = width * height;
+ var rgbaLength = size * 4;
+ var buf = new Uint8Array(size * components);
+ var tmpCanvas = createScratchCanvas(width, height);
+ var tmpCtx = tmpCanvas.getContext('2d');
+ tmpCtx.drawImage(img, 0, 0);
+ var data = tmpCtx.getImageData(0, 0, width, height).data;
+ var i, j;
- if (components == 3) {
- for (var i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
- buf[j] = data[i];
- buf[j + 1] = data[i + 1];
- buf[j + 2] = data[i + 2];
+ if (components === 3) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j += 3) {
+ buf[j] = data[i];
+ buf[j + 1] = data[i + 1];
+ buf[j + 2] = data[i + 2];
+ }
+ } else if (components === 1) {
+ for (i = 0, j = 0; i < rgbaLength; i += 4, j++) {
+ buf[j] = data[i];
+ }
}
- } else if (components == 1) {
- for (var i = 0, j = 0; i < rgbaLength; i += 4, j++) {
- buf[j] = data[i];
- }
- }
- deferred.resolve({ data: buf, width: width, height: height});
- }).bind(this);
- img.src = imageUrl;
+ resolve({ data: buf, width: width, height: height});
+ };
+ img.onerror = function () {
+ reject(new Error('JpegDecode failed to load image'));
+ };
+ img.src = imageUrl;
+ });
});
},
fetchDocument: function WorkerTransport_fetchDocument(source) {
source.disableAutoFetch = PDFJS.disableAutoFetch;
+ source.disableStream = PDFJS.disableStream;
source.chunkedViewerLoading = !!this.pdfDataRangeTransport;
this.messageHandler.send('GetDocRequest', {
source: source,
disableRange: PDFJS.disableRange,
maxImageSize: PDFJS.maxImageSize,
+ cMapUrl: PDFJS.cMapUrl,
+ cMapPacked: PDFJS.cMapPacked,
disableFontFace: PDFJS.disableFontFace,
+ disableCreateObjectURL: PDFJS.disableCreateObjectURL,
verbosity: PDFJS.verbosity
});
},
- getData: function WorkerTransport_getData(promise) {
- this.messageHandler.send('GetData', null, function(data) {
- promise.resolve(data);
- });
+ getData: function WorkerTransport_getData() {
+ return this.messageHandler.sendWithPromise('GetData', null);
},
- dataLoaded: function WorkerTransport_dataLoaded() {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('DataLoaded', null, function(args) {
- promise.resolve(args);
- });
- return promise;
- },
+ getPage: function WorkerTransport_getPage(pageNumber, capability) {
+ if (pageNumber <= 0 || pageNumber > this.numPages ||
+ (pageNumber|0) !== pageNumber) {
+ return Promise.reject(new Error('Invalid page request'));
+ }
- getPage: function WorkerTransport_getPage(pageNumber, promise) {
var pageIndex = pageNumber - 1;
- if (pageIndex in this.pagePromises)
+ if (pageIndex in this.pagePromises) {
return this.pagePromises[pageIndex];
- var promise = new PDFJS.LegacyPromise();
+ }
+ var promise = this.messageHandler.sendWithPromise('GetPage', {
+ pageIndex: pageIndex
+ }).then(function (pageInfo) {
+ var page = new PDFPageProxy(pageIndex, pageInfo, this);
+ this.pageCache[pageIndex] = page;
+ return page;
+ }.bind(this));
this.pagePromises[pageIndex] = promise;
- this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
return promise;
},
getPageIndex: function WorkerTransport_getPageIndexByRef(ref) {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('GetPageIndex', { ref: ref },
- function (pageIndex) {
- promise.resolve(pageIndex);
- }
- );
- return promise;
+ return this.messageHandler.sendWithPromise('GetPageIndex', { ref: ref });
},
getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
- this.messageHandler.send('GetAnnotationsRequest',
+ return this.messageHandler.sendWithPromise('GetAnnotations',
{ pageIndex: pageIndex });
},
getDestinations: function WorkerTransport_getDestinations() {
- var promise = new PDFJS.LegacyPromise();
- this.messageHandler.send('GetDestinations', null,
- function transportDestinations(destinations) {
- promise.resolve(destinations);
- }
- );
- return promise;
+ return this.messageHandler.sendWithPromise('GetDestinations', null);
+ },
+
+ getDestination: function WorkerTransport_getDestination(id) {
+ return this.messageHandler.sendWithPromise('GetDestination', { id: id } );
+ },
+
+ getAttachments: function WorkerTransport_getAttachments() {
+ return this.messageHandler.sendWithPromise('GetAttachments', null);
+ },
+
+ getJavaScript: function WorkerTransport_getJavaScript() {
+ return this.messageHandler.sendWithPromise('GetJavaScript', null);
+ },
+
+ getOutline: function WorkerTransport_getOutline() {
+ return this.messageHandler.sendWithPromise('GetOutline', null);
+ },
+
+ getMetadata: function WorkerTransport_getMetadata() {
+ return this.messageHandler.sendWithPromise('GetMetadata', null).
+ then(function transportMetadata(results) {
+ return {
+ info: results[0],
+ metadata: (results[1] ? new PDFJS.Metadata(results[1]) : null)
+ };
+ });
+ },
+
+ getStats: function WorkerTransport_getStats() {
+ return this.messageHandler.sendWithPromise('GetStats', null);
},
startCleanup: function WorkerTransport_startCleanup() {
- this.messageHandler.send('Cleanup', null,
- function endCleanup() {
- for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
- var page = this.pageCache[i];
- if (page) {
- page.destroy();
- }
+ this.messageHandler.sendWithPromise('Cleanup', null).
+ then(function endCleanup() {
+ for (var i = 0, ii = this.pageCache.length; i < ii; i++) {
+ var page = this.pageCache[i];
+ if (page) {
+ page.destroy();
}
- this.commonObjs.clear();
- FontLoader.clear();
- }.bind(this)
- );
+ }
+ this.commonObjs.clear();
+ FontLoader.clear();
+ }.bind(this));
}
};
return WorkerTransport;
@@ -5086,6 +2768,7 @@ var WorkerTransport = (function WorkerTransportClosure() {
* for fonts, images, rendering code and such. These objects might get processed
* inside of a worker. The `PDFObjects` implements some basic functions to
* manage these objects.
+ * @ignore
*/
var PDFObjects = (function PDFObjectsClosure() {
function PDFObjects() {
@@ -5098,11 +2781,12 @@ var PDFObjects = (function PDFObjectsClosure() {
* Ensures there is an object defined for `objId`.
*/
ensureObj: function PDFObjects_ensureObj(objId) {
- if (this.objs[objId])
+ if (this.objs[objId]) {
return this.objs[objId];
+ }
var obj = {
- promise: new LegacyPromise(),
+ capability: createPromiseCapability(),
data: null,
resolved: false
};
@@ -5124,7 +2808,7 @@ var PDFObjects = (function PDFObjectsClosure() {
// If there is a callback, then the get can be async and the object is
// not required to be resolved right now
if (callback) {
- this.ensureObj(objId).promise.then(callback);
+ this.ensureObj(objId).capability.promise.then(callback);
return null;
}
@@ -5134,8 +2818,9 @@ var PDFObjects = (function PDFObjectsClosure() {
// If there isn't an object yet or the object isn't resolved, then the
// data isn't ready yet!
- if (!obj || !obj.resolved)
+ if (!obj || !obj.resolved) {
error('Requesting object that isn\'t resolved yet ' + objId);
+ }
return obj.data;
},
@@ -5148,7 +2833,7 @@ var PDFObjects = (function PDFObjectsClosure() {
obj.resolved = true;
obj.data = data;
- obj.promise.resolve(data);
+ obj.capability.resolve(data);
},
isResolved: function PDFObjects_isResolved(objId) {
@@ -5184,24 +2869,50 @@ var PDFObjects = (function PDFObjectsClosure() {
return PDFObjects;
})();
+/**
+ * Allows controlling of the rendering tasks.
+ * @class
+ */
var RenderTask = (function RenderTaskClosure() {
function RenderTask(internalRenderTask) {
this.internalRenderTask = internalRenderTask;
- this.promise = new PDFJS.LegacyPromise();
+ /**
+ * Promise for rendering task completion.
+ * @type {Promise}
+ */
+ this.promise = this.internalRenderTask.capability.promise;
}
- /**
- * Cancel the rendering task. If the task is curently rendering it will not be
- * cancelled until graphics pauses with a timeout. The promise that this
- * object extends will resolved when cancelled.
- */
- RenderTask.prototype.cancel = function RenderTask_cancel() {
- this.internalRenderTask.cancel();
+ RenderTask.prototype = /** @lends RenderTask.prototype */ {
+ /**
+ * Cancels the rendering task. If the task is currently rendering it will
+ * not be cancelled until graphics pauses with a timeout. The promise that
+ * this object extends will resolved when cancelled.
+ */
+ cancel: function RenderTask_cancel() {
+ this.internalRenderTask.cancel();
+ },
+
+ /**
+ * Registers callback to indicate the rendering task completion.
+ *
+ * @param {function} onFulfilled The callback for the rendering completion.
+ * @param {function} onRejected The callback for the rendering failure.
+ * @return {Promise} A promise that is resolved after the onFulfilled or
+ * onRejected callback.
+ */
+ then: function RenderTask_then(onFulfilled, onRejected) {
+ return this.promise.then(onFulfilled, onRejected);
+ }
};
return RenderTask;
})();
+/**
+ * For internal use only.
+ * @ignore
+ */
var InternalRenderTask = (function InternalRenderTaskClosure() {
function InternalRenderTask(callback, params, objs, commonObjs, operatorList,
@@ -5217,6 +2928,11 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
this.graphicsReadyCallback = null;
this.graphicsReady = false;
this.cancelled = false;
+ this.capability = createPromiseCapability();
+ // caching this-bound methods
+ this._continueBound = this._continue.bind(this);
+ this._scheduleNextBound = this._scheduleNext.bind(this);
+ this._nextBound = this._next.bind(this);
}
InternalRenderTask.prototype = {
@@ -5236,8 +2952,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
var params = this.params;
this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
- this.objs, params.textLayer,
- params.imageLayer);
+ this.objs, params.imageLayer);
this.gfx.beginDrawing(params.viewport, transparency);
this.operatorListIdx = 0;
@@ -5256,7 +2971,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
operatorListChanged: function InternalRenderTask_operatorListChanged() {
if (!this.graphicsReady) {
if (!this.graphicsReadyCallback) {
- this.graphicsReadyCallback = this._continue.bind(this);
+ this.graphicsReadyCallback = this._continueBound;
}
return;
}
@@ -5277,19 +2992,23 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
return;
}
if (this.params.continueCallback) {
- this.params.continueCallback(this._next.bind(this));
+ this.params.continueCallback(this._scheduleNextBound);
} else {
- this._next();
+ this._scheduleNext();
}
},
+ _scheduleNext: function InternalRenderTask__scheduleNext() {
+ window.requestAnimationFrame(this._nextBound);
+ },
+
_next: function InternalRenderTask__next() {
if (this.cancelled) {
return;
}
this.operatorListIdx = this.gfx.executeOperatorList(this.operatorList,
this.operatorListIdx,
- this._continue.bind(this),
+ this._continueBound,
this.stepper);
if (this.operatorListIdx === this.operatorList.argsArray.length) {
this.running = false;
@@ -5316,8 +3035,8 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
var chars = '';
for (var i = 0; i < bytes.length; i += 2) {
var code = bytes.charCodeAt(i) * 256 + bytes.charCodeAt(i + 1);
- chars += code >= 32 && code < 127 && code != 60 && code != 62 &&
- code != 38 && false ? String.fromCharCode(code) :
+ chars += code >= 32 && code < 127 && code !== 60 && code !== 62 &&
+ code !== 38 && false ? String.fromCharCode(code) :
'' + (0x10000 + code).toString(16).substring(1) + ';';
}
return '>' + chars;
@@ -5347,20 +3066,22 @@ var Metadata = PDFJS.Metadata = (function MetadataClosure() {
if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in
+
+
+